Commit graph

250 commits

Author SHA1 Message Date
Sam Valladares
140b15f59f proof(blackbox): dream.patch proven live with a real dream run
Bounded follow-up (tight acceptance criteria, no scope expansion): flip the
dream.patch producer from "quiet because no dream ran" to a recorded live event.

The dream tool's `insights` array carries no per-item id, so the recorder
extracted zero proposals and dream.patch never fired even on a real dream.
Fix: derive a stable proposal id from each insight's REAL content (its
insight_type + the source memories it consolidated). The dream genuinely ran;
this just gives each real proposal a deterministic handle. Unit-tested against
the exact dream output shape.

Proven end to end (run_dream_proof, 6 memories consolidated):
- one dream.patch event: dream:RecurringPattern:5d941c7f+a41aca72+...
- SQLite + /api/traces/:runId: dream-trace.json (14 events, last is dream.patch)
- WebSocket: dream-websocket-events.jsonl (the dream.patch TraceEvent)
- dashboard: screenshots/dream-producers.png — the row flips to "fired this run"

PROOF.md updated: dream.patch moves from CAVEAT to REAL (still not live by
default — it fires only when a dream actually runs, and the UI says so).
sanhedrin.veto remains an honest CAVEAT (optional hook, off by default).

Gates: 957 lib tests pass, clippy -D warnings clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:51:46 -05:00
Sam Valladares
b89beeeb63 proof(blackbox): Proof Lock — full-spine test, honest UI states, proof pack
Make the receipt chain impossible to doubt. Freeze the claim surface, prove
every hop, and turn the two off-by-default producers into explicit UI states.

Frozen public claim: "Vestige records real MCP memory activity into a
replayable local trace, with receipts and reviewable risky writes." We do NOT
claim Sanhedrin vetoes or dream patches are live by default.

Regression — full-spine test (server.rs): one runId must cross, byte-identical,
MCP output -> SQLite trace -> WebSocket event -> API response shape ->
MCP resource. Fails if any hop drops or rewrites the id.

Honest UI states (Black Box "Event producers" panel):
- sanhedrin.veto -> "No veto producer connected (optional Sanhedrin hook, off
  by default)" instead of empty mystery.
- dream.patch -> "No dream run in this trace" unless a dream actually ran.
- contradiction.detected -> "no contradiction in this run" when none fired.

Quarantine review (not pre-write blocking): risky writes are committed then
suppressed — audit history preserved, retrieval influence suspended until
reviewed. Reworded the server notice + UI copy to say exactly that.

Receipts UI gap closed: ReceiptCard is now mounted on the Black Box page
(retrieved/suppressed/trust-floor, activation path, "Open receipt in Cinema").

Proof pack (blackbox-proof-2026-06-22/): status.json, trace.json (the
.vestige-trace.json export), receipt.json, memory_pr.json (promoted via
UI->API->SQLite), websocket-events.jsonl (live TraceEvent x6 + PR opened/
decided), screenshots (Black Box, Receipts, Memory PRs, Graph), and PROOF.md
with real/caveat/stub per feature.

Gates: 988 lib tests pass, clippy -D warnings clean, dashboard check + build
clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:41:02 -05:00
Sam Valladares
80c823a3ca feat(blackbox): Agent Black Box + Receipts + risk-gated Memory PRs
Watch the agent think. Watch memory change. Watch the receipt prove why.

Make Vestige the first memory server where you can replay an agent run,
audit every retrieval, and review changes to the agent's brain like code.

Phase 0 — the trace-correlation spine. One runId threads, unbroken, through
every layer: MCP tool output (runId + traceUri) -> SQLite agent_traces rows ->
WebSocket TraceEvent -> dashboard pulse -> /api/traces/:runId ->
vestige://trace/{runId} -> .vestige-trace.json export -> Cinema replay input.
Proven end to end by a real JSON-RPC round-trip integration test.

Core (vestige-core):
- trace/ module: MemoryTraceEvent (7 variants incl. contradiction.detected),
  Receipt, and classify_write — the pure, DB-free immune-system logic.
- Risk taxonomy: contradiction-vs-high-trust, supersede/forget/merge/protect,
  identity/preference/workflow/positioning, auth/security/money/legal,
  dream consolidation, decay resurrection, low-confidence batch, weak-provenance
  connector. Fast / Risk-Gated (default) / Paranoid modes.
- V18 migration: agent_traces, agent_runs, memory_receipts, memory_prs.
- trace_store.rs: CRUD following the established store idiom.

MCP (vestige-mcp):
- trace_recorder.rs: records mcp.call + downstream retrieve/suppress/write/
  contradiction/veto/dream events; builds + persists receipts; risk-gates
  writes into Memory PRs. Args are hashed, never stored raw.
- server.rs dispatch stamps runId/traceUri/receipt onto every tool result and
  routes risky writes to the PR queue; trace events broadcast over WebSocket.
- vestige://trace/{runId} resource; /api/traces, /api/receipts, /api/memory-prs.

