Commit graph

278 commits

Author SHA1 Message Date
Sam Valladares
02746d4b91 chore(launch): remove one-time verify scripts leaking private absolute paths
verify-launch.mjs / verify-launch-mobile.mjs were throwaway Playwright
screenshot scripts hardcoding /Users/entity002/... paths (incl. a Desktop
testimonial dir and the retired vestige-launch-main worktree). Nothing
references them; they violate public-repo hygiene. Removed before publishing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 16:37:28 -05:00
Sam Valladares
6e3cc4439a docs(server): sharpen MCP manifest description — FSRS-6/active-forgetting, not a vector store
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 16:28:17 -05:00
Sam Valladares
ba5a28d5f9 fix(dashboard): close remaining BackdropEngine audit findings (M3 H1-H4 + mediums)
Clears the rest of the MiniMax M3 audit backlog (all verified, svelte-check green):
- H1: Canvas2D fallback now honors decay (inward pull+damp) and birth (outward
  bloom) events, not just firewall — full event parity with the WGSL path for
  pre-iOS-26 / no-WebGPU users.
- H2: noise/flow time is now an `activeT` accumulator advanced by dt only while
  drawing, so a backgrounded tab no longer fast-forwards the curl flow and snaps
  it to a new direction on resume (was wall-clock `(now-startedAt)`). Both the
  WebGPU and Canvas2D paths share it.
- H3: prefers-reduced-motion is now reactive ($state + a matchMedia change
  listener) so toggling the OS setting mid-session takes effect next frame
  (was a const snapshot at init).
- H4: documented that `count` is read once at boot (buffer sizing); `intensity`
  is the live knob.
- M3: cache the Canvas2D context once in bootFallback (was getContext per frame).
- M4: coalesce resize bursts to one resize/frame via rAF (was thrashing the
  swapchain config + 2D backing store on every drag event).
- M7: register device.lost BEFORE pipeline creation (was after the handle,
  leaving a race window where a loss mid-build never fired the fallback).
- L2/L4/L1: drop the empty onMount return (single onDestroy teardown); reset
  lastT in bootFallback so a WebGPU recovery sees no giant dt; document the
  intentionally-non-reactive animation state.

