From d7f5657bc70b1a5a401be235b205974d6c76cb9d Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Wed, 8 Jul 2026 21:49:22 -0700 Subject: [PATCH] feat(observatory): contradiction firewall fires on real events (Phase 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The crimson quarantine firewall was hard-locked to the deterministic demo clock. Now it fires on real cognitive events — a MemorySuppressed or a DeepReferenceCompleted contradiction pair — targeting the REAL memory and its REAL graph neighbors, on camera. - firewall-plan: buildLiveFirewallPlan(graph, seed, intruderIndex) reuses all the deterministic machinery (real-layout shock delays, real severed neighbors, spine, verdict) but takes the intruder from the live event. - firewall.wgsl + render-nodes.wgsl: dual-gate on demo_id==4 OR live_kind==1, driven by live_frame (frames since the event) so the 720-frame beat map plays once from the event, not the loop clock. - firewall-renderer: rearm(plan) rebuilds the fire buffer for a live target; compute() gates on demo OR live. - live-bridge: lazily builds + rearms a live FirewallRenderer on a firewall event; onFirewall callback surfaces the verdict. - ObservatoryStage: crimson "threat quarantined" verdict card naming the real memory, auto-clears after the choreography. - live lane [13] repurposed liveStartFrame -> liveFrame (event-relative). Verified live: fired 3 real suppressions on the 1241-memory brain — each raised the crimson verdict naming the real memory ("ProtocolGate Lane 4 design decision", cascade ~54), the field ran the quarantine, the forget counter incremented 129->132, then all 3 reversed cleanly. check 0 err, 1033 tests, build green. Co-Authored-By: Claude Opus 4.8 --- .../lib/observatory/ObservatoryStage.svelte | 45 ++++++++++++++++++- .../src/lib/observatory/firewall-plan.ts | 35 ++++++++++++++- .../src/lib/observatory/firewall-renderer.ts | 30 ++++++++++++- .../src/lib/observatory/live-bridge.ts | 42 ++++++++++++++++- .../shaders/birth-particles.wgsl.ts | 2 +- .../lib/observatory/shaders/firewall.wgsl.ts | 25 ++++++++--- .../observatory/shaders/forgetting.wgsl.ts | 2 +- .../observatory/shaders/render-edges.wgsl.ts | 2 +- .../observatory/shaders/render-nodes.wgsl.ts | 10 +++-- .../observatory/shaders/render-path.wgsl.ts | 2 +- .../lib/observatory/shaders/rescue.wgsl.ts | 2 +- .../lib/observatory/shaders/simulate.wgsl.ts | 2 +- apps/dashboard/src/lib/observatory/types.ts | 9 ++-- 13 files changed, 184 insertions(+), 24 deletions(-) diff --git a/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte b/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte index 1c8881d..0693e34 100644 --- a/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte +++ b/apps/dashboard/src/lib/observatory/ObservatoryStage.svelte @@ -96,6 +96,11 @@ let projectionDays = $state(0); let liveBridge: LiveBridge | null = null; let liveDecayReady = $state(false); + // Live contradiction-firewall verdict — set when a real MemorySuppressed / + // contradiction event quarantines a memory on camera. Held ~7s then fades. + let liveFirewallLabel = $state(''); + let liveFirewallAt = $state(0); + let liveFirewallVisible = $derived(liveFirewallLabel !== '' && liveFirewallAt > 0); // GPU picking — screen px → NDC → NodeRenderer.pickAt (one readback/click). let canvasLayerEl: HTMLDivElement | null = $state(null); @@ -297,7 +302,12 @@ engine, renderer, graph: renderer.graph, - projectionDays: () => projectionDays + seed, + projectionDays: () => projectionDays, + onFirewall: (info) => { + liveFirewallLabel = info.intruderLabel; + liveFirewallAt = Date.now(); + } }); liveDecayReady = liveBridge.liveDecayAvailable; engine.setPreFrameHook((simFrame) => liveBridge?.drain(simFrame)); @@ -324,6 +334,17 @@ liveBridge?.refreshDecay(); }); + // Auto-clear the live firewall verdict ~7s after it fires (matches the + // quarantine choreography length so the card leaves with the crimson ring). + $effect(() => { + if (!liveFirewallAt) return; + const t = setTimeout(() => { + liveFirewallLabel = ''; + liveFirewallAt = 0; + }, 7000); + return () => clearTimeout(t); + }); + onMount(() => { loadGraph(); }); @@ -359,6 +380,28 @@ chrome='none' leaves only loading/error (host page owns the chrome). --> {#if showHud}
+ + {#if live && liveFirewallVisible} +
+
+ ⬤ threat quarantined +
+
+ {liveFirewallLabel} +
+
+ memory held in review · Memory PR opened +
+
+ {/if} +