Dashboard:
- Black Box tab: live spine header + Proof Mode, run picker, timeline scrubber,
  per-event detail, memory pulse, full event log, .vestige-trace.json export.
- Memory PRs tab: GitHub-style cognition diff, self-explaining risk signals,
  Promote/Merge/Supersede/Quarantine/Forget/Ask-Agent-Why, mode toggle.
- ReceiptCard with "Open receipt in Cinema" (deep-links graph; Cinema untouched).

Gates: 987 lib tests pass, clippy -D warnings clean, dashboard check + build
clean. Live proof in blackbox-proof-2026-06-22/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 17:06:35 -05:00
Sam Valladares
9e92a5999a fix(cinema): back-pressure the frame loop — kill parallax lag
The loop fired requestAnimationFrame immediately and never awaited render(); with
150k particles + compute + bloom a frame can exceed 16ms, so rAF callbacks queued
faster than the GPU could drain them and the camera/parallax visibly lagged behind
the cursor. Now AWAIT sb.render(dt) before scheduling the next frame → the loop is
capped to real GPU throughput, every frame reflects the latest pointer position,
no backlog. Also snappier active-steer damping (lam 3.5→9, ~110ms converge) so
input feels immediate; idle glide-home unchanged. renderFailures resets on success.

Plus docs/MEMORY_CINEMA.md — complete feature reference for the cinema engine.

Gate: svelte-check 0/0, 937 tests, verified live (parallax tracks cursor, no lag).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 15:12:28 -05:00
Sam Valladares
5e948320a9 fix(cinema): lift brightness so the 4 depth systems don't stack to black
near-fade × fog × DOF × seam-fade each multiply a <1 factor; together they were
crushing the figure dark. Raised the fog floor (0.18→0.45) and the color/emissive
glow bases so the stacked attenuation lands in a vivid range. Verified live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:39:07 -05:00
Sam Valladares
4e3542eecb feat(cinema): flythrough streaks + interactive parallax (immersion steps 5+6/6)
Step 5 — VELOCITY-STRETCH FLYTHROUGH: sandbox derives camera velocity per frame
(one Vector3, zero compute) and pushes view-space apparent velocity to the storm;
flythrough relaxes the camera clamp floor (lerp 30→6) so the camera plunges
inside the shell. Storm stretches each sprite along screen-space velocity via
rotationNode + scaleNode (clamped streak), separate output graph (no extra
positionView read). Defaults 0 → no-op until wired.

Step 6 — INTERACTIVE PARALLAX: pointer orbits / scroll + pinch zoom the camera
with frame-rate-independent damping, composed onto the director's base pose in
loop() (after director.update, before render); idle >2.5s eases back to 0 so it's
a toy when touched and a film when left alone. sandbox.render re-clamps so the
user can't break framing. Per-beat flythrough strength wired from shot.tension;
dream mode flies through at 0.6. Fully gated off under reduced-motion (no
listeners, flythrough 0).