svelte-check 0 errors / 967 files. Cosmetic-only items left (M1 dead DPR slot,
M2 dead vel.w, M5 sizePx naming, L3 alpha-mode smell) — no behavior, deferred.
Memory Cinema / Graph3D untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 15:35:05 -05:00
Sam Valladares
b41b1b90de fix(dashboard): kill parallax size-pop at the z-wrap seam (DeepSeek V4-Pro audit)
4th-model pass (DeepSeek V4-Pro, max reasoning, steered at the GPU numerics the
other 3 didn't audit) found a NEW bug class none of them connected:

The compute pass soft-wraps ALL of pos including z into [-1,1]
(fract(pos*0.5+0.5)*2-1). The vertex shader derived particle depth/size from a
NON-periodic linear function of that wrapped z (depth = 1.7 + z*0.5), so every
time a particle crossed the z=+/-1 seam its depth jumped 2.2 -> 1.2 and its
rendered size ~doubled (1.83x) in a single frame — a continuous popping that
breaks the volumetric-cloud illusion.

Fix: make depth periodic across the seam with sin(z*pi)*0.5 — it's 0 at both
z=+/-1 (size continuous across the wrap) and still sweeps depth over [1.2, 2.2].
Verified continuous: depth(z=+1)=depth(z=-1)=1.7.

(Also fixed a self-inflicted gate catch: the explanatory comment originally
contained a backtick, which terminated the WGSL template literal early and broke
svelte-check — caught by the gate before commit, now ASCII-only.)

svelte-check 0 errors / 967 files. Visual capture still pending a live backend.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 15:22:32 -05:00
Sam Valladares
deb3b82134 fix(dashboard): correct WebGPU shader coordinate + frame-rate bugs (MiniMax M3 audit)
MiniMax M3 (max-depth audit, fresh eyes on the shader MATH that Claude+Kimi's
lifecycle-focused passes missed) found 4 pre-existing criticals, all verified:

- C1 aspect-ratio inversion: vertex shader divided particle X by aspect, which
  SQUASHED the whole field into the center ~56% of a 16:9 screen (~22% empty
  bars each side). Fix: position now uses the full [-1,1] clip box (no divide);
  roundness comes from a proper px2ndc = 2/viewport corner offset so quads are
  sizePx x sizePx device px on any aspect ratio (also kills the 0.01 magic number).
- C3 firewall flare landed at the wrong X (distance measured in unit-box space
  while the particle rendered in divided space). Fixed-for-free by C1; the crimson
  distance is now aspect-corrected so the halo is circular, centered on the catch.
- C4 frame-rate-dependent flow absorption: the velocity lerp used a fixed 0.06
  per-frame factor (not dt-scaled), so the field was 2x snappier at 120Hz
  ProMotion vs 60Hz. Fix: absorb = 1 - exp(-dt * 3.7) — identical feel at 60fps,
  correct everywhere else.

VERIFIED: svelte-check 0 errors / 967 files; zero WGSL validation errors in the
browser (a broken shader struct/syntax would throw at pipeline creation — none).
NOTE: the on-screen full-width widening is not yet visually captured this session
— the preview backend returns API 500 so the (app) layout error-states and the
field doesn't mount; pending eyeball on a wide window against a live backend.
Memory Cinema / Graph3D untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 14:52:45 -05:00
Sam Valladares
85650f02fd fix(dashboard): backdrop lifecycle races + GPU buffer leaks (Kimi-audited)
Kimi K2.7-code audit (max-thinking) found a CRITICAL race + leaks that Claude's
shallower pass missed; all verified and fixed:
- CRITICAL: late WebGPU boot after the 6s watchdog fired bootFallback() would
  set mode='webgpu' and start a SECOND rAF loop, orphaning the fallback loop.
  Fixed with a top-of-function + post-await abort guard in tryBootWebgpu and a
  single idempotent tick()/startLoop() dispatcher (running flag) — rAF for the
  draw loop is now scheduled in EXACTLY one place.
- GPU buffer leaks: partBuf/uBuf are now destroyed via releaseBuffers() on every
  early-exit, the catch path, and the device-lost handler (was leaked everywhere
  except the handle!=null onDestroy path).
- resize() now reconfigures the WebGPU context (was stretching after resize).
- drawWebgpu wrapped in try/catch -> bootFallback (one bad frame no longer kills
  the field permanently).
- fallback now honors the intensity prop + is frame-rate independent (dt*60);
  onVisibility resets fbLastT; onDestroy SSR-guard ordering.

svelte-check 0 errors / 967 files. Memory Cinema / Graph3D untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 14:24:10 -05:00
Sam Valladares
b8de5c9bf7 fix(launch): close waitlist RLS bypass + open email relay + add security headers
Launch-critical fixes for the public July-14 signup surface (swarm-audited by
MiniMax M3, Claude-verified against the frontend RPC call path):
- migration: DROP the "anon can insert with check(true)" RLS policy. It let
  anon write arbitrary rows straight to the table, bypassing all join_waitlist
  validation. The frontend already calls the join_waitlist RPC (rest/v1/rpc/),
  never a direct insert, so signup is unaffected. RLS stays enabled with no
  permissive INSERT policy = direct anon inserts denied by default.
- join_waitlist: cap email <=254, reject control chars, truncate referrer <=2048.
- waitlist-welcome edge fn: FAIL CLOSED — if WAITLIST_WEBHOOK_SECRET is unset,
  return 401 instead of serving (was an open Resend relay). Guard the referral
  code against ^[a-z2-9]{7}$ and cap email length before sending.
- vercel.json: add baseline security headers (nosniff, Referrer-Policy,
  X-Frame-Options: DENY, HSTS, Permissions-Policy). CSP deferred (would break
  the WebGPU hero's inline bootstrap without nonces) — documented.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 14:23:58 -05:00
Sam Valladares
b107fd5d7f fix(firewall): close homoglyph + format-char + exfil/base64 bypasses
Swarm-audited (DeepSeek V4-Pro) + Claude-verified gaps in the Microglial
Firewall's screening normalization:
- fold_confusable: add Greek homoglyphs that are TRUE visual Latin matches
  (ο→o ι→i α→a ε→e ρ→p τ→t χ→x κ→k β→b). Upsilon/nu deliberately omitted
  (not reliable homoglyphs). Math-alphanumerics left as a TODO (need per-block
  offset tables to fold correctly).
- is_format_or_space: add U+00AD soft hyphen, U+034F, U+2061..U+2064 so they
  can't hide inside a keyword and split tokenization (system\u{AD}: bypass).
- has_external_destination: broaden exfil prepositions (via/through/using/over/onto).
- has_long_base64_run: accept the base64url alphabet (-, _).
- strip ordered-list gutter (1. / 2)) before the role-prefix check.

The benign-marker/quoted-trigger suppression (a deliberate false-positive
tradeoff) is intentionally left unchanged. clippy clean; 30 firewall tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 14:23:48 -05:00
Sam Valladares
9d791a35a5 feat(dashboard): backdrop robustness + fallback firewall flash
Real robustness fixes found while verifying Phase 3:

- Boot watchdog: if WebGPU hasn't started rendering within 6s (slow/contended
  GPU, hung device request), fall back to Canvas2D so the field is never stuck
  on the static gradient. Cleared on successful webgpu boot + onDestroy.
