lisp-machine / ltms-console.html
SNAPKITTYWEST's picture
Deploy interactive lisp-machine Space
4cd921e verified
Raw
History Blame Contribute Delete
24.3 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LTMS Truth Maintenance — Live Console</title>
<style>
:root {
--bg-void: #020508;
--bg-deep: #050b12;
--bg-panel: rgba(8, 18, 28, 0.82);
--bg-panel-strong: rgba(9, 24, 36, 0.96);
--line-soft: rgba(112, 220, 255, 0.12);
--line-medium: rgba(112, 220, 255, 0.28);
--line-bright: rgba(112, 220, 255, 0.72);
--text-primary: #e8fbff;
--text-secondary: #8eb5c1;
--text-muted: #52707a;
--cyan: #56e8ff;
--cyan-hot: #a9f7ff;
--teal: #38ffc7;
--violet: #ab7cff;
--gold: #ffc857;
--red: #ff5470;
--green: #5dff9d;
--shadow-cyan: 0 0 18px rgba(86, 232, 255, 0.2), 0 0 52px rgba(86, 232, 255, 0.08);
--shadow-violet: 0 0 20px rgba(171, 124, 255, 0.2), 0 0 60px rgba(171, 124, 255, 0.08);
--radius-xs: 6px;
--radius-sm: 10px;
--radius-md: 16px;
--radius-lg: 24px;
--font-display: "Orbitron", "Rajdhani", "Segoe UI", sans-serif;
--font-mono: "JetBrains Mono", "IBM Plex Mono", "Cascadia Code", monospace;
--ease-system: cubic-bezier(0.22, 1, 0.36, 1);
}
* { box-sizing: border-box; }
html { min-height: 100%; background: var(--bg-void); }
body {
min-height: 100vh;
margin: 0;
color: var(--text-primary);
font-family: var(--font-mono);
background: linear-gradient(180deg, #020508 0%, #041019 48%, #020609 100%);
}
button, input, textarea { font: inherit; color: inherit; }
.ltms-shell {
width: min(1800px, 100%);
margin: 0 auto;
padding: 18px;
}
.ltms-header {
position: sticky;
top: 12px;
z-index: 30;
display: flex;
gap: 20px;
align-items: center;
min-height: 76px;
padding: 14px 18px;
border: 1px solid var(--line-medium);
border-radius: var(--radius-lg);
background: linear-gradient(135deg, rgba(9, 24, 36, 0.94), rgba(4, 12, 19, 0.91));
box-shadow: var(--shadow-cyan), inset 0 1px rgba(255, 255, 255, 0.04);
backdrop-filter: blur(22px) saturate(135%);
margin-bottom: 20px;
}
.ltms-title {
font-family: var(--font-display);
font-size: 1.35rem;
font-weight: 700;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--violet);
}
.ltms-subtitle {
color: var(--text-secondary);
font-size: 0.75rem;
letter-spacing: 0.1em;
}
.ltms-status {
display: flex;
gap: 12px;
margin-left: auto;
}
.status-chip {
display: inline-flex;
gap: 8px;
align-items: center;
padding: 8px 12px;
border: 1px solid var(--line-soft);
border-radius: 999px;
color: var(--text-secondary);
background: rgba(2, 10, 16, 0.55);
font-size: 0.75rem;
}
.status-chip[data-state="ready"] {
color: var(--green);
border-color: rgba(93, 255, 157, 0.35);
}
.status-dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
box-shadow: 0 0 10px currentColor;
}
.ltms-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 20px;
}
.ltms-panel {
border: 1px solid var(--line-soft);
border-radius: var(--radius-md);
background: linear-gradient(160deg, rgba(10, 26, 38, 0.9), rgba(3, 11, 17, 0.96));
box-shadow: 0 20px 80px rgba(0, 0, 0, 0.26), inset 0 1px rgba(255, 255, 255, 0.035);
overflow: hidden;
}
.panel-header {
display: flex;
gap: 12px;
align-items: center;
min-height: 52px;
padding: 0 16px;
border-bottom: 1px solid var(--line-soft);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.025), transparent);
}
.panel-title {
display: flex;
gap: 10px;
align-items: center;
margin: 0;
color: var(--cyan-hot);
font-family: var(--font-display);
font-size: 0.78rem;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.panel-body {
padding: 14px;
}
.input-group {
display: flex;
gap: 8px;
margin-bottom: 12px;
}
.input-group input {
flex: 1;
padding: 8px 12px;
border: 1px solid var(--line-soft);
background: #03080d;
color: var(--cyan);
border-radius: var(--radius-xs);
font-size: 0.85rem;
}
.input-group button {
padding: 8px 16px;
border: 1px solid var(--line-medium);
background: linear-gradient(180deg, rgba(18, 47, 65, 0.9), rgba(6, 19, 28, 0.95));
color: var(--text-primary);
border-radius: var(--radius-xs);
cursor: pointer;
transition: all 160ms var(--ease-system);
text-transform: uppercase;
font-size: 0.75rem;
font-weight: bold;
}
.input-group button:hover {
border-color: var(--line-bright);
box-shadow: var(--shadow-cyan);
}
.input-group button[data-variant="primary"] {
background: linear-gradient(135deg, var(--cyan-hot), var(--cyan));
color: #001115;
border-color: transparent;
}
.belief-list {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 500px;
overflow-y: auto;
}
.belief-node {
position: relative;
padding: 12px 14px 12px 18px;
border: 1px solid var(--line-soft);
border-radius: var(--radius-sm);
background: rgba(4, 13, 20, 0.78);
transition: all 200ms var(--ease-system);
}
.belief-node::before {
position: absolute;
top: 14px;
bottom: 14px;
left: 8px;
width: 2px;
content: "";
border-radius: 2px;
background: linear-gradient(var(--cyan), var(--violet));
}
.belief-node[data-status="asserted"] {
border-left-color: var(--green);
}
.belief-node[data-status="assumed"] {
border-left-color: var(--gold);
}
.belief-node[data-status="derived"] {
border-left-color: var(--teal);
}
.belief-node[data-status="retracted"] {
border-left-color: var(--red);
opacity: 0.5;
text-decoration: line-through;
}
.belief-label {
color: var(--text-primary);
font-weight: bold;
margin-bottom: 4px;
}
.belief-meta {
display: flex;
gap: 12px;
font-size: 0.7rem;
color: var(--text-muted);
margin-top: 4px;
}
.belief-action {
font-size: 0.65rem;
color: var(--cyan);
cursor: pointer;
padding: 2px 6px;
border-radius: 3px;
transition: all 100ms var(--ease-system);
}
.belief-action:hover {
background: rgba(86, 232, 255, 0.1);
}
.derivation-chain {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 500px;
overflow-y: auto;
}
.derivation-step {
padding: 10px;
border-left: 3px solid var(--teal);
background: rgba(56, 255, 199, 0.05);
border-radius: var(--radius-xs);
font-size: 0.8rem;
}
.derivation-step .step-label {
color: var(--teal);
font-weight: bold;
margin-bottom: 4px;
}
.derivation-step .step-content {
color: var(--text-secondary);
font-family: var(--font-mono);
}
.contradiction-alert {
padding: 12px;
border: 1px solid var(--red);
background: rgba(255, 84, 112, 0.1);
border-radius: var(--radius-sm);
color: var(--red);
margin-bottom: 12px;
animation: pulse-red 1s infinite;
}
@keyframes pulse-red {
0%, 100% { box-shadow: inset 0 0 0 1px rgba(255, 84, 112, 0.3); }
50% { box-shadow: inset 0 0 0 1px rgba(255, 84, 112, 0.8); }
}
.execution-trace {
display: flex;
flex-direction: column;
gap: 6px;
max-height: 600px;
overflow-y: auto;
font-size: 0.75rem;
}
.trace-line {
padding: 6px 8px;
border-left: 2px solid var(--line-soft);
color: var(--text-secondary);
}
.trace-line.assert {
border-left-color: var(--green);
color: var(--green);
}
.trace-line.assume {
border-left-color: var(--gold);
color: var(--gold);
}
.trace-line.derive {
border-left-color: var(--teal);
color: var(--teal);
}
.trace-line.retract {
border-left-color: var(--red);
color: var(--red);
}
.demo-buttons {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 8px;
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--line-soft);
}
.demo-btn {
padding: 10px 12px;
border: 1px solid var(--line-soft);
background: rgba(2, 10, 16, 0.55);
color: var(--cyan);
border-radius: var(--radius-xs);
cursor: pointer;
font-size: 0.75rem;
transition: all 100ms var(--ease-system);
}
.demo-btn:hover {
border-color: var(--line-bright);
background: rgba(86, 232, 255, 0.1);
}
.full-width {
grid-column: 1 / -1;
}
@media (max-width: 1024px) {
.ltms-grid {
grid-template-columns: 1fr;
}
.ltms-header {
flex-direction: column;
align-items: flex-start;
}
.ltms-status {
margin-left: 0;
width: 100%;
}
}
</style>
</head>
<body>
<div class="ltms-shell">
<div class="ltms-header">
<div>
<h1 class="ltms-title">🧠 LTMS</h1>
<p class="ltms-subtitle">Layered Truth Maintenance System — Live Belief Graph</p>
</div>
<div class="ltms-status">
<div class="status-chip" data-state="ready">
<div class="status-dot"></div>
<span>KNOWLEDGE ENGINE</span>
</div>
</div>
</div>
<div class="ltms-grid">
<!-- BELIEF OPERATIONS -->
<div class="ltms-panel">
<div class="panel-header">
<h2 class="panel-title">📝 Operations</h2>
</div>
<div class="panel-body">
<div class="input-group">
<input type="text" id="belief-input" placeholder="Enter belief (e.g., Socrates is human)">
<button onclick="assertBelief()" data-variant="primary">Assert</button>
</div>
<div class="input-group">
<input type="text" id="rule-input" placeholder="Enter rule (e.g., Every human is mortal)">
<button onclick="addRule()">Rule</button>
</div>
<div style="margin-top: 16px; border-top: 1px solid var(--line-soft); padding-top: 16px;">
<h3 style="color: var(--gold); font-size: 0.8rem; margin: 0 0 12px; text-transform: uppercase;">Queries</h3>
<div class="input-group">
<input type="text" id="query-input" placeholder="Query belief (e.g., Socrates is mortal)">
<button onclick="queryBelief()">Exact</button>
</div>
<div class="input-group">
<input type="text" id="semantic-input" placeholder="Semantic search (e.g., mortality)">
<button onclick="semanticSearch()">🔍 Semantic</button>
</div>
</div>
<div class="demo-buttons">
<button class="demo-btn" onclick="socraticDemo()">📖 Socratic Demo</button>
<button class="demo-btn" onclick="contradictionDemo()">⚠️ Contradiction</button>
<button class="demo-btn" onclick="clearAll()">🔄 Clear All</button>
</div>
</div>
</div>
<!-- BELIEF STATE -->
<div class="ltms-panel">
<div class="panel-header">
<h2 class="panel-title">💭 Beliefs</h2>
<span style="margin-left: auto; color: var(--text-muted); font-size: 0.7rem;" id="belief-count">0 active</span>
</div>
<div class="panel-body">
<div id="contradiction-alerts"></div>
<div class="belief-list" id="belief-list">
<div style="color: var(--text-muted); font-size: 0.75rem;">No beliefs yet. Assert or assume a belief to begin.</div>
</div>
</div>
</div>
<!-- DERIVATIONS (FULL WIDTH) -->
<div class="ltms-panel full-width">
<div class="panel-header">
<h2 class="panel-title">⛓️ Derivation Chain</h2>
<span style="margin-left: auto; color: var(--text-muted); font-size: 0.7rem;" id="step-count">0 steps</span>
</div>
<div class="panel-body">
<div class="derivation-chain" id="derivation-chain">
<div style="color: var(--text-muted); font-size: 0.75rem;">Waiting for inferences...</div>
</div>
</div>
</div>
<!-- EXECUTION TRACE (FULL WIDTH) -->
<div class="ltms-panel full-width">
<div class="panel-header">
<h2 class="panel-title">📋 Execution Log</h2>
</div>
<div class="panel-body">
<div class="execution-trace" id="execution-trace">
<div class="trace-line" style="color: var(--cyan);">• System initialized</div>
</div>
</div>
</div>
</div>
</div>
<script type="module">
import ONNXBridge from './onnx-bridge.mjs';
window.ONNXBridge = ONNXBridge;
</script>
<script>
// ========================================================================
// LTMS State Management
// ========================================================================
const state = {
beliefs: new Map(), // Map<id, { label, status, justification, timestamp }>
rules: [], // Array<{ antecedent, consequent }>
derivations: [], // Array<{ step, result, source }>
contradictions: [], // Array<{ belief1, belief2 }>
executionLog: [], // Array<{ timestamp, action, detail }>
beliefCounter: 0,
};
const STATUS = {
ASSERTED: 'asserted',
ASSUMED: 'assumed',
DERIVED: 'derived',
RETRACTED: 'retracted',
};
// ========================================================================
// Core Operations
// ========================================================================
function assertBelief() {
const input = document.getElementById('belief-input');
const label = input.value.trim();
if (!label) return;
const id = `belief-${++state.beliefCounter}`;
state.beliefs.set(id, {
id,
label,
status: STATUS.ASSERTED,
justification: 'user assertion',
timestamp: Date.now(),
dependents: [],
});
logExecution('assert', label);
input.value = '';
// Check for contradictions
checkContradictions();
// Trigger inference
inferenceStep();
render();
}
function addRule() {
const input = document.getElementById('rule-input');
const rule = input.value.trim();
if (!rule) return;
// Parse simple rule format: "If X then Y"
const match = rule.match(/If\s+(.+?)\s+then\s+(.+)/i);
if (!match) {
logExecution('error', 'Rule format: "If X then Y"');
return;
}
state.rules.push({
antecedent: match[1].trim(),
consequent: match[2].trim(),
timestamp: Date.now(),
});
logExecution('rule_add', rule);
input.value = '';
// Re-run inference with new rule
inferenceStep();
render();
}
function queryBelief() {
const input = document.getElementById('query-input');
const query = input.value.trim();
if (!query) return;
const matches = Array.from(state.beliefs.values())
.filter(b => b.label.toLowerCase().includes(query.toLowerCase()) && b.status !== STATUS.RETRACTED);
if (matches.length === 0) {
logExecution('query', `No beliefs match: "${query}"`);
} else {
matches.forEach(m => {
logExecution('query_result', `${m.label} (${m.status})`);
});
}
input.value = '';
render();
}
async function semanticSearch() {
const input = document.getElementById('semantic-input');
const query = input.value.trim();
if (!query) return;
logExecution('semantic_search', `Searching for: "${query}"`);
try {
if (!window.ONNXBridge) {
logExecution('error', 'ONNX not loaded');
return;
}
// Get all active beliefs
const candidates = Array.from(state.beliefs.values())
.filter(b => b.status !== STATUS.RETRACTED)
.map(b => b.label);
if (candidates.length === 0) {
logExecution('semantic_result', 'No beliefs to search');
input.value = '';
return;
}
// Perform semantic search
const results = await window.ONNXBridge.search(query, candidates);
if (results.length === 0) {
logExecution('semantic_result', 'No semantically similar beliefs found');
} else {
results.slice(0, 5).forEach(r => {
logExecution('semantic_result', `"${r.text}" (similarity: ${(r.similarity * 100).toFixed(0)}%)`);
});
}
} catch (err) {
logExecution('error', `Semantic search failed: ${err.message}`);
}
input.value = '';
render();
}
function inferenceStep() {
state.rules.forEach(rule => {
// Check if antecedent matches any active belief
const antecedentBeliefs = Array.from(state.beliefs.values())
.filter(b => b.label.toLowerCase().includes(rule.antecedent.toLowerCase()) && b.status !== STATUS.RETRACTED);
if (antecedentBeliefs.length > 0) {
// Derive consequent
const consequentId = `belief-${++state.beliefCounter}`;
const consequent = rule.consequent.replace('{subject}', 'it');
state.beliefs.set(consequentId, {
id: consequentId,
label: consequent,
status: STATUS.DERIVED,
justification: `From: ${rule.antecedent}`,
timestamp: Date.now(),
dependents: [],
});
state.derivations.push({
step: state.derivations.length + 1,
antecedent: antecedentBeliefs[0].label,
rule: rule.antecedent + ' → ' + rule.consequent,
consequent,
timestamp: Date.now(),
});
logExecution('derive', consequent);
}
});
}
function checkContradictions() {
const active = Array.from(state.beliefs.values())
.filter(b => b.status !== STATUS.RETRACTED);
state.contradictions = [];
for (let i = 0; i < active.length; i++) {
for (let j = i + 1; j < active.length; j++) {
const b1 = active[i];
const b2 = active[j];
// Simple contradiction: "X is Y" vs "X is not Y"
const negPattern1 = `${b1.label.split(' is ')[0]} is not ${b1.label.split(' is ')[1]}`;
const negPattern2 = `${b2.label.split(' is ')[0]} is not ${b2.label.split(' is ')[1]}`;
if (b1.label === negPattern2 || b2.label === negPattern1) {
state.contradictions.push({ belief1: b1, belief2: b2 });
}
}
}
}
function retractBelief(beliefId) {
const belief = state.beliefs.get(beliefId);
if (!belief) return;
// Mark as retracted
belief.status = STATUS.RETRACTED;
// Cascade: retract dependent beliefs
state.derivations.forEach(d => {
if (d.antecedent === belief.label) {
const dependentBeliefs = Array.from(state.beliefs.values())
.filter(b => b.label === d.consequent);
dependentBeliefs.forEach(b => {
b.status = STATUS.RETRACTED;
logExecution('cascade_retract', b.label);
});
}
});
logExecution('retract', belief.label);
render();
}
// ========================================================================
// Demos
// ========================================================================
function socraticDemo() {
clearAll();
setTimeout(() => {
document.getElementById('belief-input').value = 'Socrates is human';
assertBelief();
}, 200);
setTimeout(() => {
document.getElementById('rule-input').value = 'If Socrates is human then Socrates is mortal';
addRule();
}, 600);
setTimeout(() => {
document.getElementById('query-input').value = 'mortal';
queryBelief();
}, 1200);
setTimeout(() => {
logExecution('demo_info', 'Now retracting: "Socrates is human"');
}, 1600);
setTimeout(() => {
const beliefId = Array.from(state.beliefs.entries())
.find(([_, b]) => b.label === 'Socrates is human')?.[0];
if (beliefId) retractBelief(beliefId);
}, 2200);
}
function contradictionDemo() {
clearAll();
setTimeout(() => {
document.getElementById('belief-input').value = 'The light is on';
assertBelief();
}, 200);
setTimeout(() => {
document.getElementById('belief-input').value = 'The light is not on';
assertBelief();
}, 600);
}
function clearAll() {
state.beliefs.clear();
state.rules = [];
state.derivations = [];
state.contradictions = [];
state.executionLog = [];
state.beliefCounter = 0;
logExecution('system', 'Cleared all state');
render();
}
// ========================================================================
// Logging
// ========================================================================
function logExecution(action, detail) {
state.executionLog.push({
timestamp: new Date().toLocaleTimeString(),
action,
detail,
});
}
// ========================================================================
// Rendering
// ========================================================================
function render() {
renderBeliefs();
renderDerivations();
renderExecutionLog();
renderContradictions();
}
function renderBeliefs() {
const list = document.getElementById('belief-list');
const beliefs = Array.from(state.beliefs.values());
const count = beliefs.filter(b => b.status !== STATUS.RETRACTED).length;
document.getElementById('belief-count').textContent = `${count} active`;
if (beliefs.length === 0) {
list.innerHTML = '<div style="color: var(--text-muted); font-size: 0.75rem;">No beliefs yet.</div>';
return;
}
list.innerHTML = beliefs
.map(b => `
<div class="belief-node" data-status="${b.status}">
<div class="belief-label">${b.label}</div>
<div class="belief-meta">
<span>${b.status}</span>
<span>${b.justification}</span>
<span class="belief-action" onclick="retractBelief('${b.id}')">retract</span>
</div>
</div>
`)
.join('');
}
function renderDerivations() {
const chain = document.getElementById('derivation-chain');
const derivations = state.derivations;
document.getElementById('step-count').textContent = `${derivations.length} steps`;
if (derivations.length === 0) {
chain.innerHTML = '<div style="color: var(--text-muted); font-size: 0.75rem;">Waiting for inferences...</div>';
return;
}
chain.innerHTML = derivations
.map((d, i) => `
<div class="derivation-step">
<div class="step-label">Step ${d.step}:</div>
<div class="step-content">
<strong>${d.antecedent}</strong><br>
+ ${d.rule}<br>
⇒ <strong>${d.consequent}</strong>
</div>
</div>
`)
.join('');
}
function renderContradictions() {
const alerts = document.getElementById('contradiction-alerts');
if (state.contradictions.length === 0) {
alerts.innerHTML = '';
return;
}
alerts.innerHTML = state.contradictions
.map(c => `
<div class="contradiction-alert">
⚠️ Contradiction: "${c.belief1.label}" vs "${c.belief2.label}"
</div>
`)
.join('');
}
function renderExecutionLog() {
const trace = document.getElementById('execution-trace');
const logs = state.executionLog.slice(-50); // Last 50 entries
trace.innerHTML = logs
.map(log => `
<div class="trace-line ${log.action}">
<strong>${log.timestamp}</strong> • ${log.action}: ${log.detail}
</div>
`)
.join('');
trace.scrollTop = trace.scrollHeight;
}
// ========================================================================
// Initialization
// ========================================================================
window.addEventListener('load', () => {
logExecution('system', 'LTMS console initialized');
render();
});
window.assertBelief = assertBelief;
window.addRule = addRule;
window.queryBelief = queryBelief;
window.semanticSearch = semanticSearch;
window.retractBelief = retractBelief;
window.socraticDemo = socraticDemo;
window.contradictionDemo = contradictionDemo;
window.clearAll = clearAll;
// Initialize ONNX on page load
window.addEventListener('load', async () => {
if (window.ONNXBridge) {
const ready = await window.ONNXBridge.initialize();
if (ready) {
logExecution('onnx', 'Semantic search ready (ONNX in-browser)');
} else {
logExecution('onnx', 'Semantic search ready (fallback mode)');
}
}
});
</script>
</body>
</html>