Commit graph

11 commits

Author SHA1 Message Date
Sam Valladares
8fe8bb2f39 test(v2.3): full e2e + integration coverage for Pulse + Birth Ritual
Post-ship verification pass — five parallel write-agents produced 229 new
tests across vitest units, vitest integration, and Playwright browser e2e.
Net suite: 361 vitest pass (up from 251, +110) and 9/9 Playwright pass on
back-to-back runs.

**toast.test.ts (NEW, 661 lines, 42 tests)**
  Silent-lobotomy batch walk proven (multi-event tick processes ALL, not
  just newest, oldest-first ordering preserved). Hover-panic pause/resume
  with remaining-ms math. All 9 event type translations asserted, all 11
  noise types asserted silent. ConnectionDiscovered 1500ms throttle.
  MAX_VISIBLE=4 eviction. clear() tears down all timers. fireDemoSequence
  staggers 4 toasts at 800ms intervals. vi.useFakeTimers + vi.mock of
  eventFeed; vi.resetModules in beforeEach for module-singleton isolation.

**websocket.test.ts (NEW, 247 lines, 30 tests)**
  injectEvent adds to front, respects MAX_EVENTS=200 with FIFO eviction,
  triggers eventFeed emissions. All 6 derived stores (isConnected,
  heartbeat, memoryCount, avgRetention, suppressedCount, uptimeSeconds)
  verified — defaults, post-heartbeat values, clearEvents preserves
  lastHeartbeat. 13 formatUptime boundary cases (0/59/60/3599/3600/
  86399/86400 seconds + negative / NaN / ±Infinity).

**effects.test.ts (EXTENDED, +501 lines, +21 tests, 51 total)**
  createBirthOrb full lifecycle — sprite count (halo + core), cosmic
  center via camera.quaternion, gestation phase (position lock, opacity
  rise, scale easing, color tint), flight Bezier arc above linear
  midpoint at t=0.5, dynamic mid-flight target redirect. onArrive fires
  exactly once at frame 139. Post-arrival fade + disposal cleans scene
  children. Sanhedrin Shatter: target goes undefined mid-flight →
  onArrive NEVER called, implosion spawned, halo blood-red, eventual
  cleanup. dispose() cleans active orbs. Multiple simultaneous orbs.
  Custom gestation/flight frame opts honored. Zero-alloc invariant
  smoke test (6 orbs × 150 frames, no leaks).

**nodes.test.ts (EXTENDED, +197 lines, +10 tests, 42 total)**
  addNode({isBirthRitual:true}) hides mesh/glow/label immediately,
  stamps birthRitualPending sentinel with correct totalFrames +
  targetScale, does NOT enqueue materialization. igniteNode flips
  visibility + enqueues materialization. Idempotent — second call
  no-op. Non-ritual nodes unaffected. Unknown id is safe no-op.
  Position stored in positions map while invisible (force sim still
  sees it). removeNode + late igniteNode is safe.

**events.test.ts (EXTENDED, +268 lines, +7 tests, 55 total)**
  MemoryCreated → mesh hidden immediately, 2 birth-orb sprites added,
  ZERO RingGeometry meshes and ZERO Points particles at spawn. Full
  ritual drive → onArrive fires, node visible + materializing, sentinel
  cleared. Newton's Cradle: target mesh scale exactly 0.001 * 1.8 right
  after arrival. Dual shockwave: exactly 2 Ring meshes added. Re-read
  live position on arrival — force-sim motion during ritual → burst
  lands at the NEW position. Sanhedrin abort path → rainbow burst,
  shockwave, ripple wave are NEVER called (vi.spyOn).

**three-mock.ts (EXTENDED)**
  Added Color.setRGB — production Three.js has it, the Sanhedrin-
  Shatter path in effects.ts uses it. Two write-agents independently
  monkey-patched the mock inline; consolidated as a 5-line mock
  addition so tests stay clean.

**e2e/pulse-toast.spec.ts (NEW, 235 lines, 6 Playwright tests)**
  Navigate /dashboard/settings → click Preview Pulse → assert first
  toast appears within 500ms → assert >= 2 toasts visible at peak.
  Click-to-dismiss removes clicked toast (matched by aria-label).
  Hover survives >8s past the 5.5s dwell. Keyboard Enter dismisses
  focused toast. CSS animation-play-state:paused on .toast-progress-
  fill while hovered, running on mouseleave. Screenshots attached to
  HTML report. Zero backend dependency (fireDemoSequence is purely
  client-side).

