Commit graph

2 commits

Author SHA1 Message Date
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
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