vestige/apps/dashboard/build/_app/immutable/nodes/8.CJVG2CGC.js
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

4 lines
6.4 KiB
JavaScript

import"../chunks/Bzak7iHL.js";import{o as qe}from"../chunks/DeTA_5mp.js";import{p as Be,s as b,c as Qe,t as E,g as e,a as Ye,d as t,e as s,h as u,r as a}from"../chunks/nyjtQ1Ok.js";import{d as ze,a as p,s as v}from"../chunks/C4L78yoI.js";import{i as ce}from"../chunks/B17metm1.js";import{e as Z,i as ue}from"../chunks/BilMa3tw.js";import{a as _,f as g}from"../chunks/B0IenmM-.js";import{r as xe}from"../chunks/BBOOwRwQ.js";import{s as Ge}from"../chunks/BgOFZ9jq.js";import{s as _e}from"../chunks/D2QmVWrb.js";import{b as fe}from"../chunks/BOVu8he9.js";import{b as He}from"../chunks/J2LZW-kP.js";import{a as f}from"../chunks/BcuCGYSa.js";import{N as Ie}from"../chunks/BNytumrp.js";var Je=g('<div class="h-24 glass-subtle rounded-xl animate-pulse"></div>'),Ke=g('<div class="grid gap-3"></div>'),Ue=g('<span class="text-xs px-1.5 py-0.5 bg-white/[0.04] rounded text-muted"> </span>'),Ve=g('<div class="mt-4 pt-4 border-t border-synapse/10 space-y-3"><p class="text-sm text-text whitespace-pre-wrap"> </p> <div class="grid grid-cols-3 gap-3 text-xs text-dim"><div> </div> <div> </div> <div> </div></div> <div class="flex gap-2"><span role="button" tabindex="0" class="px-3 py-1.5 bg-recall/20 text-recall text-xs rounded-lg hover:bg-recall/30 cursor-pointer select-none">Promote</span> <span role="button" tabindex="0" class="px-3 py-1.5 bg-decay/20 text-decay text-xs rounded-lg hover:bg-decay/30 cursor-pointer select-none">Demote</span> <span role="button" tabindex="0" class="px-3 py-1.5 bg-decay/10 text-decay/60 text-xs rounded-lg hover:bg-decay/20 ml-auto cursor-pointer select-none">Delete</span></div></div>'),We=g('<button><div class="flex items-start justify-between gap-4"><div class="flex-1 min-w-0"><div class="flex items-center gap-2 mb-2"><span class="w-2 h-2 rounded-full"></span> <span class="text-xs text-dim"> </span> <!></div> <p class="text-sm text-text leading-relaxed line-clamp-2"> </p></div> <div class="flex flex-col items-end gap-1 flex-shrink-0"><div class="w-12 h-1.5 bg-deep rounded-full overflow-hidden"><div class="h-full rounded-full"></div></div> <span class="text-xs text-muted"> </span></div></div> <!></button>'),Xe=g('<div class="grid gap-3"></div>'),Ze=g(`<div class="p-6 max-w-6xl mx-auto space-y-6"><div class="flex items-center justify-between"><h1 class="text-xl text-bright font-semibold">Memories</h1> <span class="text-dim text-sm"> </span></div> <div class="flex gap-3 flex-wrap"><input type="text" placeholder="Search memories..." class="flex-1 min-w-64 px-4 py-2.5 bg-white/[0.03] border border-synapse/10 rounded-xl text-text text-sm
placeholder:text-muted focus:outline-none focus:border-synapse/40 focus:ring-1 focus:ring-synapse/20 transition backdrop-blur-sm"/> <select class="px-3 py-2.5 bg-white/[0.03] border border-synapse/10 rounded-xl text-dim text-sm focus:outline-none backdrop-blur-sm"><option>All types</option><option>Fact</option><option>Concept</option><option>Event</option><option>Person</option><option>Place</option><option>Note</option><option>Pattern</option><option>Decision</option></select> <div class="flex items-center gap-2 text-xs text-dim"><span>Min retention:</span> <input type="range" min="0" max="1" step="0.1" class="w-24 accent-synapse"/> <span> </span></div></div> <!></div>`);function xt(ge,me){Be(me,!0);let k=b(Qe([])),P=b(""),S=b(""),be="",h=b(0),F=b(!0),T=b(null),ee;qe(()=>m());async function m(){u(F,!0);try{const i={};e(P)&&(i.q=e(P)),e(S)&&(i.node_type=e(S)),e(h)>0&&(i.min_retention=String(e(h)));const c=await f.memories.list(i);u(k,c.memories,!0)}catch{u(k,[],!0)}finally{u(F,!1)}}function he(){clearTimeout(ee),ee=setTimeout(m,300)}function ye(i){return i>.7?"#10b981":i>.4?"#f59e0b":"#ef4444"}var M=Ze(),A=s(M),te=t(s(A),2),we=s(te);a(te),a(A);var C=t(A,2),$=s(C);xe($);var y=t($,2),N=s(y);N.value=N.__value="";var O=t(N);O.value=O.__value="fact";var R=t(O);R.value=R.__value="concept";var j=t(R);j.value=j.__value="event";var L=t(j);L.value=L.__value="person";var q=t(L);q.value=q.__value="place";var B=t(q);B.value=B.__value="note";var Q=t(B);Q.value=Q.__value="pattern";var ae=t(Q);ae.value=ae.__value="decision",a(y);var se=t(y,2),D=t(s(se),2);xe(D);var ie=t(D,2),ke=s(ie);a(ie),a(se),a(C);var Pe=t(C,2);{var Se=i=>{var c=Ke();Z(c,20,()=>Array(8),ue,(w,o)=>{var x=Je();_(w,x)}),a(c),_(i,c)},Te=i=>{var c=Xe();Z(c,21,()=>e(k),w=>w.id,(w,o)=>{var x=We(),Y=s(x),z=s(Y),G=s(z),oe=s(G),H=t(oe,2),$e=s(H,!0);a(H);var De=t(H,2);Z(De,17,()=>e(o).tags.slice(0,3),ue,(n,l)=>{var d=Ue(),J=s(d,!0);a(d),E(()=>v(J,e(l))),_(n,d)}),a(G);var re=t(G,2),Ee=s(re,!0);a(re),a(z);var ne=t(z,2),I=s(ne),Fe=s(I);a(I);var le=t(I,2),Me=s(le);a(le),a(ne),a(Y);var Ae=t(Y,2);{var Ce=n=>{var l=Ve(),d=s(l),J=s(d,!0);a(d);var K=t(d,2),U=s(K),Ne=s(U);a(U);var V=t(U,2),Oe=s(V);a(V);var de=t(V,2),Re=s(de);a(de),a(K);var pe=t(K,2),W=s(pe),X=t(W,2),ve=t(X,2);a(pe),a(l),E((r,je,Le)=>{v(J,e(o).content),v(Ne,`Storage: ${r??""}%`),v(Oe,`Retrieval: ${je??""}%`),v(Re,`Created: ${Le??""}`)},[()=>(e(o).storageStrength*100).toFixed(1),()=>(e(o).retrievalStrength*100).toFixed(1),()=>new Date(e(o).createdAt).toLocaleDateString()]),p("click",W,r=>{r.stopPropagation(),f.memories.promote(e(o).id)}),p("keydown",W,r=>{r.key==="Enter"&&(r.stopPropagation(),f.memories.promote(e(o).id))}),p("click",X,r=>{r.stopPropagation(),f.memories.demote(e(o).id)}),p("keydown",X,r=>{r.key==="Enter"&&(r.stopPropagation(),f.memories.demote(e(o).id))}),p("click",ve,async r=>{r.stopPropagation(),await f.memories.delete(e(o).id),m()}),p("keydown",ve,async r=>{r.key==="Enter"&&(r.stopPropagation(),await f.memories.delete(e(o).id),m())}),_(n,l)};ce(Ae,n=>{var l;((l=e(T))==null?void 0:l.id)===e(o).id&&n(Ce)})}a(x),E((n,l)=>{var d;Ge(x,1,`text-left p-4 glass-subtle rounded-xl hover:bg-white/[0.04]
transition-all duration-200 group
${((d=e(T))==null?void 0:d.id)===e(o).id?"!border-synapse/40 glow-synapse":""}`),_e(oe,`background: ${(Ie[e(o).nodeType]||"#8B95A5")??""}`),v($e,e(o).nodeType),v(Ee,e(o).content),_e(Fe,`width: ${e(o).retentionStrength*100}%; background: ${n??""}`),v(Me,`${l??""}%`)},[()=>ye(e(o).retentionStrength),()=>(e(o).retentionStrength*100).toFixed(0)]),p("click",x,()=>{var n;return u(T,((n=e(T))==null?void 0:n.id)===e(o).id?null:e(o),!0)}),_(w,x)}),a(c),_(i,c)};ce(Pe,i=>{e(F)?i(Se):i(Te,!1)})}a(M),E(i=>{v(we,`${e(k).length??""} results`),v(ke,`${i??""}%`)},[()=>(e(h)*100).toFixed(0)]),p("input",$,he),fe($,()=>e(P),i=>u(P,i)),p("change",y,m),He(y,()=>e(S),i=>u(S,i)),p("change",D,m),fe(D,()=>e(h),i=>u(h,i)),_(ge,M),Ye()}ze(["input","change","click","keydown"]);export{xt as component};