**e2e/birth-ritual.spec.ts (NEW, 199 lines, 3 Playwright tests)**
  Canvas mounts on /dashboard/graph (gracefully test.fixme if MCP
  backend absent). Settings button injection + SPA route to /graph
  → screenshot timeline at t=0/500/1200/2000/2400/3000ms attached
  to HTML report. pageerror + console-error listeners catch any
  crash (would re-surface FATAL 6 if reintroduced). Three back-to-
  back births — no errors, canvas still dispatches clicks.

Run commands:
  cd apps/dashboard && npm test           # 361/361 pass, ~600ms
  cd apps/dashboard && npx playwright test # 9/9 pass, ~25s

Typecheck: 0 errors, 0 warnings. Build: clean adapter-static.
2026-04-20 18:14:50 -05:00
Sam Valladares
ec614fed85 fix(v2.3): 5 FATAL bugs + 4 god-tier upgrades from post-ship audit
Post-ship audit surfaced 6 FATALs and 4 upgrades. Shipping 5 of the 6 +
all 4 upgrades. FATAL 4 (VRAM hemorrhage from un-pooled label canvases
in createTextSprite) is pre-existing, not from this session, and scoped
separately for a proper texture-pool refactor.

**FATAL 1 — Toast Silent Lobotomy** (stores/toast.ts)
Subscriber tracked events[0] only. When Svelte batched multiple events
in one update tick (swarm firing DreamCompleted + ConnectionDiscovered
within the same millisecond), every event but the newest got silently
dropped. Fixed to walk from index 0 until hitting lastSeen — same
pattern as Graph3D.processEvents. Processes oldest-first to preserve
narrative order.

**FATAL 2 — Premature Birth** (graph/nodes.ts + graph/events.ts)
Orb flight is 138 frames; materialization was 30 frames. Node popped
fully grown ~100 frames before orb arrived — cheap UI glitch instead
of a biological birth. Added `addNode(..., { isBirthRitual: true })`
option that reserves the physics slot but hides mesh/glow/label and
skips the materializing queue. New `igniteNode(id)` flips visibility
and enqueues materialization. events.ts onArrive now calls igniteNode
at the exact docking moment, so the elastic spring-up peaks on impact.

**FATAL 3 — 120Hz ProMotion Time-Bomb** (components/Graph3D.svelte)
All physics + effect counters are frame-based. On a 120Hz display every
ritual ran at 2x speed. Added a `lastTime`-based governor in animate()
that early-returns if dt < 16ms, clamping effective rate to ~60fps.
`- (dt % 16)` carry avoids long-term drift. Zero API changes; tonight's
fast fix until physics is rewritten to use dt.

**FATAL 5 — Bezier GC Panic** (graph/effects.ts birth-orb update)
Flight phase allocated a new Vector3 (control point) and a new
QuadraticBezierCurve3 every frame per orb. With 3 orbs in flight that's
360 objects/sec for the GC to collect. Rewrote as inline algebraic
evaluation — zero allocations per frame, identical curve.

**FATAL 6 — Phantom Shockwave** (graph/events.ts)
A 166ms setTimeout fired the 2nd shockwave. If the user navigated
away during that window the scene was disposed, the timer still
fired, and .add() on a dead scene threw unhandled rejection. Dropped
the setTimeout entirely; both shockwaves fire immediately in onArrive
with different scales/colors for the same layered-crash feel.

**UPGRADE 1 — Sanhedrin Shatter** (graph/effects.ts birth-orb update)
If getTargetPos() returns undefined AFTER gestation (target node was
deleted mid-ritual — Stop hook sniping a hallucination), the orb
turns blood-red, triggers a violent implosion in place, and skips
the arrival cascade. Cognitive immune system made visible.

**UPGRADE 2 — Newton's Cradle** (graph/events.ts onArrive)
On docking the target mesh's scale gets bumped 1.8×, so the elastic
materialization + force-sim springs physically recoil instead of the
orb landing silently. The graph flinches when an idea is born into it.

**UPGRADE 3 — Hover Panic** (stores/toast.ts + InsightToast.svelte)
Paused dwell timer on mouseenter/focus, resume on mouseleave/blur.
Stored remaining ms at pause so resume schedules a correctly-sized
timer. CSS pairs via `animation-play-state: paused` on the progress
bar. A toast the user is reading no longer dismisses mid-sentence.