- bootFallback is now idempotent (guards double-start, cancels any in-flight
  rAF) so the watchdog can't race a second loop.
- Canvas2D fallback now reacts to the firewall field event too — an outward
  shockwave + crimson tint — so pre-iOS-26 / no-WebGPU users also see the catch.
- ?demo=firewall fires the flash on a short delay (so the field has booted, not
  mid-boot where it'd be missed); ?demo=firewall&loop=1 re-arms it every 3.2s
  for repeatable launch-footage capture.

svelte-check 0 errors / 967 files. NOTE: the on-screen crimson flash remains
visually unconfirmed this session — the preview env had an unstable viewport +
exhausted GPU process; pending a clean browser. Memory Cinema untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 12:29:42 -05:00
Sam Valladares
69aab30d38 feat(dashboard): Phase 3 — event-triggered field effects (firewall flash)
The "earned by the backend" payoff: cognitive events drive the WebGPU field.

- fieldEvents.ts: a tiny decoupled pub/sub bridge (emit/onFieldEvent) so the
  dashboard publishes cognitive events and the BackdropEngine reacts, with no
  coupling either way. Kinds: firewall / decay / birth.
- BackdropEngine: uniform expanded to carry an event vec4 (code, fade, origin).
  Compute shader applies a scoped impulse — firewall = outward shockwave + energy
  spike, decay = inward cold collapse, birth = bright bloom. Render shader flares
  particles near a firewall origin toward an angry CRIMSON (reserved ONLY for the
  firewall block; nothing else turns red). Effect fades over 1.6s.
- Black Box ?demo=firewall now emits a firewall field event, so catching the
  attack visibly flashes the living field crimson — the launch money-shot.

Verified: svelte-check 0 errors / 967 files; WGSL compiles with no validation
errors in-browser. NOTE: the on-screen crimson flash is not yet visually
captured this session (preview GPU device stalled after many reloads); pending a
clean GPU context. Memory Cinema / Graph3D untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:55:47 -05:00
Sam Valladares
f5ce349cac feat(dashboard): Phase 2 — alive shell, translucent panels, living dead-states
Make the WebGPU violet field breathe THROUGH the UI and turn the dead
offline/empty/error states into intentional, alive moments:

- Glass veil-ramp: panel tops drop to ~0.30 opacity so the field crests through
  every header, while body text composites over a ~0.82 floor — more alive AND
  more legible than the old flat 0.45. New .veil/.veil-strong/.text-legible
  legibility utilities.
- edge-live membrane: a state-colored synapse rim (indigo idle, synapse live,
  dream violet, amber alarm) + rail-dormant desaturate when offline. Shell mood
  derived from connection/dream state.
- LifeState component replaces raw "Error: API 500"/"Offline"/"Select a run":
  a calm "Dormant" breathing state, a self-healing error with the raw detail
  demoted to a collapsed <details> + Retry, and a "Listening for the agent"
  offline state wired to the firewall demo.
- Legibility fixes from the a11y audit: sidebar metrics text-muted->text-dim,
  LifeState body->text, detail->dim + veil-strong, ambient strip + text-legible.

All new animation prefers-reduced-motion guarded. Memory Cinema, Black Box
machinery, Graph3D, and the backdrop core untouched. svelte-check 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:36:28 -05:00
Sam Valladares
a68895482d fix: clean launch baseline + close firewall leetspeak bypass
- websocket.test.ts: 3 stale injectEvent assertions now expect the correct
  source:'synthetic' tag the store adds (production behavior was already right).
- server.rs: collapse a clippy::collapsible_if in test code into a let-chain.
- microglial_firewall: gated de-leet so leetspeak injections (1gn0re prev1ous
  1nstruct10ns) are caught, with a structural guard — a digit-bearing token is
  only rewritten if it de-leets exactly onto a known injection keyword, so
  v1.2.3 / sha256 / base64 / 0x1f / i18n / port 8080 never false-quarantine.

Verified: vestige-core tests + clippy --all-targets clean, dashboard 950/950.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:23:27 -05:00
Sam Valladares
a2f4e459e1 docs(launch): viral asset package + waitlist setup runbook
- VIRAL_ASSETS_2026-07-14.md: X thread, Show HN, Reddit variants, 30s demo
  script, positioning. Firewall claim cleared after the re-audit confirmed
  enforcement; honest wording (kept-from-influencing, not "deleted").
- waitlist-setup.md refreshed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:13:10 -05:00
Sam Valladares
6837198328 feat(launch): waitlist page, raw-WebGPU hero, supabase + vercel infra
The July 14 launch surface, previously uncommitted:
- /dashboard/launch raw-WebGPU particle "memory brain" hero (RawVestigeEngine,
  NeuralWordmark, dendrite sign) + DOM waitlist overlay with share/referral.
- Supabase waitlist client + migrations + welcome edge function; legacy waitlist
  archived under supabase/legacy.
- vercel.json deploy config, root-redirect env wiring, base-path config,
  graph-only route, Playwright launch verifiers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:13:02 -05:00
Sam Valladares
24ef2d504f feat(dashboard): firewall UI in Black Box + alive WebGPU backdrop
- Black Box surfaces the memory.quarantine + episode.boundary events: a red
  "Microglial Firewall" detail panel (QUARANTINED / influenceAllowed: false +
  threat prose), hasQuarantine producer/proof-mode status, episode dividers.
  ReceiptCard renders quarantined[] + the influence badge.
- TS MemoryTraceEvent union + Receipt interface extended to mirror the Rust
  serde wire shapes exactly (memory.quarantine, episode.boundary, quarantined/
  influence_allowed/engram_phases). +13 blackbox-helpers tests.
- New lib/core: VestigeGPU (reusable raw-WebGPU boot core, 3-tier adapter
  fallback + device-loss recovery, no Three.js) and BackdropEngine, a curl-noise
  "alive purple neural field" mounted behind every route, with a Canvas2D
  fallback for pre-iOS-26 devices. SSR-safe (browser-guarded).
- ?demo=firewall loads a synthetic attack->quarantine->receipt run for offline
  launch-footage capture (real UI, synthetic data).

Verified live in preview (data-mode=webgpu, firewall panel renders), svelte-check
0 errors / 965 files.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:12:23 -05:00
Sam Valladares
921304a475 feat(neuroruntime): wire Microglial Firewall into the write path
Add the firewall causal slice so a poisoned/injected memory is screened,
quarantined, and proven held-out on the receipt (influence_allowed=false):

- screen_write() detector (neuroscience/microglial_firewall.rs): deterministic
  prompt-injection / exfiltration / poisoning screen with NFKC + homoglyph
  folding and word-boundary matching to avoid false quarantines.
- Receipt gains quarantined[] / influence_allowed / engram_phases (additive,
  serde-default, back-compatible with old receipts).
- New trace events memory.quarantine + episode.boundary (mirror the TS union).
- gate_writes() now screens every write and, on a quarantine verdict, suppresses
  the node (held out of retrieval) + records the quarantine receipt + events, so
  influence_allowed=false is ENFORCED, not cosmetic. Content capped at 16KB.
- VestigeEvent::MemoryQuarantined live broadcast.

Verified: cargo test vestige-core/vestige-mcp green, clippy -D warnings clean,
integration test proves a screened injection is absent from the write's retrieval.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:12:06 -05:00
Sam Valladares
cfe8d03d36 feat(landing): full-viewport GPU node-engine hero + waitlist + dashboard auth removal
The /launch landing page (bleeding-edge waitlist hero):
- Full-viewport WebGL node engine (src/lib/hero/nodeEngine.ts): 40k GPU particles
  on a two-FBO GPUComputationRenderer running an 18s looping cinematic — particles
  stream in from the screen edges, slam together and EXPLODE at center, reform into
  a brain / graph constellation / neural lattice, dissolve back out, loop. Glowing
  additive particles + UnrealBloom, fills the whole screen edge to edge.
- Key GPGPU fix: custom DataTexture shape targets read black in GPUComputationRenderer
  (three.js #15882), so shape targets are computed PROCEDURALLY in-shader from the
  per-particle seed. Position integrates raw per-frame velocity (Codrops pattern),
  texel-center reference attribute.
- AmbientField (god-ray glow + parallax starfield), phantomBrain (deterministic
  seed-from-identity memory graph), LandingHero/neuralFlow (WebGPU Cinema-storm
  reuse + WebGL fallback, kept as alternates). Manifesto copy, seed input, email
  capture. No em-dashes. SSR off + prerender for the WebGL route.

Waitlist backend (Supabase, owned data):
- supabase/migrations/0001_waitlist.sql (RLS-locked table, dedup), Edge Function
  waitlist-join (CORS, validation, honeypot, dedup, Resend confirmation), setup doc.

Dashboard auth removed (reverts the launch-polish auth wall that 401'd the dashboard
against itself): mod.rs/state.rs/websocket.rs back to no-token, api.ts/websocket.ts/
+layout.svelte stripped of the token client. Pending-review UX + Memory PR gating kept.

Research/spec docs under docs/launch/. Frontend typechecks 0/0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 22:54:51 -05:00
Sam Valladares
335a42f341 merge: cloud sync pro — encrypted managed sync (lane 5/5) 2026-06-24 17:35:12 -05:00
Sam Valladares
1b48800916 merge: github pages demo deploy (lane 4/5) 2026-06-24 17:35:06 -05:00
Sam Valladares
e95b772cfe merge: launch polish — dashboard auth + review UX (lane 3/5) 2026-06-24 17:35:00 -05:00
Sam Valladares
d5002c314b merge: black box launch spine (lane 2/5) 2026-06-24 17:34:54 -05:00
Sam Valladares
f80c51ee59 merge: dashboard cinema foundation (lane 1/5) 2026-06-24 17:34:47 -05:00
Sam Valladares
0ff9527d2b feat(launch-polish): finish dashboard auth trust boundary + pending-review UX
Completes the launch-polish lane Codex started (rate-limited mid-wiring):

Trust boundary (was: dashboard API/WS unauthenticated):
- Token middleware on all /api/* and /ws, reusing the persisted Vestige auth
  token with constant-time compare (subtle); Sec-Fetch-Site + exact-Origin checks
- Token delivered via URL fragment (never sent to server / logged), installed
  into localStorage on app load — WIRES installDashboardTokenFromLocation() into
  the root +layout onMount BEFORE websocket.connect()/any fetch (the missing
  piece that otherwise 401s the dashboard against its own API)

Fail-closed memory governance:
- Dashboard delete/suppress pre-gate through Memory PRs in Risk-Gated/Paranoid
  (Fast still mutates directly); decision-before-mutation; replay -> 409
- Duplicate pending-PR reuse; PR content redacted to preview+hash at the API layer

Black Box / receipts:
- Live refresh of run list + receipts on real TraceEvents (trace-before-receipt
  race handled via retry); synthetic events excluded from proof counters

Fixes on top of Codex's work:
- websocket.ts: source 'synthetic' -> `as const` (TS error, blocked pnpm check)
- memories: scoped a11y-ignore on the non-interactive review-notice
- collapsed sanitize_memory_pr_json (clippy collapsible_if); rustfmt the 7
  touched Rust files

Gates: pnpm check 0/0 (905 files); vestige-mcp 453 tests; core trace/review/
receipt 67 tests; clippy -D warnings clean. All green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 17:28:38 -05:00
Sam Valladares
26ef4bc43a 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-24 16:13:31 -05:00
Sam Valladares
b2da9cd6bd 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-24 16:13:30 -05:00
Sam Valladares
822ec3b19b 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-24 16:13:30 -05:00
Sam Valladares
430a723505 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-24 16:08:33 -05:00
Sam Valladares
979c2ae802 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-24 16:08:33 -05:00
Sam Valladares
5c438e61f4 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-24 16:08:33 -05:00
Sam Valladares
19ef586056 fix(blackbox): C2-deep gate destructive writes post-delete + redact PR content
Two deeper review findings (both blockers) + doc de-staling.

C2-deep: my earlier C2 made purge/delete TRACE as memory.write, but gate_writes
did `get_node(id) -> skip on None`, and purge had already DELETEd the row — so a
destructive removal still never opened a Memory PR (it was silently skipped).
The most security-critical write type couldn't be reviewed. Fix: a missing node
is now gateable for destructive decisions — gate_writes builds the WriteContext
from the decision itself (marks `forgets`, which classify_write gates), and the
PR records the removal with node.deleted=true. Proven live: purging a node opens
a PR (kind node_decayed, deleted true); test
gate_opens_pr_for_destructive_write_after_node_deleted_c2.

PRIV: gate_writes copied the FULL node.content into the PR diff + title, so a
real secret in a gated memory would leak into the memory_prs table, the
dashboard, and any exported proof bundle — defeating the point of gating
sensitive writes. Fix: the PR now stores a truncated content PREVIEW + an FNV
content HASH, and sensitive-topic/sensitive-node-type writes are fully REDACTED
("[redacted — sensitive content; review via risk signals]"). The reviewer still
sees the risk signals (why it opened) and a hash (to correlate), never the
secret. Tests gate_redacts_sensitive_content_in_pr_priv,
content_preview_redacts_sensitive_and_truncates, content_hash_is_stable. The
committed memory_pr.json + the whole proof bundle were re-captured and contain
no secret (verified by scan); the re-shot memory-prs.png shows the redaction.

DOC: REVIEW.md commit list is now git-log-based (no stale hashes); C2-deep + PRIV
added to the findings table; PROOF.md write/PR rows updated; test count -> 1007.

Gates: 1007 lib tests pass (+7 new regressions), clippy -D warnings clean,
dashboard check + build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 16:05:35 -05:00
Sam Valladares
c61ae6c335 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-24 16:05:35 -05:00
Sam Valladares
c70404b8d1 fix(blackbox): C1 unconditional quarantine release + C2 trace destructive writes
Two more review findings — both real, both blockers — plus stale-doc cleanup.

C1: the B1 release used reverse_suppression(subject_id, labile_hours), which
REFUSES once the 24h active-forgetting labile window has passed. So a Memory PR
reviewed late could be marked "promoted" while its memory stayed suppressed.
Approving a quarantined write is an explicit reviewer decision and must release
the memory regardless of elapsed time. New SqliteMemoryStore::release_quarantine
fully clears the suppression (count→0, suppressed_at→NULL) with NO time-window
limit; the PR handler now uses it. Proven: a test backdates suppressed_at to
+100h, shows reverse_suppression refuses, and release_quarantine still releases.

C2: memory(action="purge"|"delete") returns `action` + nodeId but those labels
weren't in is_write_decision, so destructive removal bypassed the memory.write
trace and the PR gate. Added purge/purged/delete/deleted/forget/forgotten.
Proven live: purging a node now records a second memory.write event
({"decision":"purge"}) under the run.

Docs: REVIEW.md de-staled — removed the fixed 140b15f diff-stat / "3 commits"
prose (it moved with each fix), listed all commits, added C1/C2 to the findings
table, updated the test count.

Gates: 1002 lib tests pass (+3 new regressions), clippy -D warnings clean,
dashboard check + build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 16:05:35 -05:00
Sam Valladares
5fa0a2c848 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-24 16:05:35 -05:00
Sam Valladares
01040bc3a6 fix(blackbox): address review blockers B1–B7 + re-capture proof bundle
A full multi-agent review found 7 real issues (4 blockers). All fixed + tested.

B1 (blocker): Promoting a Memory PR did not release the quarantined memory —
the UI said "promoted" while the memory stayed suppressed/out of retrieval.
act_on_memory_pr now calls reverse_suppression(subject_id) on accept actions;
MemoryPrAction::releases_memory() encodes the rule (promote/merge/supersede
release; forget/quarantine keep it held). Proven live: PR response
subjectReleased:true, SQLite suppression_count 0.

B2 (blocker): memory promote/demote (returns `action`, not `decision`) and
codebase remember_* writes bypassed the write-trace + PR gate. extract_writes
now reads `action` too, filtered by is_write_decision (reads like get/state
excluded); is_write_tool includes `codebase`.

B3 (blocker): receipt ids collided within a run (r_<date>_<runId> +
INSERT OR REPLACE overwrote earlier receipts). IDs are now
r_<date>_<runId8>_<unique6>; build() mints the suffix, build_with_unique()
keeps tests deterministic.

B4 (blocker): proof bundle was assembled from two runs (trace.json=run_proof,
websocket-events.jsonl=run_proof2). Re-captured the whole bundle from a single
run — trace, websocket, receipt, and memory_pr all carry run_proof now.

B5: Black Box receipts panel showed global latest, not the selected run.
Added list_receipts_for_run + /api/receipts?run= ; the page uses listForRun.

B6: SENSITIVE_TOPICS substring matching false-fired (tokenizer->token,
author->auth, secretary->secret). Switched to word-boundary matching; real
phrasings (auth token, security vulnerability, api key) still gate.

B7: set_review_mode now writes atomically (temp+rename via write_atomic);
export_trace sanitizes run_id in the Content-Disposition filename; memory-prs
static routes declared before the dynamic /{id} route.

Withdrawn: the /mode-vs-/{id} route order is NOT a functional bug (axum 0.8 /
matchit prioritizes static segments) — reordered for clarity only.

Gates: 999 lib tests pass (+9 new regressions), clippy -D warnings clean,
dashboard check + build clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 16:05:35 -05:00
Sam Valladares
6c537eb85e 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-24 16:05:35 -05:00
Sam Valladares
10d2a2200a docs(blackbox): package the review bundle — REVIEW.md entry point
Freeze feature work and package the Black Box proof bundle for full review
before anything else lands (no quarantine-constellation work has started).

REVIEW.md is the single entry point: frozen public claim, the per-producer
caveat ledger (real / caveat — sanhedrin.veto stays an honest off-by-default
caveat; dream.patch is REAL but not live-by-default), and the exact command
receipts (run live at 2026-06-22T22:57:59Z, toolchain pinned) for every
validation status credited — nothing claimed from memory.

The bundle (blackbox-proof-2026-06-22/) already contains: status/trace/receipt/
memory_pr JSON, two live WebSocket captures (one with the dream.patch
TraceEvent), six screenshots (Black Box, Receipts/ReceiptCard, Memory PRs,
Graph, dream Black Box, dream producers panel), and PROOF.md. Every credited
artifact was verified to contain real content.

Review surface: 27 source files, +5830/-18 across commits 80c823a, b89beee,
140b15f (build artifacts + proof bundle excluded).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 16:05:35 -05:00
Sam Valladares
9149357485 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-24 16:05:35 -05:00
Sam Valladares
e575e684de 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-24 16:05:35 -05:00
Sam Valladares
520e6e9233 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-24 16:05:35 -05:00
Sam Valladares
9af97c5d46 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-24 16:05:35 -05:00
Sam Valladares
f97e452180 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-24 16:05:35 -05:00
Sam Valladares
be9d4509a6 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-24 16:05:35 -05:00
Sam Valladares
dca910fa01 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-24 16:05:35 -05:00
Sam Valladares
bb00cdb053 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-24 16:05:35 -05:00
Sam Valladares
d234b38133 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-24 16:05:35 -05:00
Sam Valladares
9afc79342d 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-24 16:05:35 -05:00
Sam Valladares
49b1fcdd19 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-24 16:05:35 -05:00
Sam Valladares
2b9df10951 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-24 16:05:35 -05:00
Sam Valladares
557277f598 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-24 16:05:35 -05:00
Sam Valladares
437c2b93fa 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-24 16:05:35 -05:00