// SPDX-License-Identifier: Apache-2.0
// © 2026 Lutar, Stephen P. Jr. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11
//
// surfaces/governance.js — AI GOVERNANCE / Assurance holographic surface (Dev5).
//
// Leader/technique modeled (we are MODELED ON, never claim to BE):
// GUAC v1.0 (OpenSSF) — Graph for Understanding Artifact Composition
// Sigstore / Rekor — append-only hash-chained Merkle transparency log
// SCITT (IETF) — Transparent Statement -> Ledger Entry -> Merkle proof
// Technique: 3D force-directed dependency knowledge graph + 3D Merkle hash-chain
// tree + compliance crosswalk heatmap.
//
// DOCTRINE v11 (LOCKED): WIRE TO LIVE DATA, never fabricate. Every value on screen
// traces to a real a11oy endpoint and carries its honesty label read straight off the
// JSON. The 5 assurance/forge routes are PENDING the Forge mesh deploy and currently
// 404 -> ctx.live.poll renders the honest NO-LIVE-DATA badge for each; this viz is
// built to the REAL data shapes the engines (artifact_behaviour_monitor.py,
// content_credentials.py, compliance_crosswalk.py, runtime_attestation.py,
// forge_governance.py, pq_signing.py) WILL return, so it lights up automatically on 200.
//
// TEACHING POINT (doctrine): a SIGNATURE is NOT proof of safety — CVE-2026-45321
// (Mini Shai-Hulud): 84 @tanstack/* npm versions shipped VALID SLSA L3 / Sigstore
// provenance; provenance flagged ZERO; behaviour caught all 84. Λ = Conjecture 1
// (advisory governance, NOT proven trust / NOT proven safe).
//
// 0 runtime CDN: three via the page importmap (ctx.THREE); the SBOM force-graph reuses
// the repo-vendored 3d-force-graph UMD global at /vendor/3d-force-graph.min.js.
//
// CONTRACT: default-export { id, title, endpoints[], mount(ctx), unmount() }.
const ID = "governance";
const TITLE = "AI Governance · Assurance";
// The 5 gap routes (PENDING Forge mesh; 404 -> NO-LIVE-DATA until 200).
const EP = {
artifact: "/api/a11oy/v1/assurance/artifact", // artifact_behaviour_monitor.py
credential: "/api/a11oy/v1/assurance/credential", // content_credentials.py (C2PA)
compliance: "/api/a11oy/v1/assurance/compliance", // compliance_crosswalk.py + compliance.json
attest: "/api/a11oy/v1/assurance/attest", // runtime_attestation.py
ledger: "/api/a11oy/v1/forge/ledger", // forge_governance.py
};
const ENDPOINTS = Object.values(EP);
// Palette (matches the holographic shell tokens).
const C = {
accent: 0xb08fff, teal: 0x39d3c4, gold: 0xe8c074, red: 0xff6b6b,
green: 0x2fd07a, gray: 0x8a97a3, blue: 0x6fb1ff, cream: 0xeef3f6,
};
// Honest framework-status colors (IMPLEMENTED/PARTIAL/ROADMAP) for the heatmap.
const STATUS_COLOR = { IMPLEMENTED: 0x2fd07a, PARTIAL: 0xe8c074, ROADMAP: 0x8a97a3 };
let _stage = null, _THREE = null, _label = null, _live = null;
let _root = null; // THREE.Group holding everything we add to the scene
let _handles = []; // poll handles to stop on unmount
let _overlay = null, _graphPanel = null, _graph = null, _hud = {};
let _frameCb = null, _fgScript = null;
const _state = {}; // last meta per endpoint (for HUD)
// ---------------------------------------------------------------------------
// small helpers
// ---------------------------------------------------------------------------
function el(tag, css, txt) {
const e = document.createElement(tag);
if (css) e.style.cssText = css;
if (txt != null) e.textContent = txt;
return e;
}
function disposeObj(o) {
o.traverse?.((c) => {
if (c.geometry) c.geometry.dispose?.();
if (c.material) {
const m = c.material;
(Array.isArray(m) ? m : [m]).forEach((mm) => { mm.map?.dispose?.(); mm.dispose?.(); });
}
});
}
// ---------------------------------------------------------------------------
// mount
// ---------------------------------------------------------------------------
function mount(ctx) {
_stage = ctx.stage; _THREE = ctx.THREE; _label = ctx.label; _live = ctx.live;
const THREE = _THREE;
_root = new THREE.Group();
_stage.scene.add(_root);
_buildOverlay(ctx);
// --- the 7 in-scene scene demos (positioned around the estate) -----------
const merkle = buildMerkleTree(THREE); // Demo: Rekor-style 3D Merkle hash-chain tree
merkle.position.set(-7.5, 0, 0);
_root.add(merkle);
const helix = buildAttestationHelix(THREE); // Demo: attestation timeline helix
helix.position.set(7.5, -1, 0);
_root.add(helix);
const heatmap = buildComplianceHeatmap(THREE); // Demo: NIST/ISO/EU compliance heatmap (60/60/0)
heatmap.position.set(0, 4.2, -3);
_root.add(heatmap);
const ledger = buildLedgerChain(THREE); // Demo: Forge ledger hash-chain replay
ledger.position.set(0, -4.4, 0);
_root.add(ledger);
const axes = buildAttestationAxes(THREE); // Demo: 3-axis attestation (build/model/runtime)
axes.position.set(7.0, 4.0, -1);
_root.add(axes);
const pq = buildPqNode(THREE); // Demo: PQ hybrid Ed25519+ML-DSA node
pq.position.set(-7.5, 4.0, -1);
_root.add(pq);
const killSwitch = buildKillSwitch(THREE); // Demo: kill-switch indicator
killSwitch.position.set(0, 0, 6);
_root.add(killSwitch);
const callout = buildSigSafetyCallout(THREE); // Demo: signature ≠ safety teaching callout
callout.position.set(0, -8.2, 2);
_root.add(callout);
// doctrine billboards (every cluster is labelled honestly until its route is live)
_root.add(_label.billboard(THREE, "STRUCTURAL-ONLY", { text: "Merkle ledger", scale: 0.5, position: [-7.5, 4.4, 0] }));
_root.add(_label.billboard(THREE, "STRUCTURAL-ONLY", { text: "Attest helix", scale: 0.5, position: [7.5, 3.0, 0] }));
_root.add(_label.billboard(THREE, "MEASURED", { text: "Crosswalk 60/60/0", scale: 0.5, position: [0, 7.0, -3] }));
this_registerFrame(THREE, { merkle, helix, heatmap, ledger, axes, pq, killSwitch, callout });
// --- SBOM dependency force-graph (GUAC-style), reuses vendored ForceGraph3D
_initForceGraph();
// --- wire all 5 gap routes; each renders NO-LIVE-DATA honestly on 404 -----
startPolls(ctx);
return { id: ID, started: true };
}
// per-frame animation registered once with the stage.
function this_registerFrame(THREE, parts) {
let t = 0;
_frameCb = () => {
t += 0.016;
if (_root) _root.rotation.y = Math.sin(t * 0.08) * 0.06;
parts.helix.rotation.y += 0.006;
parts.merkle.rotation.y += 0.003;
parts.ledger.rotation.y -= 0.004;
// kill-switch pulse (armed=red glow throb; safe=steady green) — value set by poll
const ks = parts.killSwitch.userData;
if (ks.core) {
const armed = !!ks.armed;
const pulse = armed ? (0.5 + 0.5 * Math.sin(t * 6)) : 0.85;
ks.core.material.emissiveIntensity = (armed ? 0.6 : 0.3) + pulse * (armed ? 0.8 : 0.1);
}
// PQ node: two interlocked rings (Ed25519 + ML-DSA) counter-rotate
if (parts.pq.userData.ed) parts.pq.userData.ed.rotation.z += 0.01;
if (parts.pq.userData.ml) parts.pq.userData.ml.rotation.x -= 0.012;
// helix beads orbit on flowing
(parts.helix.userData.beads || []).forEach((b, i) => {
b.material.emissiveIntensity = 0.4 + 0.4 * Math.sin(t * 2 + i * 0.7);
});
};
_stage.onFrame(_frameCb);
}
// ===========================================================================
// DEMOS — 3D scene objects (built to the engine shapes; live values overlaid)
// ===========================================================================
// Demo 1: Rekor/SCITT-style 3D Merkle hash-chain tree (TubeGeometry branches).
// forge ledger uses a LINEAR khipu chain (prev_hash/entry_hash, no merkle); the
// Rekor inclusion proof is a binary Merkle tree — we render the canonical Merkle
// structure and color leaves by signature freshness once /forge/ledger is live.
function buildMerkleTree(THREE) {
const g = new THREE.Group(); g.userData.kind = "merkle";
const leafMat = () => new THREE.MeshStandardMaterial({
color: C.gray, emissive: C.gray, emissiveIntensity: 0.25, metalness: 0.4, roughness: 0.4,
});
const levels = 4; // 1 + 2 + 4 + 8 = 15 nodes
const nodes = [];
let y = 3.2;
const spread = 4.6;
const branchMat = new THREE.MeshStandardMaterial({ color: C.accent, emissive: C.accent, emissiveIntensity: 0.2, transparent: true, opacity: 0.55 });
const placed = [];
for (let lvl = 0; lvl < levels; lvl++) {
const count = Math.pow(2, lvl);
const row = [];
const w = spread * (lvl / (levels - 1));
for (let i = 0; i < count; i++) {
const x = count === 1 ? 0 : (-w + (2 * w) * (i / (count - 1)));
const isLeaf = lvl === levels - 1;
const geo = new THREE.OctahedronGeometry(isLeaf ? 0.28 : 0.36, 0);
const node = new THREE.Mesh(geo, leafMat());
node.position.set(x, y - lvl * 1.7, 0);
node.userData.leaf = isLeaf;
g.add(node); row.push(node); nodes.push(node);
}
placed.push(row);
}
// connect parents -> children with tube branches
for (let lvl = 0; lvl < levels - 1; lvl++) {
placed[lvl].forEach((parent, pi) => {
[2 * pi, 2 * pi + 1].forEach((ci) => {
const child = placed[lvl + 1][ci];
if (!child) return;
const curve = new THREE.LineCurve3(parent.position.clone(), child.position.clone());
const tube = new THREE.Mesh(new THREE.TubeGeometry(curve, 1, 0.03, 6, false), branchMat);
g.add(tube);
});
});
}
g.userData.leaves = placed[levels - 1];
g.userData.root = placed[0][0];
g.userData.allNodes = nodes;
return g;
}
// Demo 2: attestation timeline helix — SCITT-style. Each ring = a pipeline stage;
// beads = attestations (SLSA provenance, SBOM, test result) that lock into the ledger.
function buildAttestationHelix(THREE) {
const g = new THREE.Group(); g.userData.kind = "helix";
const turns = 3, perTurn = 12, n = turns * perTurn, R = 1.7, H = 6;
const pts = [];
for (let i = 0; i <= n; i++) {
const a = (i / perTurn) * Math.PI * 2;
const yy = -H / 2 + H * (i / n);
pts.push(new THREE.Vector3(Math.cos(a) * R, yy, Math.sin(a) * R));
}
const curve = new THREE.CatmullRomCurve3(pts);
const tube = new THREE.Mesh(
new THREE.TubeGeometry(curve, 200, 0.045, 8, false),
new THREE.MeshStandardMaterial({ color: C.teal, emissive: C.teal, emissiveIntensity: 0.3, transparent: true, opacity: 0.7 }),
);
g.add(tube);
const beads = [];
const stageColors = [C.gold, C.teal, C.accent, C.blue];
for (let i = 0; i < n; i += 3) {
const p = curve.getPointAt(i / n);
const bead = new THREE.Mesh(
new THREE.SphereGeometry(0.12, 12, 12),
new THREE.MeshStandardMaterial({ color: stageColors[(i / 3) % stageColors.length], emissive: stageColors[(i / 3) % stageColors.length], emissiveIntensity: 0.5 }),
);
bead.position.copy(p); g.add(bead); beads.push(bead);
}
g.userData.beads = beads;
return g;
}
// Demo 3: NIST / ISO / EU compliance crosswalk heatmap (HONEST 60/60/0).
// Rows = controls (compliance.json), cols = the 3 frameworks. Cell color =
// IMPLEMENTED/PARTIAL/ROADMAP; bar height = framework pct_implemented. We seed
// it with the STRUCTURAL frame from compliance.json and replace with live cells
// when /assurance/compliance is 200.
function buildComplianceHeatmap(THREE) {
const g = new THREE.Group(); g.userData.kind = "heatmap";
const frameworks = ["NIST", "ISO", "EU"];
const rows = 10, cols = 3, cw = 1.05, ch = 0.5;
const cells = [];
// STRUCTURAL seed mirroring compliance.json (NIST/ISO: 6 impl,3 part,1 road; EU: 0,9,1)
const seed = {
NIST: ["IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "PARTIAL", "PARTIAL", "PARTIAL", "ROADMAP"],
ISO: ["IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "IMPLEMENTED", "PARTIAL", "PARTIAL", "PARTIAL", "ROADMAP"],
EU: ["PARTIAL", "PARTIAL", "PARTIAL", "PARTIAL", "PARTIAL", "PARTIAL", "PARTIAL", "PARTIAL", "PARTIAL", "ROADMAP"],
};
for (let c = 0; c < cols; c++) {
for (let r = 0; r < rows; r++) {
const status = seed[frameworks[c]][r];
const mesh = new THREE.Mesh(
new THREE.BoxGeometry(cw * 0.9, 0.12, ch * 0.9),
new THREE.MeshStandardMaterial({ color: STATUS_COLOR[status], emissive: STATUS_COLOR[status], emissiveIntensity: 0.3, metalness: 0.2, roughness: 0.6 }),
);
mesh.position.set((c - 1) * cw, 0, (r - rows / 2) * ch);
mesh.userData = { framework: frameworks[c], row: r };
g.add(mesh); cells.push(mesh);
}
}
// framework coverage pillars (height = pct_implemented; seeded 60/60/0)
const pct = { NIST: 60, ISO: 60, EU: 0 };
const pillars = {};
frameworks.forEach((f, c) => {
const h = Math.max(0.05, (pct[f] / 100) * 3.5);
const col = pct[f] >= 100 ? C.green : (pct[f] > 0 ? C.gold : C.gray);
const pil = new THREE.Mesh(
new THREE.BoxGeometry(0.5, h, 0.5),
new THREE.MeshStandardMaterial({ color: col, emissive: col, emissiveIntensity: 0.35, transparent: true, opacity: 0.85 }),
);
pil.position.set((c - 1) * cw, h / 2 + 0.2, (rows / 2) * ch + 0.9);
g.add(pil); pillars[f] = pil;
const bb = _label.billboard(THREE, "MEASURED", { text: `${f} ${pct[f]}%`, scale: 0.34, position: [(c - 1) * cw, h + 0.7, (rows / 2) * ch + 0.9] });
g.add(bb);
});
g.userData.cells = cells; g.userData.pillars = pillars; g.userData.frameworks = frameworks;
return g;
}
// Demo 4: Forge ledger hash-chain replay — linear khipu chain (prev_hash/entry_hash).
// Genesis = 64 zeros; ring color (safe-auto/gated/forbidden) + decision (ALLOW/DENY/
// BLOCKED). Populated from /forge/ledger entries[]; kill_switch drives the indicator.
function buildLedgerChain(THREE) {
const g = new THREE.Group(); g.userData.kind = "ledger";
const n = 8, gap = 1.25;
const blocks = [];
for (let i = 0; i < n; i++) {
const blk = new THREE.Mesh(
new THREE.BoxGeometry(0.7, 0.7, 0.7),
new THREE.MeshStandardMaterial({ color: C.gray, emissive: C.gray, emissiveIntensity: 0.25, metalness: 0.5, roughness: 0.4 }),
);
blk.position.set((i - (n - 1) / 2) * gap, 0, 0);
g.add(blk); blocks.push(blk);
if (i > 0) {
const link = new THREE.Mesh(
new THREE.CylinderGeometry(0.025, 0.025, gap - 0.7, 6),
new THREE.MeshStandardMaterial({ color: C.accent, emissive: C.accent, emissiveIntensity: 0.3 }),
);
link.rotation.z = Math.PI / 2;
link.position.set((i - (n - 1) / 2) * gap - gap / 2, 0, 0);
g.add(link);
}
}
// genesis marker (64 zeros)
blocks[0].material.color.setHex(C.blue); blocks[0].material.emissive.setHex(C.blue);
g.userData.blocks = blocks;
return g;
}
// Demo 5: 3-axis attestation (build / model / runtime) — runtime_attestation.py.
// Three orthogonal axes; a bar grows along each present axis. trust_level rises
// NONE -> BUILD-ONLY -> BUILD+MODEL -> ALL-THREE-AXES. More axes = more STRUCTURE,
// NOT more safety (lambda_note).
function buildAttestationAxes(THREE) {
const g = new THREE.Group(); g.userData.kind = "axes";
const defs = [
{ name: "build", dir: [1, 0, 0], color: C.green },
{ name: "model", dir: [0, 1, 0], color: C.gold },
{ name: "runtime", dir: [0, 0, 1], color: C.teal },
];
const bars = {};
defs.forEach((d) => {
const len = 1.6;
const bar = new THREE.Mesh(
new THREE.CylinderGeometry(0.06, 0.06, len, 8),
new THREE.MeshStandardMaterial({ color: d.color, emissive: d.color, emissiveIntensity: 0.35, transparent: true, opacity: 0.45 }),
);
// orient cylinder (default +Y) along dir
const v = new THREE.Vector3(...d.dir);
bar.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), v);
bar.position.copy(v.clone().multiplyScalar(len / 2));
g.add(bar); bars[d.name] = bar;
});
const hub = new THREE.Mesh(
new THREE.SphereGeometry(0.2, 16, 16),
new THREE.MeshStandardMaterial({ color: C.accent, emissive: C.accent, emissiveIntensity: 0.4 }),
);
g.add(hub);
g.userData.bars = bars;
return g;
}
// Demo 6: PQ hybrid-signature node — pq_signing.py (Ed25519 + ML-DSA, FIPS-204
// ML-DSA-65). Two interlocked rings; hybrid policy = BOTH must verify. ML-DSA is
// a STRUCTURAL STUB in-sandbox (real:false) until the real PQ signer lands -> gray.
function buildPqNode(THREE) {
const g = new THREE.Group(); g.userData.kind = "pq";
const core = new THREE.Mesh(
new THREE.IcosahedronGeometry(0.45, 0),
new THREE.MeshStandardMaterial({ color: C.accent, emissive: C.accent, emissiveIntensity: 0.4, metalness: 0.5, roughness: 0.3 }),
);
g.add(core);
const ed = new THREE.Mesh(
new THREE.TorusGeometry(0.95, 0.05, 8, 40),
new THREE.MeshStandardMaterial({ color: C.green, emissive: C.green, emissiveIntensity: 0.45 }), // Ed25519 = real
);
g.add(ed);
const ml = new THREE.Mesh(
new THREE.TorusGeometry(0.95, 0.05, 8, 40),
new THREE.MeshStandardMaterial({ color: C.gray, emissive: C.gray, emissiveIntensity: 0.3 }), // ML-DSA = STUB until real
);
ml.rotation.x = Math.PI / 2;
g.add(ml);
g.userData.core = core; g.userData.ed = ed; g.userData.ml = ml;
return g;
}
// Demo 7: kill-switch indicator — forge_governance.py kill_switch bool. Armed
// (true) -> gated actions forced to DENY, throbbing red; safe (false) -> steady green.
function buildKillSwitch(THREE) {
const g = new THREE.Group(); g.userData.kind = "killswitch";
const ring = new THREE.Mesh(
new THREE.TorusGeometry(0.7, 0.08, 10, 48),
new THREE.MeshStandardMaterial({ color: C.gray, emissive: C.gray, emissiveIntensity: 0.3 }),
);
g.add(ring);
const core = new THREE.Mesh(
new THREE.SphereGeometry(0.42, 24, 24),
new THREE.MeshStandardMaterial({ color: C.green, emissive: C.green, emissiveIntensity: 0.4, metalness: 0.3, roughness: 0.4 }),
);
g.add(core);
g.userData.core = core; g.userData.ring = ring; g.userData.armed = false;
return g;
}
// Demo 8: signature ≠ safety teaching callout (CVE-2026-45321). A green "valid
// signature" badge sitting ON a red behavioural-anomaly body — the whole point:
// a valid signature does NOT make the artifact safe.
function buildSigSafetyCallout(THREE) {
const g = new THREE.Group(); g.userData.kind = "callout";
const body = new THREE.Mesh(
new THREE.BoxGeometry(1.4, 1.0, 1.0),
new THREE.MeshStandardMaterial({ color: C.red, emissive: C.red, emissiveIntensity: 0.35, transparent: true, opacity: 0.7 }),
);
g.add(body);
// a green "signature valid" seal stuck on the malicious body
const seal = new THREE.Mesh(
new THREE.CylinderGeometry(0.32, 0.32, 0.1, 24),
new THREE.MeshStandardMaterial({ color: C.green, emissive: C.green, emissiveIntensity: 0.5 }),
);
seal.rotation.x = Math.PI / 2; seal.position.set(0, 0, 0.55);
g.add(seal);
g.add(_label.billboard(THREE, "STRUCTURAL-ONLY", { text: "signature ≠ safety · CVE-2026-45321", scale: 0.4, position: [0, 1.0, 0] }));
return g;
}
// ===========================================================================
// SBOM dependency knowledge graph (GUAC-style) — reuses vendored ForceGraph3D.
// Demo 9. Renders into its own DOM panel (the UMD lib owns a three.js canvas).
// Seeded STRUCTURAL; replaced with real nodes/edges when /assurance/artifact 200s.
// ===========================================================================
function _seedSbom() {
// STRUCTURAL placeholder graph (clearly labelled). Real SBOM arrives via the
// artifact route's dependency closure + behavioural verdict per node.
const root = { id: "szl/agentic-pinn-solver", group: "root", status: "ROADMAP", val: 8 };
const nodes = [root];
const links = [];
const deps = ["numpy", "fastapi", "starlette", "cryptography", "uvicorn", "pydantic", "ed25519", "rekor-client"];
deps.forEach((d, i) => {
const node = { id: d, group: "dep", status: "ROADMAP", val: 3 };
nodes.push(node);
links.push({ source: root.id, target: d, rel: "depends-on" });
if (i % 3 === 0) {
const sub = { id: d + "·sub", group: "transitive", status: "ROADMAP", val: 2 };
nodes.push(sub);
links.push({ source: d, target: sub.id, rel: "depends-on" });
}
});
return { nodes, links };
}
function _initForceGraph() {
if (!_graphPanel) return;
const ForceGraph3D = (typeof window !== "undefined") && window.ForceGraph3D;
if (!ForceGraph3D) {
// vendored lib not yet on the page — inject it same-origin (0 CDN), then build.
if (!_fgScript) {
_fgScript = el("script");
_fgScript.src = "/vendor/3d-force-graph.min.js";
_fgScript.onload = () => { try { _buildForceGraph(); } catch (_) {} };
_fgScript.onerror = () => { if (_hud.sbom) _hud.sbom.textContent = "SBOM graph: vendored lib unavailable"; };
document.head.appendChild(_fgScript);
}
return;
}
_buildForceGraph();
}
function _buildForceGraph() {
const ForceGraph3D = window.ForceGraph3D;
if (!ForceGraph3D || !_graphPanel || _graph) return;
const data = _seedSbom();
_graph = ForceGraph3D()(_graphPanel)
.backgroundColor("rgba(5,7,13,0)")
.graphData(data)
.nodeLabel((n) => `${n.id} · ${n.status}`)
.nodeColor((n) => "#" + (STATUS_COLOR[n.status] || C.gray).toString(16).padStart(6, "0"))
.nodeVal((n) => n.val || 3)
.nodeOpacity(0.92)
.linkColor(() => "rgba(176,143,255,0.4)")
.linkDirectionalParticles(1)
.linkDirectionalParticleSpeed(0.006)
.width(_graphPanel.clientWidth || 360)
.height(_graphPanel.clientHeight || 240)
.showNavInfo(false);
}
// update the SBOM graph from a live /assurance/artifact verdict (real shape).
function _updateSbomFromArtifact(json) {
if (!_graph) return;
// The artifact route returns a behavioural verdict (assess_live_certificate /
// assess_artifact). When a full dependency closure is present we render it; else
// we color the single certified artifact node by its verdict.
const verdict = json.behavioural_verdict || json.verdict;
const vColor = verdict === "ALLOW" ? "PARTIAL" : (verdict === "DENY" ? null : "ROADMAP");
const data = _graph.graphData();
if (data && data.nodes && data.nodes.length) {
data.nodes.forEach((n) => {
if (n.group === "root") {
// DENY -> red; ALLOW -> amber (PARTIAL, never green: signature ≠ safety);
n.status = vColor || "DENY";
n._deny = verdict === "DENY";
}
});
_graph.nodeColor((n) => n._deny ? "#ff6b6b" : ("#" + (STATUS_COLOR[n.status] || C.gray).toString(16).padStart(6, "0")));
_graph.refresh && _graph.refresh();
}
}
// ===========================================================================
// OVERLAY HUD — badges per route + legend + teaching callout + SBOM panel
// ===========================================================================
function _buildOverlay(ctx) {
_overlay = el("div", "position:absolute;left:14px;top:14px;z-index:5;display:flex;flex-direction:column;gap:9px;max-width:min(94%,440px);pointer-events:none");
const head = el("div", "font:600 14px ui-sans-serif,system-ui;color:#eef3f6;letter-spacing:.4px", TITLE);
_overlay.appendChild(head);
const sub = el("div", "font:10.5px ui-monospace,Menlo,monospace;color:#9fb1bf;line-height:1.5",
"modeled on GUAC v1.0 · Sigstore/Rekor · SCITT — knowledge graph + Merkle hash-chain + crosswalk");
_overlay.appendChild(sub);
// per-route live badges (each shows NO-LIVE-DATA until Forge meshes it)
const badgeWrap = el("div", "display:flex;flex-direction:column;gap:5px;pointer-events:auto");
_hud.badges = {};
const ROUTE_LABEL = {
artifact: "artifact (behaviour monitor)", credential: "credential (C2PA)",
compliance: "compliance (crosswalk)", attest: "attest (build/model/runtime)",
ledger: "forge ledger (hash-chain)",
};
Object.keys(EP).forEach((k) => {
const row = el("div", "display:flex;align-items:center;gap:8px");
const tag = el("span", "font:10px ui-monospace,monospace;color:#7d8a96;min-width:182px", ROUTE_LABEL[k]);
const badge = _live.createBadge();
_hud.badges[k] = badge;
row.appendChild(tag); row.appendChild(badge.el);
badgeWrap.appendChild(row);
});
_overlay.appendChild(badgeWrap);
// honesty legend (doctrine chips)
const legend = _label.legend(); legend.style.opacity = "0.9"; legend.style.pointerEvents = "auto";
_overlay.appendChild(legend);
// teaching callout (doctrine): signature ≠ safety
const teach = el("div",
"pointer-events:auto;margin-top:2px;padding:8px 10px;border:1px solid #3a2330;border-radius:8px;" +
"background:rgba(255,107,107,.08);color:#ffb4b4;font:10.5px ui-monospace,Menlo,monospace;line-height:1.55");
teach.innerHTML =
"A signature is NOT proof of safety.
" +
"CVE-2026-45321 (Mini Shai-Hulud): 84 @tanstack/* npm versions shipped valid " +
"SLSA L3 / Sigstore provenance. Provenance flagged 0; behaviour caught all 84. " +
"Λ = Conjecture 1 — advisory governance, NOT proven trust.";
_overlay.appendChild(teach);
// status / scope line (filled live)
_hud.status = el("div", "font:10px ui-monospace,monospace;color:#7d8a96;line-height:1.5;pointer-events:auto");
_hud.status.textContent = "awaiting Forge mesh — all 5 assurance routes render NO-LIVE-DATA honestly until 200.";
_overlay.appendChild(_hud.status);
// SBOM graph panel (bottom-right), hosts the GUAC-style force-directed graph
_graphPanel = el("div",
"position:absolute;right:14px;bottom:42px;width:min(40vw,380px);height:min(34vh,260px);z-index:5;" +
"border:1px solid #1b2734;border-radius:10px;background:rgba(7,13,21,.55);overflow:hidden;pointer-events:auto");
const gh = el("div", "position:absolute;left:8px;top:6px;z-index:2;font:10px ui-monospace,monospace;color:#9fb1bf", "SBOM dependency graph · GUAC-style");
_hud.sbom = el("div", "position:absolute;left:8px;bottom:6px;z-index:2;font:9.5px ui-monospace,monospace;color:#7d8a96", "STRUCTURAL-ONLY · awaiting /assurance/artifact");
_graphPanel.appendChild(gh); _graphPanel.appendChild(_hud.sbom);
const host = ctx.container || document.body;
host.appendChild(_overlay);
host.appendChild(_graphPanel);
}
// ===========================================================================
// LIVE POLLS — wire each gap route; render honest state; light up on 200.
// ===========================================================================
function startPolls(ctx) {
// 1) artifact behaviour monitor -> SBOM node verdict + status
_handles.push(_live.poll(EP.artifact, 6000, (json, meta) => {
_state.artifact = meta;
_updateSbomFromArtifact(json);
const v = json.behavioural_verdict || json.verdict;
if (v && _hud.sbom) {
const safe = json.signature_alone_is_safety; // doctrine invariant: always false
_hud.sbom.textContent = `verdict ${v} · sig==safety:${safe === undefined ? "?" : safe} · ${json.fired_monitors ? json.fired_monitors.length : 0} fired`;
}
}, { badge: _hud.badges.artifact }));
// 2) C2PA credential -> trust hint colors the callout seal honestly
_handles.push(_live.poll(EP.credential, 7000, (json, meta) => {
_state.credential = meta;
// trust_hint ∈ {STRUCTURAL-ONLY, SELF_SIGNED, C2PA_TRUST_LIST, TAMPERED} — never "green"
const hint = json.trust_hint || (json.active_manifest && json.active_manifest.labels && json.active_manifest.labels.trust);
const callout = _root && _root.children.find((c) => c.userData && c.userData.kind === "callout");
if (callout) {
const seal = callout.children.find((c) => c.geometry && c.geometry.type === "CylinderGeometry");
if (seal) {
const col = hint === "TAMPERED" ? C.red : (hint === "C2PA_TRUST_LIST" ? C.green : C.gold);
seal.material.color.setHex(col); seal.material.emissive.setHex(col);
}
}
}, { badge: _hud.badges.credential }));
// 3) compliance crosswalk -> recolor heatmap cells + resize pillars (60/60/0 honest)
_handles.push(_live.poll(EP.compliance, 8000, (json, meta) => {
_state.compliance = meta;
_applyCompliance(json);
}, { badge: _hud.badges.compliance }));
// 4) runtime attestation -> grow the present build/model/runtime axis bars
_handles.push(_live.poll(EP.attest, 7000, (json, meta) => {
_state.attest = meta;
_applyAttest(json);
}, { badge: _hud.badges.attest }));
// 5) forge ledger -> color blocks by ring/decision, drive kill-switch indicator
_handles.push(_live.poll(EP.ledger, 6000, (json, meta) => {
_state.ledger = meta;
_applyLedger(json);
}, { badge: _hud.badges.ledger }));
// roll a compact status line as states change
_handles.forEach((h) => {});
_refreshStatus();
const si = setInterval(_refreshStatus, 2000);
_handles.push({ stop: () => clearInterval(si) });
}
function _refreshStatus() {
if (!_hud.status) return;
const live = Object.keys(_state).filter((k) => _state[k] && _state[k].state === "live");
const missing = Object.keys(EP).filter((k) => !_state[k] || _state[k].state === "missing" || _state[k].state === "init");
if (live.length === 0) {
_hud.status.textContent = `awaiting Forge mesh · ${missing.length}/5 routes NO-LIVE-DATA · viz lights up automatically on 200`;
_hud.status.style.color = "#7d8a96";
} else {
_hud.status.textContent = `LIVE: ${live.join(", ")} · ${missing.length} still awaiting Forge mesh`;
_hud.status.style.color = "#39d3c4";
}
}
function _applyCompliance(json) {
const heatmap = _root && _root.children.find((c) => c.userData && c.userData.kind === "heatmap");
if (!heatmap) return;
const cov = (json.coverage || json).frameworks || json.frameworks;
const crosswalk = json.crosswalk;
const FW = { NIST_AI_RMF: "NIST", ISO_IEC_42001: "ISO", EU_AI_ACT: "EU" };
// recolor cells from the real crosswalk[] (control x framework x status)
if (Array.isArray(crosswalk)) {
const byFw = { NIST: [], ISO: [], EU: [] };
crosswalk.forEach((c) => { const f = FW[c.framework]; if (f) byFw[f].push(c.status); });
heatmap.userData.cells.forEach((cell) => {
const arr = byFw[cell.userData.framework];
const st = arr && arr[cell.userData.row];
if (st && STATUS_COLOR[st]) { cell.material.color.setHex(STATUS_COLOR[st]); cell.material.emissive.setHex(STATUS_COLOR[st]); }
});
}
// resize coverage pillars to real pct_implemented (honest 60/60/0 expected)
if (cov) {
Object.entries(FW).forEach(([apiKey, shortKey]) => {
const entry = cov[apiKey];
const pil = heatmap.userData.pillars[shortKey];
if (entry && pil && typeof entry.pct_implemented === "number") {
const h = Math.max(0.05, (entry.pct_implemented / 100) * 3.5);
pil.scale.y = h / pil.geometry.parameters.height;
pil.position.y = h / 2 + 0.2;
const col = entry.pct_implemented >= 100 ? C.green : (entry.pct_implemented > 0 ? C.gold : C.gray);
pil.material.color.setHex(col); pil.material.emissive.setHex(col);
}
});
}
}
function _applyAttest(json) {
const axes = _root && _root.children.find((c) => c.userData && c.userData.kind === "axes");
if (!axes) return;
const present = json.axes_present || [];
["build", "model", "runtime"].forEach((name) => {
const bar = axes.userData.bars[name];
if (!bar) return;
const on = present.indexOf(name) >= 0;
bar.material.opacity = on ? 0.95 : 0.3;
bar.material.emissiveIntensity = on ? 0.55 : 0.2;
});
}
function _applyLedger(json) {
const ledger = _root && _root.children.find((c) => c.userData && c.userData.kind === "ledger");
const killSwitch = _root && _root.children.find((c) => c.userData && c.userData.kind === "killswitch");
const entries = json.entries || json.replay || [];
const RING = { "safe-auto": C.green, gated: C.gold, forbidden: C.red, unknown: C.gray };
if (ledger && Array.isArray(entries)) {
ledger.userData.blocks.forEach((blk, i) => {
const e = entries[i];
if (!e) return;
if (i === 0) return; // keep genesis blue
const col = e.decision === "BLOCKED" || e.decision === "DENY" ? C.red : (RING[e.ring] || C.gray);
blk.material.color.setHex(col); blk.material.emissive.setHex(col);
});
}
// kill-switch: forge_governance kill_switch bool -> armed indicator
if (killSwitch) {
const armed = !!json.kill_switch;
killSwitch.userData.armed = armed;
const col = armed ? C.red : C.green;
killSwitch.userData.core.material.color.setHex(col);
killSwitch.userData.core.material.emissive.setHex(col);
}
}
// ---------------------------------------------------------------------------
// unmount
// ---------------------------------------------------------------------------
function unmount() {
_handles.forEach((h) => { try { h.stop && h.stop(); } catch (_) {} });
_handles = [];
try { if (_frameCb && _stage && _stage.offFrame) _stage.offFrame(_frameCb); } catch (_) {}
_frameCb = null;
try { if (_graph && _graph._destructor) _graph._destructor(); } catch (_) {}
_graph = null;
try { if (_root && _stage) { disposeObj(_root); _stage.scene.remove(_root); } } catch (_) {}
_root = null;
[_overlay, _graphPanel].forEach((n) => { try { if (n && n.parentNode) n.parentNode.removeChild(n); } catch (_) {} });
_overlay = null; _graphPanel = null; _hud = {};
_stage = null; _THREE = null; _label = null; _live = null;
for (const k in _state) delete _state[k];
}
export default { id: ID, title: TITLE, endpoints: ENDPOINTS, mount, unmount };