snapkitty
agents
python
holy-agents / docs /twins.html
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/holy-agents
662ceed verified
Raw History Blame Contribute Delete
22.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>twins · holy-agents</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{background:#0a0a0a;color:#b0b0b0;font-family:'Courier New',monospace;min-height:100vh}
.nav{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;border-bottom:1px solid #1a1a1a}
.nav-brand{color:#e0e0e0;font-size:14px;letter-spacing:2px}
.nav-links a{color:#555;text-decoration:none;margin-left:16px;font-size:11px}
.nav-links a:hover,.nav-links a.active{color:#e0e0e0}
.container{max-width:900px;margin:0 auto;padding:32px 20px}
h1{color:#e0e0e0;font-size:18px;margin-bottom:8px}
p{color:#555;font-size:12px;margin-bottom:24px}
.twin-card{border:1px solid #1a1a1a;margin-bottom:16px;padding:20px;position:relative;overflow:hidden}
.twin-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.twin-name{color:#e0e0e0;font-size:14px;display:flex;align-items:center;gap:8px}
.twin-emoji{font-size:20px}
.twin-zone{color:#444;font-size:10px}
.twin-status{padding:3px 10px;font-size:10px;border:1px solid;text-transform:uppercase;letter-spacing:1px}
.twin-status.auditing{border-color:#a84;color:#a84;animation:pulse 1s infinite}
.twin-status.complete{border-color:#4a9;color:#4a9}
.twin-status.fail{border-color:#a44;color:#a44}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}
.twin-body{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.twin-metric{border:1px solid #111;padding:12px}
.twin-metric-label{color:#555;font-size:9px;text-transform:uppercase;letter-spacing:1px;margin-bottom:4px}
.twin-metric-value{color:#e0e0e0;font-size:16px}
.twin-metric-value.pass{color:#4a9}
.twin-metric-value.fail{color:#a44}
.twin-metric-value.warn{color:#a84}
.findings{margin-top:12px;border-top:1px solid #111;padding-top:12px}
.finding{padding:6px 0;border-bottom:1px solid #0a0a0a;font-size:11px}
.finding:last-child{border-bottom:none}
.finding-sev{display:inline-block;width:60px;font-size:9px;text-transform:uppercase}
.finding-sev.critical{color:#a44}
.finding-sev.high{color:#a44}
.finding-sev.medium{color:#a84}
.finding-sev.low{color:#555}
.finding-sev.info{color:#444}
.disagreements{margin-top:16px;border:1px solid #a443;padding:12px}
.disagreements h3{color:#a44;font-size:11px;margin-bottom:8px}
.disagreement{font-size:10px;color:#888;margin-bottom:4px}
.remediation{margin-top:24px}
.remediation h2{color:#e0e0e0;font-size:14px;margin-bottom:4px}
.remediation-sub{color:#555;font-size:11px;margin-bottom:16px}
.repair-card{border:1px solid #1a1a1a;margin-bottom:12px;overflow:hidden}
.repair-header{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid #111}
.repair-id{color:#e0e0e0;font-size:11px;font-weight:bold}
.repair-verdict{padding:2px 8px;font-size:9px;border:1px solid;text-transform:uppercase;letter-spacing:1px}
.repair-verdict.before{border-color:#a44;color:#a44}
.repair-verdict.after{border-color:#4a9;color:#4a9}
.repair-body{padding:12px 16px}
.repair-row{display:flex;gap:12px;margin-bottom:8px}
.repair-col{flex:1;padding:10px;border:1px solid #111}
.repair-col-label{font-size:9px;text-transform:uppercase;letter-spacing:1px;margin-bottom:4px}
.repair-col.before .repair-col-label{color:#a44}
.repair-col.after .repair-col-label{color:#4a9}
.repair-col.before{background:#0a0000}
.repair-col.after{background:#000a00}
.repair-col-text{font-size:10px;color:#888;line-height:1.5}
.repair-file{font-size:9px;color:#444;margin-top:4px}
.animation-zone{border:1px solid #1a1a1a;padding:16px;margin-bottom:16px;text-align:center}
#twin-canvas{background:#050505;display:block;margin:0 auto}
.vote-bar{display:flex;gap:4px;margin-top:12px;justify-content:center}
.vote{padding:4px 12px;font-size:10px;border:1px solid #1a1a1a}
.vote.pass{border-color:#4a9;color:#4a9}
.vote.fail{border-color:#a44;color:#a44}
</style>
</head>
<body>
<nav class="nav">
<div class="nav-brand">holy-agents</div>
<div class="nav-links">
<a href="index.html">home</a>
<a href="query.html">query</a>
<a href="twins.html" class="active">twins</a>
<a href="agents.html">agents</a>
<a href="geometry.html">geometry</a>
<a href="debate.html">debate</a>
<a href="repl.html">repl</a>
</div>
</nav>
<div class="container">
<h1>Digital Twin Audit</h1>
<p>Three independent auditors run in parallel. Disagreements are logged, not hidden.</p>
<div class="animation-zone">
<canvas id="twin-canvas" width="860" height="200"></canvas>
<div class="vote-bar">
<div class="vote" id="vote-a">🛡️ TWIN-A</div>
<div class="vote" id="vote-b">⚖️ TWIN-B</div>
<div class="vote" id="vote-c">⚡ TWIN-C</div>
</div>
</div>
<div class="twin-card" id="twin-a">
<div class="twin-header">
<div class="twin-name"><span class="twin-emoji">🛡️</span> TWIN-A — Security Auditor</div>
<span class="twin-status auditing" id="status-a">auditing</span>
</div>
<div class="twin-zone">zone: sentinel_gate</div>
<div class="twin-body">
<div class="twin-metric"><div class="twin-metric-label">Confidence</div><div class="twin-metric-value" id="conf-a">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Verdict</div><div class="twin-metric-value" id="verd-a">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Critical</div><div class="twin-metric-value" id="crit-a">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Findings</div><div class="twin-metric-value" id="find-a">—</div></div>
</div>
<div class="findings" id="findings-a"></div>
</div>
<div class="twin-card" id="twin-b">
<div class="twin-header">
<div class="twin-name"><span class="twin-emoji">⚖️</span> TWIN-B — Logic Auditor</div>
<span class="twin-status auditing" id="status-b">auditing</span>
</div>
<div class="twin-zone">zone: court</div>
<div class="twin-body">
<div class="twin-metric"><div class="twin-metric-label">Confidence</div><div class="twin-metric-value" id="conf-b">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Verdict</div><div class="twin-metric-value" id="verd-b">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">High</div><div class="twin-metric-value" id="high-b">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Findings</div><div class="twin-metric-value" id="find-b">—</div></div>
</div>
<div class="findings" id="findings-b"></div>
</div>
<div class="twin-card" id="twin-c">
<div class="twin-header">
<div class="twin-name"><span class="twin-emoji">⚡</span> TWIN-C — Performance Auditor</div>
<span class="twin-status auditing" id="status-c">auditing</span>
</div>
<div class="twin-zone">zone: forge</div>
<div class="twin-body">
<div class="twin-metric"><div class="twin-metric-label">Confidence</div><div class="twin-metric-value" id="conf-c">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Verdict</div><div class="twin-metric-value" id="verd-c">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Critical</div><div class="twin-metric-value" id="crit-c">—</div></div>
<div class="twin-metric"><div class="twin-metric-label">Findings</div><div class="twin-metric-value" id="find-c">—</div></div>
</div>
<div class="findings" id="findings-c"></div>
</div>
<div class="disagreements" id="disagreements" style="display:none">
<h3>⚡ Disagreements</h3>
<div id="disagreement-list"></div>
</div>
<div class="remediation">
<h2>Previous Failure → Current Pass</h2>
<div class="remediation-sub">9 consensus failures repaired via repentance cycle. Each finding was diagnosed, repaired, and re-audited.</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">1. WORM Race Condition</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">readEntries() → modify → writeEntries() rewrote entire file. Concurrent appends overwrite each other.</div><div class="repair-file">src/worm.ts — writeEntries()</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">appendLine() using fs.appendFileSync(). Single-line atomic append, no full-file rewrite.</div><div class="repair-file">src/worm.ts — appendLine()</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">2. Path Traversal Vulnerability</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">serveStatic() joined paths with no containment check. /docs/../../src/server.ts served arbitrary files.</div><div class="repair-file">src/server.ts — path.join()</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">isPathSafe() resolves full path, checks it starts with DOCS_DIR. Returns 403 on escape.</div><div class="repair-file">src/server.ts — isPathSafe()</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">3. RTRUST Enforcement Incomplete</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">checkActionAgainstRules() checked 3 of 7 principles: truthfulness, love, justice. Autonomy, accountability, attribution unenforced.</div><div class="repair-file">src/rtrust.ts — switch (principle)</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">Added autonomy (consent), accountability (witnessed), attribution (cited). All 7 principles enforced.</div><div class="repair-file">src/rtrust.ts — 7 cases</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">4. Reverse Proof Not Integrated</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">reverseProof hardcoded to { allVerified: true, orphanArtifacts: [] }. buildReverseProof() never called.</div><div class="repair-file">src/server.ts — /query endpoint</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">buildReverseProof() called with actual artifact maps. Article III of Second Trust Deed enforced.</div><div class="repair-file">src/server.ts — /query, /audit</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">5. Unsafe JSON.parse</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">JSON.parse without try/catch in worm.ts, rtrust.ts, server.ts. Corrupted data crashes the system.</div><div class="repair-file">src/worm.ts, rtrust.ts, server.ts</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">All JSON.parse calls wrapped in try/catch. Corrupt lines skipped gracefully. POST handlers return 400.</div><div class="repair-file">src/worm.ts, rtrust.ts, server.ts</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">6. Missing Request Validation</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">POST endpoints accept arbitrary JSON. body.query as string — no type checks.</div><div class="repair-file">src/server.ts — POST /query, /action</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">validateQueryBody() and validateActionBody() type guards. Returns 400 for missing/invalid fields.</div><div class="repair-file">src/server.ts — validators</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">7. Sync I/O Hot Paths</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">loadRTRUST() reads constitution from disk on every request. No caching.</div><div class="repair-file">src/rtrust.ts — loadRTRUST()</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">Module-level cachedRules with clearRTRUSTCache(). Loaded once, cached for subsequent requests.</div><div class="repair-file">src/rtrust.ts — cachedRules</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">8. FORBIDDEN_ACTIONS Incomplete</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">unmerciful_judgment, cruelty, vengeance from RTRUST-006 missing. 21 of 24.</div><div class="repair-file">src/validation.ts — FORBIDDEN_ACTIONS</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">Added 3 missing actions. Total now 24. All RTRUST-006 violations covered.</div><div class="repair-file">src/validation.ts — 24 items</div></div>
</div>
</div>
</div>
<div class="repair-card">
<div class="repair-header">
<span class="repair-id">9. Sentinel Skips RTRUST</span>
<div><span class="repair-verdict before">FAIL</span> <span class="repair-verdict after">PASS</span></div>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before</div><div class="repair-col-text">sentinelCheck() only calls validateAction and checkForbidden. RTRUST rule violations ignored.</div><div class="repair-file">src/agents/sentinel.ts — sentinelCheck()</div></div>
<div class="repair-col after"><div class="repair-col-label">After</div><div class="repair-col-text">Now imports and calls checkActionAgainstRules() from rtrust.ts. RTRUST violations added to violations array.</div><div class="repair-file">src/agents/sentinel.ts — RTRUST check</div></div>
</div>
</div>
</div>
<div class="repair-card" style="border-color:#4a9">
<div class="repair-header" style="background:#000a00">
<span class="repair-id" style="color:#4a9">Re-Audit Summary</span>
<span class="repair-verdict after" style="font-size:10px">0/3 FAIL</span>
</div>
<div class="repair-body">
<div class="repair-row">
<div class="repair-col before"><div class="repair-col-label">Before — All Twins</div><div class="repair-col-text">TWIN-A (Security): FAIL 0.88<br>TWIN-B (Logic): FAIL 0.42<br>TWIN-C (Performance): FAIL 0.45</div></div>
<div class="repair-col after"><div class="repair-col-label">After — All Twins</div><div class="repair-col-text">TWIN-A (Security): PASS 0.92<br>TWIN-B (Logic): PASS 0.85<br>TWIN-C (Performance): PASS 0.88</div></div>
</div>
</div>
</div>
</div>
</div>
<script>
const REPLAY = {
twins: {
security: {
verdict: 'pass', confidence: 0.92, findings: [
{ severity: 'low', category: 'weak_randomness', description: 'Math.random() in visualizer.js — not security-relevant' },
{ severity: 'info', category: 'self_audit', description: 'Security twin does not audit itself — by design' }
]
},
logic: {
verdict: 'pass', confidence: 0.85, findings: [
{ severity: 'medium', category: 'principle_list', description: 'Required principles hardcoded — add 8th would not be detected' },
{ severity: 'low', category: 'incomplete_test', description: 'Only one test action in logic twin check' }
]
},
performance: {
verdict: 'pass', confidence: 0.88, findings: [
{ severity: 'low', category: 'false_async', description: 'Promise.resolve() wrapping sync functions — negligible overhead' },
{ severity: 'info', category: 'acceptable', description: 'Sync I/O acceptable for startup config reads' }
]
}
},
disagreements: []
};
const canvas = document.getElementById('twin-canvas');
const ctx = canvas.getContext('2d');
const zones = { sentinel_gate: { x: 210, y: 100 }, court: { x: 430, y: 100 }, forge: { x: 650, y: 100 } };
const twins = [
{ name: 'TWIN-A', emoji: '🛡️', zone: 'sentinel_gate', color: '#44a' },
{ name: 'TWIN-B', emoji: '⚖️', zone: 'court', color: '#a84' },
{ name: 'TWIN-C', emoji: '⚡', zone: 'forge', color: '#a44' }
];
let particles = [];
function drawZones() {
Object.entries(zones).forEach(([k, v]) => {
ctx.strokeStyle = '#1a1a1a';
ctx.strokeRect(v.x - 60, v.y - 40, 120, 80);
ctx.fillStyle = '#1a1a1a';
ctx.font = '9px Courier New';
ctx.textAlign = 'center';
ctx.fillText(k.replace('_', ' '), v.x, v.y + 55);
});
}
function drawTwins() {
twins.forEach((t, i) => {
const z = zones[t.zone];
ctx.font = '24px serif';
ctx.textAlign = 'center';
ctx.fillText(t.emoji, z.x, z.y + 8);
ctx.font = '10px Courier New';
ctx.fillStyle = t.color;
ctx.fillText(t.name, z.x, z.y + 28);
});
}
function spawnParticle(from, to, color) {
const fx = zones[from].x, fy = zones[from].y;
const tx = zones[to].x, ty = zones[to].y;
for (let i = 0; i < 3; i++) {
particles.push({
x: fx, y: fy,
vx: (tx - fx) / 40 + (Math.random() - 0.5) * 2,
vy: (ty - fy) / 40 + (Math.random() - 0.5) * 2,
life: 40, maxLife: 40, color
});
}
}
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawZones();
drawTwins();
particles = particles.filter(p => p.life > 0);
particles.forEach(p => {
p.x += p.vx; p.y += p.vy; p.life--;
ctx.globalAlpha = p.life / p.maxLife;
ctx.fillStyle = p.color;
ctx.fillRect(p.x, p.y, 2, 2);
});
ctx.globalAlpha = 1;
requestAnimationFrame(render);
}
render();
async function runAudit() {
const twins_data = REPLAY.twins;
const labels = ['a', 'b', 'c'];
const keys = ['security', 'logic', 'performance'];
const confs = ['0.92', '0.85', '0.88'];
for (let i = 0; i < 3; i++) {
await new Promise(r => setTimeout(r, 800));
const t = twins_data[keys[i]];
document.getElementById(`status-${labels[i]}`).textContent = 'complete';
document.getElementById(`status-${labels[i]}`).className = 'twin-status complete';
document.getElementById(`conf-${labels[i]}`).textContent = confs[i];
document.getElementById(`conf-${labels[i]}`).className = 'twin-metric-value ' + (t.verdict === 'pass' ? 'pass' : 'fail');
document.getElementById(`verd-${labels[i]}`).textContent = t.verdict;
document.getElementById(`verd-${labels[i]}`).className = 'twin-metric-value ' + (t.verdict === 'pass' ? 'pass' : 'fail');
const critCount = t.findings.filter(f => f.severity === 'critical').length;
const highCount = t.findings.filter(f => f.severity === 'high').length;
document.getElementById(labels[i] === 'b' ? `high-b` : `crit-${labels[i]}`).textContent = labels[i] === 'b' ? highCount : critCount;
document.getElementById(`find-${labels[i]}`).textContent = t.findings.length;
const findingsEl = document.getElementById(`findings-${labels[i]}`);
findingsEl.innerHTML = t.findings.map(f =>
`<div class="finding"><span class="finding-sev ${f.severity}">${f.severity}</span> ${f.description}</div>`
).join('');
document.getElementById(`vote-${labels[i]}`).className = `vote ${t.verdict}`;
spawnParticle(twins[i].zone, twins[(i + 1) % 3].zone, twins[i].color);
}
}
runAudit();
</script>
</body>
</html>