The 4-feature immersion stack (infinite zoom + flythrough + parallax + DOF/fog)
now composes. Gate: svelte-check 0/0, 937 tests, build green, verified live (all
4 compose, no white-out, no recursion, parallax responds without breaking framing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:35:32 -05:00
Sam Valladares
4a238a4893 feat(cinema): INFINITE DROSTE ZOOM (immersion step 4/6) — the spine
The cloud now dives inward FOREVER, seamlessly. Two layers ride offset phases of
fract(uTime/T): the outer grows pow(λ, phase) toward the camera then snaps back
(invisible — inner@1/λ == outer@1); the inner (half-period offset) grows promoted
by λ to become the next outer shell, while a fresh inner spawns inside. λ=1.923
(=1/0.52 inner scale) makes the snap mathematically exact. A sin(phase·π) seam
cross-fade in rimFactor makes each layer fully transparent at its snap → ZERO pop.
Particle-space (not a camera dolly) so it can't clip or fight the camera clamp.
Rack-focus tracks the descent. uZoomOn gates it: Act II+ and dream mode dive;
beats 0/1 + reduced-motion stay still. Verified: seamless loop, no white-out, no
recursion, 937 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:27:21 -05:00
Sam Valladares
85dacfad2b feat(cinema): depth-of-field defocus (immersion step 3b/6)
Off-focus particles dim (read as bokeh defocus under the bloom) with a breathing
rack-focus. Folded into the single depthFade depth read — NOT sprite scaleNode,
which collapsed the sprites to invisible and collides with the upcoming streak.
Subtle (0.3) so it adds cinematic depth without darkening the figure.

Gate: svelte-check 0/0, 937 tests, verified live (depth grading reads, no recursion).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:20:37 -05:00
Sam Valladares
3b342da9ea feat(cinema): volumetric fog depth (immersion step 3a/6)
Distant particles dim toward the void with view depth (exp falloff) → real 3D
atmospheric recession, not a flat sprite cloud. Combined with the near-fade into
a SINGLE depthFade Fn — critical three@0.172 TSL constraint discovered: reading
positionView from a second Fn feeding the same material output triggers a cyclic
stack-overflow in the node type-resolver (getNodeType). One depth read, one Fn.

Gate: svelte-check 0/0, 937 tests, verified live (fog depth reads, no recursion).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 14:12:05 -05:00
Sam Valladares
dad74d5aeb feat(cinema): near-plane fade (immersion step 2/6)
Particles dissolve as they approach the camera (view-space -positionView.z,
smoothstep over [near, near+band]) so the upcoming flythrough never additive-pops
a sprite in your face. Folded into color + emissive so the bloom fades too.
Invisible at the default far camera. positionView confirmed working in the
SpriteNodeMaterial color node.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 13:58:14 -05:00
Sam Valladares
d9fb791af6 refactor(cinema): canonical sprite center (positionNode = instancePos)
SpriteNodeMaterial.setupPositionView already rebuilds the billboard quad from
positionGeometry — the prior .add(positionLocal) double-counted it (harmless at
0.1 size). Bare center is required for the upcoming velocity-stretch streak
(scaleNode/rotationNode will drive the quad). Verified renders identically.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 13:53:52 -05:00
Sam Valladares
12678596d5 feat(cinema): jarring inner/outer color clash — opposing palettes that fight
The nested 3D-within-3D figure now collides with its shell in OPPOSING color
universes, not a shared rainbow. Each layer is painted from a hard duotone:
the outer shell from one world (ice / acid / gold / mint / electric-blue), the
inner figure from its enemy (fire / blood / violet / crimson / gold). A new
uClash uniform cycles the pair every beat (and randomizes per dream figure), so
it's a fresh ice-vs-fire / acid-vs-blood collision each time — the kind of
contrast that stops a scroll.

To make the clash READ instead of washing white: inner glow floor dropped hard
(dense small-radius overlap was blowing to white and killing the color), inner
figure scaled up to 0.52 (spread → less overlap), the color blast capped at 0.6
mix so the duotone shows through even during a detonation, and Act II/III
ignition lowered 8.0→4.5 so beats no longer flash the clash to white.

Gate: svelte-check 0/0, 937/937 tests pass, build green, verified live (gold
shell + violet core clash reads clearly, no white-out, beats 0/1 calm).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 12:18:25 -05:00
Sam Valladares
4bdc5955f0 feat(cinema): impossible-geometry forms + 3D-within-3D nesting + demo capture
Three upgrades to Memory Cinema:

1. IMPOSSIBLE-GEOMETRY FORM PACK — replaced the stringy ribbon dream worlds with
   brand-new signature skins nobody ships as a living particle figure:
   - world 8 → Calabi–Yau quintic cross-section (6D string-theory manifold,
     Hanson 4D→3D projection; α rotates it through the 4th dimension)
   - world 9 → Boy's surface (Bryant–Kusner minimal immersion of RP²)
   - world 10 → Aizawa attractor shell (breathing strange-attractor skin)
   - world 11 → Gyroid↔Schwarz-D Bonnet morph (triply-periodic minimal surface)
   The (u,v) MANIFOLD GRID basis is the key fix: particles map over a tensor grid
   so neighbors share edges → reads as a sculpted SKIN, not spaghetti. Plus a
   facing-ratio Fresnel rim so forms read as lit solids. Inline complex-math +
   hyperbolics (sinh/cosh not in three@0.172). atan2→atan (deprecation).

2. 3D-WITHIN-3D NESTING — ~34% of particles form a SECOND, smaller, counter-
   rotating figure (a different world, ~45% scale, complementary hue) at the core
   of the outer shell. A figure inside a figure — fills the formerly-blank-bright
   center with intentional structure and depth.

3. DEMO-CAPTURE MODE — press H in the cinema overlay to hide all UI chrome
   (top bar + captions) for clean recording; a faint restore hint remains.
   Overlay z-index raised + body.cinema-open hides the graph page's stats pill so
   nothing bleeds through.

Gate: svelte-check 0/0, 937/937 tests pass, build green, verified live (Calabi–Yau
+ nested core render, forms cycle, no errors, beats 0/1 calm).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 11:15:37 -05:00
Sam Valladares
ecb518bae8 feat(cinema): endless dream mode — infinite generative figures after the tour
The 7-beat tour no longer freezes on the last figure. When it ends, Memory
Cinema drops into an infinite generative loop: every ~5.5s it morphs into a
fresh RANDOM procedural figure and detonates a color blast — each crazier than
the last.

Five new procedural worlds (7..11), parameterized by a per-figure uMorphSeed +
a uChaos ramp so the same index never looks the same twice:
  7 supershape (3D superformula)   8 torus knot (random p,q winding)
  9 warped lissajous lattice       10 helix storm
  11 quantum foam (curl-warped chaos — max wild)

storm.dreamBeat() picks a random world, reseeds it, ramps chaos, and fires a
moderate-ignition blast (kept below the tour's 8.0 so dense random figures don't
wash white). Surfaced via sandbox.dreamBeat(); MemoryCinema starts a dream timer
on director onComplete, shows "∞ Dreaming", and tears it down on close/replay.
Honors reduced-motion (no dream loop) and the render-fail fallback.

Gate: svelte-check 0/0, 937/937 tests pass, build green, verified live (reaches
dream mode, generates distinct figures — supershapes, torus knots — cycling
forever, no white-out, no errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 10:18:44 -05:00
Sam Valladares
2422f5be6c docs(claude): pin "Maximum Ambition, No Hedging" as Mandate #0
Standing default for all Vestige work, at the absolute top of CLAUDE.md so it
loads first every session: assume maximum ambition, scour before settling, no
hedging, show proof, protect what's flawless and detonate what isn't.

Origin: the overnight session that turned the dashboard + Memory Cinema into a
category-of-one particle journey. Make that depth the default, not the exception.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 04:22:55 -05:00
Sam Valladares
c00c633104 feat(cinema): the 7-world color-blast journey — each beat a unique universe
Memory Cinema is now a choreographed 7-act journey. One 150k-particle pool,
one compute kernel; a uWorld state machine select()s which home-target + forces
are live, and uBlend crossfades world→world over ~1s. The particles never swap
— only the forces on them — which IS the journey.

The seven worlds (beats map 1:1, beatIndex % 7):
  0 nebula mist (curl-noise flow)   1 orbital anchor (cross-product spin)
  2 strange attractor (Thomas)      3 detonation void (staggered shockwave)
  4 crystal lattice (voxel snap)    5 fluid galaxy (curl + tangential swirl)
  6 phyllotaxis bloom (Vogel sunflower, golden angle)

The signature COLOR BLAST: a long-lived uBlast envelope (~2.8s, decoupled from
the fast physics burst so the color OUTLIVES the shockwave) drives an outward
SPECTRAL DISPERSION wave — concentric rainbow rings expanding through the radius
over uBlastTime (real prism order, red lags / blue leads), with a warm blackbody
ember core underneath. Spectrum dominates so the detonation reads as RAINBOW,
not a white plasma flash.

Plus per-world cosine palettes (IQ) so each world is a distinct PLACE. All the
white-out guardrails preserved + extended: rim-gated blast, capped kelvin/gain,
emissive blast held below the color path. Beats 0/1 stay calm (low uBlast),
Acts II/III blaze.

Frontier techniques sourced from a parallel web-research + design workflow;
verified against the installed three@0.172 TSL build. Retires the old uShape
5-form gallery.

Gate: svelte-check 0/0, 937/937 tests pass, build green, verified live (7
distinct worlds, spectral blast, no white-out, calm opening).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 04:18:03 -05:00
Sam Valladares
618ec6aee3 feat(cinema): full-spectrum rim-glow storm — kill the white-out, morphing forms
Memory Cinema storm color/shape overhaul (the crown-jewel pillar):
- Fix the white-out root cause: emissiveNode was NEVER set, so the selective
  MRT bloom had no color to bloom and washed the frame white. Route the shared
  iridescent rainbow to BOTH colorNode and emissiveNode.
- Rim glow (fresnel-style): bright glowing edges, dim readable center — the
  shareable luminous-shell / hollow-torus look.
- Morphing geometry: the home target cycles sphere → torus → galaxy spiral →
  cube lattice → wave sheet, drifting continuously and snapping per beat.
- Hyper-saturated full-spectrum palette (per-particle phase + radial shells +
  spatial bands + time) so the whole rainbow is present at once.
- Spread the initial spawn across a wide hollow shell (was a tiny dense ball
  that boot-flashed white).
- Act/beat-aware brightness: beats 0/1 fade in soft, Act I held calm, Acts
  II/III blaze at full. No white-out regressions.

Gate: svelte-check 0/0, 937/937 tests pass (cinema auteur/pathfinder green),
verified live in browser.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 03:59:38 -05:00
Sam Valladares
1fbbecb0b3 feat(dashboard): alive overhaul — unique icons, dropdowns, motion on every page
Make the dashboard feel alive every second, with clear controls, for the
July 14 HN relaunch. Memory Cinema is left fully untouched (zero changes to
MemoryCinema.svelte / graph/cinema/*; its tests still pass).

Foundation (lifts every page):
- Icon.svelte: inline-SVG icon system, zero runtime dep. A UNIQUE semantic
  silhouette per nav item — kills the old duplicated Unicode glyphs (◎◈◉◷
  were each reused across multiple items). Wired into sidebar, mobile nav,
  command palette, logo.
- Dropdown.svelte: accessible, keyboard-nav, type-ahead, animated select
  replacement with color dots / badges. Replaces dead native <select>s.
- AnimatedNumber.svelte: rAF count-up/tween, reduced-motion safe.
- PageHeader.svelte: shared masthead (drawn route icon + aurora title).
- actions/reveal.ts + actions/interactions.ts: scroll-reveal, magnetic,
  tilt(+glare), spotlight — all no-op under reduced-motion.
- app.css "alive layer": @property animatable gradients, conic live-border,
  breathe/ping, shimmer skeletons, @starting-style entry, aurora text, lift.

Per-page: every route (graph non-cinema controls, reasoning, memories,
timeline, feed, explore, activation, dreams, schedule, importance,
duplicates, contradictions, patterns, intentions, stats, settings) now uses
PageHeader, real Icons, count-ups, staggered reveals, shimmer loaders,
spotlight cards, and warm empty states. Native selects and button-row
filters became clear Dropdowns where it improves clarity.

Gates: svelte-check 0 errors/0 warnings, 937/937 tests pass, build green,
verified live in the browser preview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 02:58:26 -05:00
Sam Valladares
bc81da46eb feat(cinema): explode -> pixelate -> reform storm (kill the swirls)
Per direction: keep the mind-blowing explosion + pixelation moments, ditch the
thin ribbon swirls. Complete physics rewrite:
- removed orbital/stream/Rössler modes (the swirls + the off-center drift source)
- each particle has a deterministic HOME on a volumetric shell around ORIGIN
  (centroid anchored — can never drift off-frame again)
- uBurst detonation cycle: every beat blows particles radially out (explosion),
  then a home-spring crystallizes them back (reform); contradictions detonate hardest
- PIXELATION: positions snap to a 3D grid that's fine when reformed, dissolved
  during the burst — the crystalline voxel look
- hard velocity + radius clamps so it can never fly off or blow up
937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:37:10 -05:00
Sam Valladares
0e5ce76274 feat(cinema): fill the frame + true full-spectrum color (no more white-out)
Storm was a small ring leaving the canvas empty, and the core blew to white.
- FILL: sandbox fitRadius margin 0.40 -> 0.82 so the storm fills most of the
  frame; particles now target their OWN radius across 0.12r..0.92r (filled
  volumetric ORB, not a thin ring).
- COLOR: brightness was x(ignition*2.4+0.6) = up to x19.8, which + additive
  blending across 150k sprites clipped every channel to white. Clamp the glow
  low (0.45 floor, ~1.15 ceil) so the RAINBOW shows as pure spectral color;
  smaller quads (0.18 -> 0.1) keep particles crisp instead of overlapping to
  mush; gentler bloom (strength 1.1->0.6, threshold 0->0.35) accents cores
  rather than washing the cloud. 937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:26:39 -05:00
Sam Valladares
782399adb1 fix(cinema): tighten storm framing so the bloom halo never clips
The rainbow storm looked next-dimensional but still clipped the edges — the
additive bloom halo extends each particle's glow well past its geometric radius,
so the visible cloud was bigger than the contain sphere.

- spawn radius 15 -> 8 (particles start inside the shell, no asymmetric inward yank)
- sandbox fitRadius margin 0.55 -> 0.40 (leaves room for the bloom halo)
- camera band tightened + pushed farther (30-44) so the contained cloud sits
  small + centered; director standoff clamped into that band in centerOnOrigin
  mode so the camera never fights the per-frame clamp (the off-center jump).

937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:18:53 -05:00
Sam Valladares
65c801bc2f feat(cinema): radial containment spring + INSANE iridescent rainbow storm
Fixes the runaway ring (screenshot showed an expanding ellipse clipping the
frame): orbital mode added tangential velocity with nothing pulling particles to
a target radius, so they spiraled outward. Now a two-sided RADIAL SPRING pulls
every particle toward an in-frame shell (containRadius*0.62) with a per-particle
band so the cloud is a contained breathing sphere, not an ever-growing ring.
Tighter velocity clamp + boundary snap as belt-and-suspenders.

Color: replaced the flat 3-color tint with a living iridescent RAINBOW — hue
drifts by per-particle phase + radius + time + a global rotating hue shift
(fract/abs hexagon palette). Dramatic beats blend their mode color over the
rainbow (crimson at contradictions, gold at surprises) via uModeTintAmt; calm
beats stay mostly rainbow. 937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:15:12 -05:00
Sam Valladares
b3f02ebc2f fix(cinema): guarantee the storm stays centered — never flies off-screen
Root cause: layoutPositions grew per beat (radius 22 + i*6), so each beat sat
farther out; the camera + storm marched off into space as the tour progressed.

Fix (centered-by-construction):
- layoutPositions: tight BOUNDED golden-angle shell (SHELL_RADIUS 14), no growth.
- sandbox: storm pinned to the WORLD ORIGIN permanently; camera hard-clamped to
  an 18-46 unit distance band and always lookAt(origin); containment sphere
  sized to the FOV at origin. A runaway move is corrected every frame.
- director: new centerOnOrigin mode (enabled when WebGPU active) — frames/orbits
  the origin instead of flying to scattered nodes; variety from angle/standoff.

No path remains for the subject to leave frame. 937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 01:09:07 -05:00
Sam Valladares
5e8a22a427 feat(auteur): Phase 2 — director executes the screenplay (shippable hero)
director.ts: optional shots:ResolvedShot[] in DirectorOptions; per-beat
  flight/dwell timing; framePosition now reads move (push_in/pull_back/crane
  scale standoff) + angle (low=look-up, high=look-down) + standoff; orbit shots
  revolve the camera during dwell; Dutch roll via camera.up; hard/match cuts
  snap (editorial cut). With NO shots the camera is byte-identical to before
  (all values fall back to the existing constants + easeInOutCubic lerp).
MemoryCinema.svelte: build computeSignals + planShotsDeterministic + resolveShots
  on launch, pass shots to the director; onBeat drives storm mode + director's
  note + Act + tension from the shot. New UI: pre-roll DIRECTOR'S PLAN card
  (logline naming real memories), per-beat 'why this shot' note, Act I/II/III
  badge, tension-tinted progress bar, Auteur source badge.

The deterministic auteur ships the hero film with zero LLM. 937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:58:35 -05:00
Sam Valladares
8094931ea9 feat(auteur): Phase 1 — graph signals + director contract (pure, headless)
The spine of 'The Auteur': the LLM/rule-table becomes a film director.
- topology.ts: computeSignals — Brandes betweenness, union-find clusters,
  recency, retention, suppression, edge surprise (Jaccard x distance). Reuses
  pathfinder internals (now exported). Betweenness capped for huge graphs.
- auteur.ts: typed Shot/DirectorPlan/ResolvedShot contract; resolveShots
  carry-forward resolver (every axis back-filled prev->SHOT_DEFAULTS=today's
  camera constants, so a sparse/garbage plan ALWAYS yields a coherent film);
  planShotsDeterministic (Tier-2 pure auteur via graph-metric->shot-grammar
  rule table); directorSystemPrompt (same table → LLM prompt).
- pathfinder: export buildAdjacency/recencyOf/isContradictionEdge/Adjacency;
  add 'surprise' beat kind. narrator KIND_CHIP gains 'surprise' (satisfies).
- 11 new tests (carry-forward, garbage backfill, keystone betweenness,
  contradiction direction, determinism). 937 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:51:20 -05:00
Sam Valladares
4163f4fc80 fix(cinema): contain the particle storm on-screen (soft sphere + velocity clamp)
Particles (esp. the unbounded Rössler chaos mode) could fly off-screen. Add a
camera-frame-sized spherical containment field: spring pull-back past the
radius, hard velocity clamp, and a snap-to-shell safety net so no particle can
escape. The sandbox sizes the radius from camera distance + vfov each frame so
the storm reframes as the camera flies. Verified: check + build green.
2026-06-22 00:14:29 -05:00
Sam Valladares
66b10ded42 fix(dashboard): resolve all blocker/high/medium findings from Memory Cinema audit
storm.ts (blockers): correct particle position wiring — positionNode now
  instancePos.add(positionLocal) (bare storage element collapsed every quad to a
  point); serialize GPU compute dispatches (computeInFlight) to stop queue
  stalls; ignition floor so the storm never fades to black; null buffers on
  dispose for GC (StorageBufferAttribute has no dispose()); typed computeNode +
  InstancedMesh, removed unsafe casts.
narrator.ts: validate + filter backend beats, bounds-safe fallback merge,
  KIND_CHIP satisfies (compile-time enum coverage), chip type guard, timer cleanup.
MemoryCinema.svelte: replace the null-returning Local AI stub with a real
  on-device transformers.js text-generation pipeline (+ genuine fallback);
  Escape-to-close + autofocus a11y; reset all run state on launch (no stale
  Replay); fix render/close race; computed fallback camera aspect; typed state.
director.ts: NaN-guard progress on empty path; clamp dt >= 0.
sandbox.ts: guard three/webgpu exports + tsl pass() API shape; resize w/h floor.

926 tests + build green. Net: every audit blocker/high/medium fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 00:08:37 -05:00
Sam Valladares
95750f0a85 feat(dashboard): respect prefers-reduced-motion in the base 3D graph
Disable camera auto-rotate (the dominant continuous motion) when the OS
reduce-motion setting is on; live-toggle aware via matchMedia change listener,
cleaned up on destroy. Graph stays fully usable (manual orbit/hover/select/live
events). Closes the a11y gap where 0 of ~3,200 graph LOC honoured the setting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 23:53:40 -05:00
Sam Valladares
a6798c2fca feat(dashboard): wire Memory Cinema UI into graph page
- MemoryCinema.svelte: launch button + fullscreen overlay, typewriter caption
  stream, SpeechSynthesis voice toggle, opt-in lazy-loaded Local AI toggle,
  progress/beat indicators, replay. Director-driven master loop hardened so a
  WebGPU render failure drops to camera-only without stalling the tour.
- sandbox: construct Scene/Camera from the three/webgpu module instance so all
  objects fed to the WebGPU renderer are instance-compatible (fixes
  'multiple instances of Three.js' incompatibility).
- graph page: Cinema button beside Dream, gated on having nodes.

Verified live: button renders, overlay opens, WebGPU boots + reports active,
7-beat path plans, narration resolves to live captions, bundle code-splits
(WebGPU 479K chunk loads on demand only). 926 tests + build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:23:26 -05:00
Sam Valladares
1ca5941491 feat(dashboard): Memory Cinema engine — BFS director + narrator + WebGPU GPGPU storm
- pathfinder.ts: deterministic story-path BFS over real graph (origin→strongest→contradiction→recent), Tier-3 bulletproof base (8 tests)
- director.ts: cinematic camera choreography, reduced-motion jump-cut support
- narrator.ts: Tier-1 backend-LLM → Tier-2 local structured captions cascade
- storm.ts: 150k-particle TSL GPGPU SemanticComputeStorm (orbital/stream/Rössler-chaos modes) verified against installed three/tsl API (select not cond, SpriteNodeMaterial, computeAsync)
- sandbox.ts: isolated WebGPU canvas + selective MRT bloom, dynamically imported (zero main-bundle weight), graceful no-WebGPU fallback

WebGL graph untouched = zero regression. 926 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 20:16:21 -05:00
Sam Valladares
28d2434843 feat(dashboard): launch quick-wins — view transitions, OKLCH/P3 palette, reduced-motion-ready, responsive graph controls, ws reconnect state
- Native View Transitions API via onNavigate (feature-detected, reduced-motion safe)
- OKLCH + display-p3 accent palette with hex fallback (@supports progressive enhancement)
- WebSocket gains 'reconnecting' state so stale errors clear on reconnect
- Graph control bar wraps + safe-area insets for <640px / notched phones

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 19:15:12 -05:00
Sam Valladares
2b50bf5d53 ci: guard against private cloud service code in public repo
Vestige Cloud is split: the public client (a thin HTTP sync backend that
only moves encrypted bytes) belongs here, but the hosted service — billing,
sync-key->namespace mapping, per-user isolation, Lemon Squeezy webhooks,
transactional email — must live only in the private repo.

Add scripts/check-no-private-cloud.sh, which git-greps tracked files for
distinctive private-service signatures (service crate identity, module
headers, billing/provider internals, server-side sync-key mapping SQL). The
patterns are chosen so the legitimate public client — including its
VESTIGE_CLOUD_* client env vars — does not match.

Wired into CI via guard-no-private-cloud.yml on push/PR. Verified both
directions: passes on the clean repo, fails (naming the markers) when real
private webhook.rs/keys.rs are introduced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:19:01 -05:00
Sam Valladares
a19ea11276 fix(pages): serve dashboard at site root, drop double /vestige nesting
The Pages project site is already served from /vestige/, and the dashboard
is built with base path /vestige. Nesting the build under _site/vestige/
served it at /vestige/vestige/ and left a broken redirect at the root.
Copy the build to the artifact root so it serves correctly at /vestige/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:50:10 -05:00
Sam Valladares
2359472588 ci(pages): pin pnpm version in deploy workflow
pnpm/action-setup needs an explicit version (root package.json has no
packageManager field). Match test.yml's pinned version: 10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:48:11 -05:00
Sam Valladares
79b1026a65 ci(pages): deploy dashboard to GitHub Pages with subpath-aware base
The github-pages deployment showed a red X: actions/configure-pages@v5
ran with enablement:true, but Pages was never enabled in repo settings and
the default GITHUB_TOKEN cannot create a Pages site, so deploy failed with
"Resource not accessible by integration". The launch-kit revert then deleted
the workflow entirely, leaving nothing to deploy.

- Restore a modernized pages.yml (Pages now enabled via API, so no
  enablement hack; actions/checkout@v5 + Node 24 off the deprecated Node 20).
- Make the dashboard base path env-driven (VESTIGE_BASE_PATH), defaulting to
  /dashboard for local/embedded use and overridden to /vestige in CI so
  assets resolve at the Pages project subpath instead of 404ing.
- Workflow builds the dashboard under /vestige and writes a root-level
  redirect index.html so the bare Pages URL lands on the dashboard.
- Rebuild the committed dashboard artifact (was stale at 2.1.23) to 2.1.27.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:46:43 -05:00
Sam Valladares
b8212feb15 feat(cloud-sync): zero-knowledge client-side encryption (XChaCha20-Poly1305)
The portable archive is encrypted on the client before upload and decrypted
after download, so the hosted service only ever stores ciphertext — true
zero-knowledge. The passphrase (VESTIGE_CLOUD_ENCRYPTION_KEY) is independent
of the bearer sync key and never leaves the device.

- new cloud_crypto module: Argon2id KDF + XChaCha20-Poly1305 AEAD, self-
  describing envelope (MAGIC|version|salt|nonce|ciphertext+tag)
- HttpPortableSyncBackend encrypts on write / decrypts on read; transparent
  upgrade of legacy plaintext archives; clear error if remote is encrypted
  but no passphrase is set
- sync_portable_archive_cloud takes optional encryption_key
- CLI surfaces encryption status (on/off) on sync
- 6 crypto tests (roundtrip, wrong-key, tamper detection, non-determinism,
  envelope detection); E2E verified: server blob is ciphertext, passphrase
  device recovers, no-passphrase device cannot decrypt

491 core tests green, clippy -D warnings clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 21:19:16 -05:00
Sam Valladares
fdd6b98180 feat(cloud-sync): HTTP managed-sync backend + vestige sync --cloud
Vestige Cloud MVP client side. Implements HttpPortableSyncBackend, an HTTP
impl of the existing PortableSyncBackend trait, reusing the production
sync_portable_archive pull-merge-push engine unchanged — only the transport
is new. Per-user isolation via opaque bearer sync key (namespace derived
server-side). Optimistic concurrency via ETag/If-Match to prevent lost
updates across devices; 412 surfaces a re-run-to-merge message.

- new cloud-sync cargo feature (vestige-core + vestige-mcp), gates reqwest
  blocking; default local-first build stays network-free
- sync_portable_archive_cloud wrapper mirrors sync_portable_archive_file
- CLI: vestige sync --cloud [--endpoint], VESTIGE_CLOUD_ENDPOINT/SYNC_KEY env
- 8 unit tests (dependency-free TcpListener mock): 404/200/401 reads,
  If-Match present/absent writes, 412 conflict, ETag capture

485 core tests green, clippy -D warnings clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 20:35:01 -05:00
caioribeiroclw-pixel
5c2db045f6
test: add test-integrity delta fixtures (#79)
Co-authored-by: Sam Valladares <143034159+samvallad33@users.noreply.github.com>
2026-06-19 19:41:31 -05:00
Sam Valladares
d23870d906 chore(release): v2.1.27 — External-Source Connectors
Bump all manifests 2.1.26 → 2.1.27 and date the CHANGELOG entry for the
GitHub + Redmine connector layer and source-aware search filters (#57, PR #78).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 11:10:54 -05:00
Sam Valladares
8e4f4052cc
Merge pull request #78 from samvallad33/feat/connectors-issue57-v2.1.27
feat(connectors): GitHub + Redmine retrieval layer (#57)
2026-06-19 02:35:14 -05:00
Sam Valladares
4e893c02ff feat(connectors): add Redmine and source filters (#57) 2026-06-19 02:21:25 -05:00
Sam Valladares
50e7f2d0fb feat(connectors): external-source connector layer + GitHub Issues (#57)
Make Vestige a durable, local, semantically-searchable retrieval layer over an
external system of record (GitHub Issues first), citing back to the canonical
record. Unlike a live ticket-system MCP proxy, Vestige keeps a durable embedded
index: searchable offline, joinable with the rest of memory, temporally
versioned, and re-syncable idempotently with no duplication.

Phases 1-2 of #57 plus a GitHub reference connector and source-aware search:

- Source envelope on KnowledgeNode/IngestInput (source_system, source_id,
  source_url, source_updated_at, content_hash, synced_at, source_project,
  source_type, source_author). Migration V17: nullable columns (additive),
  partial UNIQUE index on (source_system, source_id), connector_cursors table.
- Idempotent sync primitives in vestige-core: upsert_by_source (content-hash
  change detection), connector cursor checkpoints, reconcile_source_tombstones
  (invalidate-don't-delete via bitemporal valid_until).
- Connector contract + run_sync driver + GitHub Issues connector behind the
  optional `connectors` feature (on by default in vestige-mcp, off in the core
  library default so non-connector consumers link no HTTP client).
- source_sync MCP tool ({"repo": "owner/name"}); token from GITHUB_TOKEN env
  only. Search results gain a sourceRecord citation for connector memories.

Adversarial review fixes: GitHub `since` Z-form (the `+00:00` offset corrupted
the cursor server-side), un-tombstone clears superseded_by too, cursor never
advances past a failing record, Link next-url host-pinned (token-leak guard),
records_seen counts new records only.

Verified: cargo check/test/clippy -D warnings green across the workspace
(default and connectors features); 483 core tests pass. Version bump to 2.1.27
and tag deferred to release.

Refs #57

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 01:21:59 -05:00
Sam Valladares
22d0d192eb fix: make windows release build and add manual rerun path 2026-06-18 23:39:38 -05:00
Sam Valladares
ef2073d4a4 Harden old CPU fallback paths (#71) 2026-06-18 21:54:04 -05:00
Sam Valladares
536776c9d6 Guard vector index init/search on unsupported CPU (#71) 2026-06-18 21:36:53 -05:00
Sam Valladares
05f0050ad8
Merge pull request #76 from samvallad33/codex/opencode-sigill-salvage
[codex] Add OpenCode integration and safer startup
2026-06-18 20:54:01 -05:00
Sam Valladares
2757010d6d Make fastembed smoke tests tolerate unavailable model 2026-06-18 20:29:02 -05:00
Sam Valladares
5e18304184 Fix OpenCode init migration cleanup 2026-06-18 20:10:28 -05:00
Sam Valladares
ea5ed28081 Merge remote-tracking branch 'origin/main' into codex/opencode-sigill-salvage 2026-06-18 19:59:25 -05:00
Sam Valladares
c60233961d Merge PR #61: storage trait phase 1 2026-06-18 19:15:07 -05:00