**UPGRADE 4 — Event Horizon Guard** (components/Graph3D.svelte)
If >MAX_EVENTS (200) events arrive in one tick, lastProcessedEvent
falls off the end of the array and the walk consumes ALL 200 entries
as "fresh" — GPU meltdown from 200 simultaneous births. Detect the
overflow and drop the batch with a console.warn, advancing the
high-water mark so next frame is normal.

Build + test:
- npm run check: 0 errors, 0 warnings
- npm test: 251/251 pass
- npm run build: clean static build
2026-04-20 16:33:25 -05:00
Sam Valladares
f40aa2e086 feat(v2.3-terrarium): Memory Birth Ritual + event pipeline fix
v2.3 "Terrarium" headline feature. When a MemoryCreated event arrives, a
glowing orb materialises in the cosmic center (camera-relative z=-40),
gestates for ~800ms growing from a tiny spark into a full orb, then arcs
along a dynamic quadratic Bezier curve to the live position of the real
node, and on arrival hands off to the existing RainbowBurst + Shockwave +
RippleWave cascade. The target position is re-resolved every frame so
the force simulation can move the destination during flight without the
orb losing its mark.

**New primitive — EffectManager.createBirthOrb()** (effects.ts):
  Accepts a camera, a color, a live target-position getter, and an
  arrival callback. Owns a sprite pair (outer halo + inner bright core),
  both depthTest:false with renderOrder 999/1000 so the orb is always
  visible through the starfield and the graph.
  - Gestation phase: easeOutCubic growth + sinusoidal pulse, halo tints
    from neutral to event color as the ritual charges.
  - Flight phase: QuadraticBezierCurve3 with control point at midpoint
    raised on Y by 30 + 15% of orb-to-target distance (shooting-star
    arc). Sampled with easeInOutQuad. Orb shrinks ~35% approaching target.
  - Arrival: fires onArrive callback once, then fades out over 8 frames
    while expanding slightly (energy dispersal).
  - Caller's onArrive triggers the burst cascade at arrivePos (NOT the
    original spawnPos — the force sim may have moved the target during
    the ritual, so we re-read nodeManager.positions on arrival).
  - Dispose path integrated with existing EffectManager.dispose().

**Event pipeline fix — Graph3D.processEvents()**:
  Previously tracked `processedEventCount` assuming APPEND order, but
  websocket.ts PREPENDS new events (index 0) and caps the array at
  MAX_EVENTS. Result: only the first MemoryCreated event after page
  load fired correctly; subsequent ones reprocessed the oldest entry.
  Fixed to walk from index 0 until hitting the last-processed event
  by reference identity — correct regardless of array direction or
  eviction pressure. Events are then processed oldest-first so causes
  precede effects. Found while wiring the v2.3 demo button; would have
  manifested as "first orb only" in production.

**Demo trigger** (Settings -> Birth Ritual Preview):
  Button that calls websocket.injectEvent() with a synthetic
  MemoryCreated event, cycling through node types (fact / concept /
  pattern / decision / person / place) to showcase the type-color
  mapping. Downstream consumers can't distinguish synthetic from real,
  so this drives the full ritual end-to-end. Intended for demo clip
  recording for the Wednesday launch.

**Test coverage:**
  - events.test.ts now tests the v2.3 birth ritual path: spawns 2+
    sprites in the scene immediately, and fires the full arrival
    cascade after driving the effects.update() loop past the ritual
    duration.
  - three-mock.ts extended with Vector3.addVectors, Vector3.applyQuaternion,
    Color.multiplyScalar, Quaternion, QuadraticBezierCurve3, Texture,
    and Object3D.quaternion/renderOrder so production code runs unaltered
    in tests.

Build + typecheck:
- npm run check: 0 errors, 0 warnings across 583 files
- npm test: 251/251 pass (net +0 from v2.2)
- npm run build: clean adapter-static output

The Sanhedrin Shatter (anti-birth ritual for hallucination veto) needs
server-side event plumbing and is deferred. Ship this as the Wednesday
visual mic-drop.
2026-04-20 12:47:37 -05:00
Sam Valladares
30d92b5371 feat(graph): redesign node labels as dark glass pills
Some checks are pending
CI / Test (macos-latest) (push) Waiting to run
CI / Test (ubuntu-latest) (push) Waiting to run
CI / Release Build (aarch64-apple-darwin) (push) Blocked by required conditions
CI / Release Build (x86_64-unknown-linux-gnu) (push) Blocked by required conditions
Test Suite / Unit Tests (push) Waiting to run
Test Suite / MCP E2E Tests (push) Waiting to run
Test Suite / User Journey Tests (push) Blocked by required conditions
Test Suite / Dashboard Build (push) Waiting to run
Test Suite / Code Coverage (push) Waiting to run
Labels previously rendered as near-white text (#e2e8f0) on a transparent
canvas. UnrealBloomPass (threshold 0.2) amplified every bright pixel
into a huge white halo that made labels unreadable at normal camera
distances — reported by Sam 2026-04-19 with a screenshot of the LoRA
training label blown out into a luminous blob.

New design:

- Dark rounded pill (rgba(10,16,28,0.82)) sits below the text and
  hugs its measured width. That keeps the pill background well below
  bloom threshold so the halo can't spread past the label footprint.
- Text dimmed to mid-luminance slate (#94a3b8). Still legible at the
  standard camera distance but dim enough that bloom only adds a soft
  glow instead of a blast.
- Font trimmed to 22px / weight 600 (was bold 28px); sprite scale
  tightened from 12×1.5 to 9×1.2 so labels don't visually out-compete
  the node spheres they annotate.
- Hairline slate stroke (18% alpha) on the pill for definition when
  the camera gets close.

The canvas mock in the vitest setup grew beginPath / closePath /
moveTo / lineTo / quadraticCurveTo / arc / fill / stroke / strokeText
stubs so createTextSprite can exercise the full rounded-rect path in
unit tests without a real DOM. All 251 tests stay green.
2026-04-19 21:52:14 -05:00
Sam Valladares
d7f0fe03e0 test(graph): ruthless coverage for v2.0.8 memory-state colour mode
80 new vitest cases exhaustively exercising the v2.0.8 colour-mode
additions, taking total dashboard coverage to 251 tests.

Pure-function correctness:
- getMemoryState: 12 retention boundaries including exact thresholds,
  NaN, ±Infinity, negative, and >1 values + determinism across 10k
  random samples.
- getNodeColor: per-node-type mapping in type mode (all 8 types),
  per-bucket mapping in state mode, unknown-type fallback, and the
  invariants that type mode ignores retention + state mode ignores type.
- MEMORY_STATE_COLORS: valid 6-digit hex, all four buckets distinct,
  zero overlap with NODE_TYPE_COLORS.
- MEMORY_STATE_DESCRIPTIONS: threshold parentheticals match getMemoryState
  bucket boundaries (70 / 40 / 10), all four lines distinct.

NodeManager state machine:
- default mode 'type', field writable pre-createNodes.
- setColorMode is idempotent (early return verified via copy() spy counts).
- setColorMode calls color.copy + emissive.copy + glow.color.copy exactly
  once per node per transition, never replaces mesh / glow / material
  references, preserves userData.{nodeId,type,retention}.
- rapid 5× type <-> state toggle preserves all three maps.
- addNode during state mode inherits the mode; subsequent switch to
  type correctly retints the live-added node.
- suppressed-node interaction: setColorMode updates color + emissive but
  never touches opacity or emissiveIntensity (v2.0.5 SIF channel stays
  isolated from v2.0.8 colour channel).
- defensive paths: missing glow, missing userData.retention, missing
  userData.type — all degrade to sane defaults without throwing.

Also refreshes the embedded dashboard build so the Rust binary picks up
the new SvelteKit chunks with the memory-state-colors feature baked in.
2026-04-19 21:12:06 -05:00
Sam Valladares
4c2016596c feat(graph): FSRS memory-state colour mode + legend overlay
Closes Agent 1's audit gap #4: FSRS memory state (Active / Dormant /
Silent / Unavailable) was computed server-side per query but never
rendered in the 3D graph. Spheres always tinted by node type.

The new colour mode adds a second channel that users can toggle
between at runtime — Type (default, existing behaviour) and State
(new). The toggle is a radio-pair pill in the graph page's top-right
control bar next to the node-count selector + Dream button.

Buckets + palette:
- Active    ≥ 70%  emerald #10b981  easily retrievable
- Dormant  40-70%  amber   #f59e0b  retrievable with effort
- Silent   10-40%  violet  #8b5cf6  difficult, needs cues
- Unavail.  < 10%  slate   #6b7280  needs reinforcement

Thresholds match `execute_system_status` at the backend so the graph
colour bands line up exactly with what the Stats page reports in its
stateDistribution block. Using retention as the proxy for the full
accessibility formula (retention × 0.5 + retrieval × 0.3 + storage ×
0.2) is an approximation — retention is the dominant 0.5 weight and
it is the only FSRS channel the current GraphNode DTO carries. Swap
to the full formula in a future release if the DTO grows.

Implementation:
- `apps/dashboard/src/lib/graph/nodes.ts` — new `MemoryState` type,
  `getMemoryState(retention)`, `MEMORY_STATE_COLORS`,
  `MEMORY_STATE_DESCRIPTIONS`, `ColorMode`, `getNodeColor(node, mode)`.
- `NodeManager.colorMode` field (default `'type'`). `createNodeMeshes`
  now calls `getNodeColor(node, this.colorMode)` so newly-added nodes
  during the session follow the toggled mode.
- New `NodeManager.setColorMode(mode)` mutates every live mesh's
  material + glow sprite colour in place. Idempotent; cheap. Does NOT
  touch opacity/emissive-intensity so the v2.0.5 suppression dimming
  layer keeps working unchanged.
- New `MemoryStateLegend.svelte` floating overlay in the bottom-right
  when state mode is active (hidden in type mode so the legend doesn't
  compete with the node-type palette).
- `Graph3D.svelte` accepts a new `colorMode` prop (default `'type'`)
  and runs a `$effect` that calls `setColorMode` on every toggle.
- Dashboard rebuild picks up the new component + wiring.

Tests: 171 vitest, svelte-check 581 files / 0 errors. No backend
changes; this is pure dashboard code.
2026-04-19 20:45:08 -05:00
Sam Valladares
cc0e70acc8 feat(dashboard): wire 6 graph event handlers (suppress + core cognitive)
Before this commit, six live WebSocket events fired against a silent 3D
graph. v2.0.5 shipped the `suppress` tool but the graph did not react to
MemorySuppressed, MemoryUnsuppressed, or Rac1CascadeSwept. Three more
core events — Connected, ConsolidationStarted, ImportanceScored — have
been silent on the graph since v2.0.0 despite appearing in the live
feed, which made the dashboard feel broken during real cognitive work.

Handlers added, all driven by the existing EffectManager:

- MemorySuppressed: violet implosion + compounding pulse scaled by
  suppression_count (Anderson 2025 SIF visualised).
- MemoryUnsuppressed: rainbow burst + green pulse to mark reversal
  within the 24h labile window.
- Rac1CascadeSwept: violet wave across a random neighbour sample
  (event carries counts, not IDs, until v2.1).
- Connected: gentle cyan ripple from the first node on WS handshake.
- ConsolidationStarted: subtle amber pulses across a 20-node sample
  while FSRS-6 decay runs (colour matches feed entry).
- ImportanceScored: magenta pulse on the scored node with intensity
  proportional to composite_score (novelty/arousal/reward/attention).
2026-04-18 18:33:31 -05:00
Sam Valladares
8178beb961 feat(v2.0.5): Intentional Amnesia — active forgetting via top-down inhibitory control
First AI memory system to model forgetting as a neuroscience-grounded
PROCESS rather than passive decay. Adds the `suppress` MCP tool (#24),
Rac1 cascade worker, migration V10, and dashboard forgetting indicators.

Based on:
- Anderson, Hanslmayr & Quaegebeur (2025), Nat Rev Neurosci — right
  lateral PFC as the domain-general inhibitory controller; SIF
  compounds with each stopping attempt.
- Cervantes-Sandoval et al. (2020), Front Cell Neurosci PMC7477079 —
  Rac1 GTPase as the active synaptic destabilization mechanism.

What's new:
* `suppress` MCP tool — each call compounds `suppression_count` and
  subtracts a `0.15 × count` penalty (saturating at 80%) from
  retrieval scores during hybrid search. Distinct from delete
  (removes) and demote (one-shot).
* Rac1 cascade worker — background sweep piggybacks the 6h
  consolidation loop, walks `memory_connections` edges from
  recently-suppressed seeds, applies attenuated FSRS decay to
  co-activated neighbors. You don't just forget Jake — you fade
  the café, the roommate, the birthday.
* 24h labile window — reversible via `suppress({id, reverse: true})`
  within 24 hours. Matches Nader reconsolidation semantics.
* Migration V10 — additive-only (`suppression_count`, `suppressed_at`
  + partial indices). All v2.0.x DBs upgrade seamlessly on first launch.
* Dashboard: `ForgettingIndicator.svelte` pulses when suppressions
  are active. 3D graph nodes dim to 20% opacity when suppressed.
  New WebSocket events: `MemorySuppressed`, `MemoryUnsuppressed`,
  `Rac1CascadeSwept`. Heartbeat carries `suppressed_count`.
* Search pipeline: SIF penalty inserted into the accessibility stage
  so it stacks on top of passive FSRS decay.
* Tool count bumped 23 → 24. Cognitive modules 29 → 30.

Memories persist — they are INHIBITED, not erased. `memory.get(id)`
returns full content through any number of suppressions. The 24h
labile window is a grace period for regret.

Also fixes issue #31 (dashboard graph view buggy) as a companion UI
bug discovered during the v2.0.5 audit cycle:

* Root cause: node glow `SpriteMaterial` had no `map`, so
  `THREE.Sprite` rendered as a solid-coloured 1×1 plane. Additive
  blending + `UnrealBloomPass(0.8, 0.4, 0.85)` amplified the square
  edges into hard-edged glowing cubes.
* Fix: shared 128×128 radial-gradient `CanvasTexture` singleton used
  as the sprite map. Retuned bloom to `(0.55, 0.6, 0.2)`. Halved fog
  density (0.008 → 0.0035). Edges bumped from dark navy `0x4a4a7a`
  to brand violet `0x8b5cf6` with higher opacity. Added explicit
  `scene.background` and a 2000-point starfield for depth.
* 21 regression tests added in `ui-fixes.test.ts` locking every
  invariant in (shared texture singleton, depthWrite:false, scale
  ×6, bloom magic numbers via source regex, starfield presence).

Tests: 1,284 Rust (+47) + 171 Vitest (+21) = 1,455 total, 0 failed
Clippy: clean across all targets, zero warnings
Release binary: 22.6MB, `cargo build --release -p vestige-mcp` green
Versions: workspace aligned at 2.0.5 across all 6 crates/packages

Closes #31
2026-04-14 17:30:30 -05:00
Sam Valladares
5b1127d630 fix: remove vestige-agent from workspace (not shipped), improve reasoning chain output
- Removed vestige-agent and vestige-agent-py from workspace members
  (ARC-AGI-3 code, not part of Vestige release — caused CI failure)
- Improved deep_reference reasoning chain: fuller output with arrows on
  supersession reasoning, longer primary finding preview, fallback message
  when no relations found, boosted relation detection for search results
  with high combined_score

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:06:24 -05:00
Sam Valladares
9bdcc69ce3 feat: live memory materialization — nodes spawn in 3D graph in real-time
When memories are created, promoted, deleted, or dreamed via MCP tools,
the 3D graph now shows spectacular live animations:

- Rainbow particle burst + elastic scale-up on MemoryCreated
- Ripple wave cascading to nearby nodes
- Green pulse + node growth on MemoryPromoted
- Implosion + dissolution on MemoryDeleted
- Edge growth animation on ConnectionDiscovered
- Purple cascade on DreamStarted/DreamProgress/DreamCompleted
- FIFO eviction at 50 live nodes to guard performance

Also: graph center defaults to most-connected node, legacy HTML
redirects to SvelteKit dashboard, CSS height chain fix in layout.

Testing: 150 unit tests (vitest), 11 e2e tests (Playwright with
MCP Streamable HTTP client), 22 proof screenshots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:04:31 -06:00
Sam Valladares
d98cf6136a feat: dashboard v2.1 glassmorphism + graph decomposition + fix flaky macOS vector test
Dashboard v2.1 "Nuclear" upgrade:
- Dark glassmorphism UI system (4-tier glass utilities, ambient orbs, nav glow)
- Graph3D decomposed from 806-line monolith into 10 focused modules
- Custom GLSL shaders (nebula FBM background, chromatic aberration, film grain, vignette)
- Enhanced dream mode with smooth 2s lerped transitions and aurora cycling
- Cognitive pipeline visualizer (7-stage search cascade animation)
- Temporal playback slider (scrub through memory evolution over time)
- Bioluminescent color palette for node types and events

Fix flaky CI test on macOS:
- vector::tests::test_add_and_search used near-identical test vectors (additive phase shift)
- Changed to multiplicative frequency so each seed produces a distinct vector

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:24:10 -06:00