vestige/CHANGELOG.md

775 lines
59 KiB
Markdown
Raw Normal View History

# Changelog
All notable changes to Vestige will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [2.1.23] - 2026-05-27 — "Receipt Lock Hardening"
v2.1.23 hardens the Sanhedrin launch path so Receipt Lock is portable,
observable, and precise enough for broader use.
### Added
- **Model-agnostic Sanhedrin backend presets** for custom OpenAI-compatible
servers, small laptops, Ollama, MLX, vLLM, llama.cpp, hosted APIs, and
Anthropic via LiteLLM. Sanhedrin no longer guesses a large default verifier.
- **Fail-open telemetry** in `fail-open.jsonl`, plus a dashboard telemetry API
and 7-day ambient dashboard counters for vetoes, appeals, and fail-open runs.
- **Receipt schema documentation** covering receipt artifacts, appeals, command
ledgers, fail-open logs, compatibility rules, and staged-evidence trust
boundaries.
- **Opt-in CUDA feature flags** for Qwen3 embedding builds on NVIDIA hardware.
### Changed
- Receipt Lock strips code fences, inline code, blockquotes, quoted regions, and
scoped epistemic hedges before matching verification claims.
- Structured transcript tool-use receipts are the default evidence path; loose
JSON command scanning now requires `VESTIGE_SANHEDRIN_ALLOW_LOOSE_LEDGER=1`.
- Claim-mode sampling now prioritizes higher-severity claims instead of taking
the first eight source-order claims.
- Hosted Sanhedrin credentials now require `VESTIGE_SANHEDRIN_API_KEY` and are
only sent to the configured Sanhedrin endpoint, never to Vestige retrieval.
- `smart_ingest` batch mode now defaults to `batchMergePolicy: "force_create"`
so caller-separated items stay separate unless callers opt into smart merging.
- CUDA-enabled Qwen3 builds now try `Device::new_cuda(0)` before falling back to
Metal or CPU.
### Fixed
- Standalone dashboard mode now hydrates the cognitive engine for Dream and
Deep Reference instead of returning 503s.
- `--data-dir` now rejects existing non-directory paths with a clear error.
- `vestige-restore` now handles `--help` and `--version` instead of treating
them as backup file paths.
- Smart ingest merge/update responses now include `previousContent`,
`mergedFrom`, and `mergePreview` so callers can inspect mutated memories.
- Daily Sanhedrin telemetry now preserves NOTE and CAUTION buckets instead of
folding both into PASS.
## [2.1.22] - 2026-05-25 — "Sanhedrin Receipts"
v2.1.22 makes the optional Sanhedrin hook quieter and more accountable by
turning draft judgment into local, appealable receipts instead of opaque vetoes.
### Added
- **Receipt Lock** blocks unsupported verification claims such as "tests passed"
unless the current transcript contains a matching successful test, build,
lint, or typecheck command receipt.
- **Veto receipts** are written to `~/.vestige/sanhedrin/latest.json` and
`latest.html` with Claim -> Verdict -> Precedent -> Fix -> Appeal fields.
- **Dashboard Verdict Bar** surfaces the latest PASS, NOTE, CAUTION, VETO, or
APPEALED state and lets users appeal stale, wrong, or too-strict vetoes.
- **Appeal training** records feedback in `appeals.jsonl` and suppresses future
vetoes for the same claim fingerprint.
### Changed
- Sanhedrin claim-mode output now feeds a per-claim receipt ledger while keeping
the existing one-line Stop-hook contract for Claude Code.
## [2.1.21] - 2026-05-24 — "Agent-Neutral Hardening"
v2.1.21 is a release-hardening pass for normal MCP usage across agents. It keeps
Claude Code Cognitive Sandwich companion files optional while making the MCP
server, package installer, release workflow, and portable sync path safer.
### Added
- **Agent-neutral memory protocol** — new `docs/AGENT-MEMORY-PROTOCOL.md` gives
any MCP-compatible client the same practical memory loop: initialize context,
search/deep-reference when needed, save durable facts with `smart_ingest`, and
promote/demote/purge with `memory`.
- **HTTP transport opt-in** — `vestige-mcp` now requires `--http`,
`--http-port`, or `VESTIGE_HTTP_ENABLED=1` before starting MCP-over-HTTP.
- **Release checksums** — release assets now publish `.sha256` files beside each
archive.
### Changed
- **`vestige update` is binary-only by default** — Claude Code Cognitive
Sandwich companion files refresh only with `vestige update --sandwich-companion`
or `vestige sandwich install`.
- **MCP tool results include structured content** while keeping text content for
clients that only consume the classic MCP response shape.
- **NPM install messaging is agent-neutral** and unsupported release targets
fail fast instead of trying to download assets that do not exist.
- **Portable merge uses UPSERT instead of `INSERT OR REPLACE`** for keyed tables,
preserving related rows instead of causing delete-and-insert side effects.
### Fixed
- **Destructive delete confirmation** — `memory(action="delete")` now requires
`confirm=true`, matching `purge`; the deprecated `delete_knowledge` shim no
longer bypasses confirmation.
- **Portable purge tombstone sync** — merge imports now carry
`deletion_tombstones` and apply purges without retaining deleted memory text.
Hard purge tombstones win over newer local edits during portable sync, while
tombstone merges keep the newest deletion timestamp.
- **Vector index reload staleness** — loading persisted embeddings rebuilds the
in-memory index from an empty index before adding current embeddings.
- **HTTP transport hardening** — origin, Accept, session, and protocol-version
validation now reject incompatible or cross-origin browser requests earlier.
- **Init config safety** — `@vestige/init` backs up existing config files, writes
atomically, accepts JSONC-style comments/trailing commas, and no longer writes
Xcode trust-accepted flags.
- **Release tag checkout** — manual release builds now checkout the requested tag
or ref before packaging.
### Verified
- `cargo test -p vestige-mcp --lib --no-fail-fast`
- `cargo test -p vestige-mcp --bin vestige-mcp --no-fail-fast`
- `cargo test -p vestige-core portable_merge_import --no-fail-fast`
- `cargo test -p vestige-mcp --bin vestige --no-fail-fast`
- `cargo test -p vestige-e2e-tests --test mcp_protocol --no-fail-fast`
- `cargo check --workspace`
- `cargo metadata --format-version 1 --locked --no-deps`
- `pnpm --filter @vestige/dashboard check`
- `pnpm --filter @vestige/dashboard test`
- `pnpm --filter @vestige/dashboard build`
- `node --check packages/vestige-init/bin/init.js`
- `node --check packages/vestige-mcp-npm/scripts/postinstall.js`
- `node --check packages/vestige-mcp-npm/bin/vestige-restore.js`
## [2.1.2] - 2026-05-01 — "Honest Memory"
v2.1.2 focuses on operational trust: exact search stays exact, purge really removes content, contradictions are directly inspectable, and the update flow no longer depends on copied curl commands.
### Added
- **Concrete search mode** — `search` now auto-detects literal queries such as quoted strings, env vars, UUIDs, paths, and code identifiers. Those queries take a keyword/literal path that skips HyDE, semantic fusion, FSRS reweighting, retrieval competition, and spreading activation so exact matches land first.
- **Irreversible purge** — `memory(action="purge", confirm=true)` permanently removes memory content and embeddings, scrubs `insights.source_memories`, detaches temporal-summary children, prunes graph edges, and writes only a non-content `deletion_tombstones` row for sync/audit.
- **First-class contradictions tool** — new `contradictions` MCP tool scans a topic or recent memories for trust-weighted disagreements using the same local contradiction logic as `deep_reference`.
- **Simple update flow** — `vestige update` refreshes the installed binary and companion Sandwich files without requiring users to paste a curl installer.
- **Pro waitlist preview** — `/dashboard/waitlist` adds a local-only marketing surface for Solo Pro and Team Pro early-access signups. `VITE_WAITLIST_ENDPOINT` and `VITE_SUPPORT_BOT_ENDPOINT` are opt-in dashboard env vars, so no signup data is captured unless endpoints are configured.
### Fixed
- **Dream connection persistence cap** — dense single-domain dreams now persist every connection discovered in that run instead of losing everything beyond the old 1,000-entry live buffer. The live dreamer buffer now keeps up to 200,000 high-scoring recent connections, and the MCP `dream` tool exposes `min_similarity` for corpus-specific tuning.
- **Embedding-model upgrade repair** — `vestige consolidate` now re-embeds every missing or active-model-mismatched memory in one pass, so v1/v2 mixed stores are no longer left partially unreachable after only the first 100 legacy embeddings are regenerated.
2026-05-01 05:24:03 -05:00
## [2.1.1] - 2026-05-01 — "Portable Sync"
v2.1.1 focuses on user-controlled portability: exact storage archives, merge-safe file sync, pluggable sync backends, and explicit hook opt-ins.
### Added
- **Exact portable archives** — `vestige portable-export` / `vestige portable-import` preserve raw Vestige storage rows: memory IDs, FSRS state, graph edges, suppression state, audit rows, sessions, intentions, and embedding blobs.
- **Merge-safe imports** — `vestige portable-import --merge` can merge into non-empty databases. It applies `sync_tombstones`, keeps newer local memory rows on timestamp conflicts, preserves stable IDs, and rebuilds FTS after import.
- **File-backed two-way sync** — `vestige sync <archive>` performs pull-merge-push through a shared portable archive. This works today with Dropbox, iCloud Drive, Syncthing, Git, network shares, and shared folders.
- **Pluggable portable-sync backend trait** — core now exposes `PortableSyncBackend`, `FilePortableSyncBackend`, and `PortableSyncReport`, so non-file backends can reuse the same merge semantics without reimplementing conflict handling.
- **Portable restore merge mode** — the MCP `restore` tool accepts `merge: true` for portable archives and returns inserted/updated/deleted/skipped/conflict counts.
- **Qwen3 embedding opt-in** — build-time and runtime support for Qwen3 embeddings, with model-aware retrieval safeguards so mixed embedding models are not compared in the same vector path.
### Fixed
- **Sanhedrin, preflight, and all Vestige Claude Code hooks are optional again.** The Cognitive Sandwich installer now activates no hooks by default and leaves every preflight hook, every Stop hook, the MLX launchd service, and the 19 GB Qwen model path behind explicit `--enable-preflight`, `--enable-sanhedrin`, or `--with-launchd` flags.
- **x86-friendly Sanhedrin path.** The verifier bridge now accepts any OpenAI-compatible chat endpoint via `VESTIGE_SANHEDRIN_ENDPOINT` and `VESTIGE_SANHEDRIN_MODEL`, so Linux and Intel Mac users can opt in without MLX or Apple Silicon.
### Verified
- `cargo test -p vestige-core portable --no-fail-fast`
- `cargo test -p vestige-mcp portable --no-fail-fast`
- `cargo test --workspace --no-fail-fast`
- Installer shell/Python/JSON validation and default/preflight/Sanhedrin migration dry-runs.
2026-04-27 13:20:51 -05:00
## [2.1.0] - 2026-04-27 — "Cognitive Sandwich Goes Local"
2026-05-01 05:24:03 -05:00
v2.1.0 ships the Cognitive Sandwich hook harness for Claude Code, with a hotfix that makes every hook layer opt-in. The default installer stages files, removes old Vestige hook wiring, starts no MLX service, downloads no model, and makes no automatic model calls. Users can opt into preflight context, Sanhedrin verification, or the Apple Silicon MLX backend separately.
2026-04-27 13:20:51 -05:00
### Added
- **`hooks/`** — first-class harness-side companion to the Vestige MCP server. 9 production hooks designed for `~/.claude/hooks/`:
- `sanhedrin.sh` — Stop hook that invokes the local Qwen Executioner via the Python bridge.
- `sanhedrin-local.py` — local backend that POSTs to `mlx_lm.server` (`localhost:8080`) with Vestige evidence injected via the dashboard `/api/deep_reference` HTTP endpoint. TRUST_FLOOR=0.55 evidence filter + topical-relevance gate + inference-verb ban + 8 worked few-shots covering true positives AND false-positive guards.
- `synthesis-preflight.sh` — UserPromptSubmit hook that POSTs the user prompt to `/api/deep_reference` and injects the trust-scored reasoning chain into context.
- `cwd-state-injector.sh` — captures git status, branch, modified files, open PRs/issues.
- `vestige-pulse-daemon.sh` — surfaces fresh Vestige dream insights from the past 20 min.
- `preflight-swarm.sh` — spawns the `lateral-thinker` subagent in fresh context for cross-disciplinary structural parallels.
- `synthesis-stop-validator.sh` — Stop hook regex against forbidden hedging patterns.
- `veto-detector.sh` — fast 50ms regex pre-screen against `veto`-tagged Vestige memories.
- `synthesis-gate.sh` — legacy v1 trigger (kept for backward compat).
2026-05-01 05:24:03 -05:00
- `settings.fragment.json` — empty default JSON snippet; the installer only wires hooks from the opt-in preflight/Sanhedrin fragments.
2026-04-27 13:20:51 -05:00
- **Dashboard `/api/changelog` endpoint** — bounded REST event feed for recent `DreamCompleted` and `ConnectionDiscovered` events, used by the Pulse hook to inject fresh synthesis into Claude Code context.
- **`agents/`** — `executioner.md` (legacy/fallback Haiku 4.5 path), `lateral-thinker.md`, `synthesis-composer.md`.
- **`launchd/com.vestige.mlx-server.plist.template`** — auto-start `mlx_lm.server` with the Qwen3.6-35B-A3B-4bit model on login. Templated with `__HOME__` and `__MODEL__` placeholders.
2026-05-01 05:24:03 -05:00
- **`scripts/install-sandwich.sh`** — one-command installer that stages hooks and agents, removes old Vestige hook wiring by default, and only wires optional layers with `--enable-preflight`, `--enable-sanhedrin`, or `--with-launchd`. Backs up `settings.json` to `.bak.pre-sandwich`. Supports `--force`, `--include-memory-loader`, and `--src=PATH`.
- **`scripts/check-sandwich-prereqs.sh`** — default verifier confirms no Vestige Claude Code hooks are wired. Optional `--preflight` and `--sanhedrin` modes check the corresponding enabled layer.
2026-04-27 13:20:51 -05:00
- **`docs/COGNITIVE_SANDWICH.md`** — architecture diagram, install guide, performance notes (82 tok/s on M3 Max), uninstall, configuration env vars.
- **PR #48** — `VESTIGE_DATA_DIR` env-var support + tilde expansion + secure unix perms (thanks @Jelloeater) — directly addresses the ghost env-vars exposed by v2.0.9 cleanup.
### Changed
2026-05-01 05:24:03 -05:00
- **Sanhedrin Executioner backend can run locally or remotely when explicitly enabled.** The bridge targets an OpenAI-compatible chat endpoint, with local `mlx_lm.server` + Qwen3.6-35B-A3B-4bit available behind `--with-launchd` on Apple Silicon. Anthropic API key no longer required for the post-cognitive layer. The `executioner.md` agent definition is retained as manual/fallback only when invoked explicitly via `Task(subagent_type='executioner')`.
2026-04-27 13:20:51 -05:00
- **All hooks sanitized for public release** — replaced hardcoded personal absolute paths with `$HOME` / `$VESTIGE_*` env vars; removed personal regex tokens.
- **NPM binary installer now follows package version** — `vestige-mcp-server@2.1.0` downloads release assets from `v2.1.0` instead of a stale hardcoded binary tag, while local workspace installs skip the release-asset download before the tag exists.
### Verified
- `cargo test --workspace --release --no-fail-fast`: **1,229 passing, 0 failed** (366 vestige-core + 358 vestige-mcp lib + 4 vestige-mcp bin + 497 e2e + 4 doctests).
- Sanhedrin bridge smoke checks: Python bytecode compilation passes, fail-open bridge invocation returns `yes`, and public hook settings validate as JSON.
2026-05-01 05:24:03 -05:00
- v2.1.0 hotfix installer matrix: default, preflight-only, Sanhedrin-only, full sandwich, legacy-all-hooks migration, and unrelated custom hooks preservation.
2026-04-27 13:20:51 -05:00
- 8-day Sandwich dogfood: **84% pass rate, 16% legitimate vetoes** caught real hallucinations.
### Closes
- #36 (Agent Hooks for Low-Effort Automatic Memory Capture) — Cognitive Sandwich is the answer.
2026-05-01 05:24:03 -05:00
### Prerequisites for optional local MLX Sanhedrin
2026-04-27 13:20:51 -05:00
2026-05-01 05:24:03 -05:00
- macOS Apple Silicon (M1+) — required only for `--with-launchd` MLX autostart
2026-04-27 13:20:51 -05:00
- Python 3.10+
- ~22 GB free RAM (Qwen3.6-35B-A3B-4bit at runtime)
- First-run model download: ~19 GB from Hugging Face (cached locally thereafter)
### Migration
2026-05-01 05:24:03 -05:00
None required for existing Vestige users. The Cognitive Sandwich is opt-in via `scripts/install-sandwich.sh`; running the default installer removes old Vestige hook wiring and leaves preflight, Sanhedrin, launchd, and the 19 GB model path disabled. The MCP server, schema, and tool surface are bit-identical to v2.0.9.
2026-04-27 13:20:51 -05:00
---
v2.0.9 "Autopilot" — backend event-subscriber + 3,091 LOC orphan cleanup (#46) * feat(v2.0.9): Autopilot — backend event-subscriber routes 6 live events into cognitive hooks The single architectural change that flips 14 dormant cognitive primitives into active ones. Before this commit, Vestige's 20-event WebSocket bus had zero backend subscribers — every emitted event flowed to the dashboard animation layer and terminated. Cognitive modules with fully-built trigger methods (synaptic_tagging.trigger_prp, predictive_memory.record_*, activation_network.activate, prospective_memory.check_triggers, the 6h auto-consolidation dreamer path) were never actually called from the bus. New module `crates/vestige-mcp/src/autopilot.rs` spawns two tokio tasks at startup: 1. Event subscriber — consumes the broadcast::Receiver, routes: - MemoryCreated → synaptic_tagging.trigger_prp(CrossReference) + predictive_memory.record_memory_access(id, preview, tags) - SearchPerformed → predictive_memory.record_query(q, []) + record_memory_access on top 10 result_ids - MemoryPromoted → activation_network.activate(id, 0.3) spread - MemorySuppressed → emit Rac1CascadeSwept (was declared-never-emitted) - ImportanceScored (composite > 0.85 AND memory_id present) → storage.promote_memory + re-emit MemoryPromoted - Heartbeat (memory_count > 700, 6h cooldown) → spawned find_duplicates sweep (rate-limited) The loop holds the CognitiveEngine mutex only per-handler, never across an await, so MCP tool dispatch is never starved. 2. Prospective poller — 60s tokio::interval calls prospective_memory.check_triggers(Context { timestamp: now, .. }). Matched intentions are logged at info! level today; v2.5 "Autonomic" upgrades this to MCP sampling/createMessage for agent-side notifications. ImportanceScored event gained optional `memory_id: Option<String>` field (#[serde(default)], backward-compatible) so auto-promote has the id to target. Both existing emit sites (server.rs tool dispatch, dashboard handlers::score_importance) pass None because they score arbitrary content, not stored memories — matches current semantics. docs/VESTIGE_STATE_AND_PLAN.md §15 POST-v2.0.8 ADDENDUM records the full three-agent audit that produced this architecture (2026-SOTA research, active-vs-passive module audit, competitor landscape), the v2.0.9/v2.5/v2.6 ship order, and the one-line thesis: "the bottleneck was one missing event-subscriber task; wiring it flips Vestige from memory library to cognitive agent that acts on the host LLM." Verified: - cargo check --workspace clean - cargo clippy --workspace -- -D warnings clean (let-chain on Rust 1.91+) - cargo test -p vestige-mcp --lib 356/356 passing, 0 failed * fix(autopilot): supervisor + dedup race + opt-out env var Three blockers from the 5-agent v2.0.9 audit, all in autopilot.rs. 1. Supervisor loops around both tokio tasks (event subscriber + prospective poller). Previously, if a cognitive hook panicked on a single bad memory, the spawned task died permanently and silently — every future event lost. Now the outer supervisor catches JoinError::is_panic(), logs the panic with full error detail, sleeps 5s, and respawns the inner task. Turns a permanent silent failure into a transient hiccup. 2. DedupSweepState struct replaces the bare Option<Instant> timestamp. It tracks the in-flight JoinHandle so the next Heartbeat skips spawning a second sweep while the first is still running. Previously, the cooldown timestamp was set BEFORE spawning the async sweep, which allowed two concurrent find_duplicates scans on 100k+ memory DBs where the sweep could exceed the 6h cooldown window. is_running() drops finished handles so a long-dead sweep doesn't block the next legitimate tick. 3. VESTIGE_AUTOPILOT_ENABLED=0 opt-out. v2.0.8 users updating in place can preserve the passive-library contract by setting the env var to any of {0, false, no, off}. Any other value (unset, 1, true, etc.) enables the default v2.0.9 Autopilot behavior. spawn() early-returns with an info! log before any task is spawned. Audit breakdown: - Agent 1 (internals): NO-GO → fixed (1, 2) - Agent 2 (backward compat): NO-GO → fixed (3) - Agent 3 (orphan cleanup): GO clean - Agent 4 (runtime safety): GO clean - Agent 5 (release prep): GO, procedural note logged Verification: - cargo check -p vestige-mcp: clean - cargo test -p vestige-mcp --lib: 373 passed, 0 failed - cargo clippy -p vestige-mcp --lib --bins -- -D warnings: clean * chore(release): v2.0.9 "Autopilot" Bump workspace + vestige-core + vestige-mcp + apps/dashboard to 2.0.9. CHANGELOG [2.0.9] entry + README hero banner rewrite to "Autopilot". Scope (two commits on top of v2.0.8): - 0e9b260: 3,091 LOC orphan-code cleanup - fe7a68c: Autopilot backend event-subscriber - HEAD (this branch): supervisor + dedup race + opt-out env var hardening Pure backend release — tool count unchanged (24), schema unchanged, JSON-RPC shape unchanged, CLI flags unchanged. Only visible behavior change is the Autopilot task running in the background, which is VESTIGE_AUTOPILOT_ENABLED=0-gated. Test gate: 1,223 passing / 0 failed (workspace, no-fail-fast). Clippy: clean on vestige-mcp lib + bins with -D warnings. Audit: 5 parallel agents (internals, backward compat, orphan cleanup, runtime safety, release prep) — all GO after hardening commit.
2026-04-24 02:00:00 -05:00
## [2.0.9] - 2026-04-24 — "Autopilot"
Autopilot flips Vestige from passive memory library to self-managing cognitive surface. A single supervised backend task subscribes to the 20-event WebSocket bus and routes live events into the cognitive engine — 14 previously dormant primitives (synaptic tagging, predictive memory, activation spread, prospective polling, auto-consolidation, Rac1 cascade emission) now fire without any MCP tool call. Shipped alongside a 3,091-LOC orphan-code cleanup of the v1.0 tool surface. **No schema changes, tool surface unchanged (24 tools), fully backward compatible with v2.0.8 databases. Opt-out via `VESTIGE_AUTOPILOT_ENABLED=0`.**
### Added
- **Autopilot event subscriber** (`crates/vestige-mcp/src/autopilot.rs`) — two supervised tokio tasks spawned at startup. The event subscriber consumes a `broadcast::Receiver<VestigeEvent>` and routes six event classes:
- `MemoryCreated``synaptic_tagging.trigger_prp()` (9h retroactive PRP window, Frey & Morris 1997) + `predictive_memory.record_memory_access()`.
- `SearchPerformed``predictive_memory.record_query()` + top-10 access records. The speculative-retrieval model now warms without waiting for an explicit `predict` call.
- `MemoryPromoted``activation_network.activate(id, 0.3)` — a small reinforcement ripple through the graph.
- `MemorySuppressed` → re-emits the previously-declared-never-emitted `Rac1CascadeSwept` event so the dashboard's cascade wave actually renders.
- `ImportanceScored` with `composite_score > 0.85` AND a stored `memory_id` → auto-promote + re-emit `MemoryPromoted`.
- `Heartbeat` with `memory_count > 700` → rate-limited `find_duplicates` sweep (6h cooldown + in-flight `JoinHandle` guard against concurrent scans on large DBs).
The engine mutex is acquired only synchronously per handler and never held across `.await`, so MCP tool dispatch is never starved. A 60-second `tokio::interval` separately polls `prospective_memory.check_triggers(Context)` — matched intentions log at `info!` level today; v2.1 "Autonomic" will surface them mid-conversation.
- **Panic-resilient supervisors** — both background tasks run inside an outer supervisor loop. If a cognitive hook panics on one bad memory, the supervisor catches `JoinError::is_panic()`, logs the panic, sleeps 5 s, and respawns the inner task. Turns a permanent silent-failure mode into a transient hiccup.
- **`VESTIGE_AUTOPILOT_ENABLED=0` opt-out** — v2.0.8 users who want the passive-library contract can disable Autopilot entirely. Values `{0, false, no, off}` early-return before any task spawns; anything else (unset, `1`, `true`) enables the default v2.0.9 behavior.
- **`ImportanceScored.memory_id: Option<String>`** — new optional field on the event variant (`#[serde(default)]`, backward-compatible) so Autopilot's auto-promote path can target a stored memory. Existing emit sites pass `None`.
### Changed
- **3,091 LOC of orphan tool code removed** from `crates/vestige-mcp/src/tools/` — nine v1.0 modules (`checkpoint`, `codebase`, `consolidate`, `ingest`, `intentions`, `knowledge`, `recall`, plus two internal helpers) superseded by the `*_unified` / `maintenance::*` replacements shipped in v2.0.5. Each module verified for zero non-test callers before removal. Tool surface unchanged — all 24 tools continue to work via the unified dispatchers.
- **Ghost environment-variable documentation scrubbed** — three docs listed env vars (`VESTIGE_DATA_DIR`, `VESTIGE_LOG_LEVEL`, a `VESTIGE_API_KEY` typo) that never existed in any shipping Rust code. Replaced with the real variables the binary actually reads.
### Fixed
- **Dedup-sweep race on large databases** — the `Heartbeat`-triggered `find_duplicates` sweep previously set its cooldown timestamp BEFORE spawning the async scan, which on 100k+ memory DBs (where a sweep can exceed the 6h cooldown) allowed two concurrent scans. Rewritten to track the in-flight `JoinHandle` via `DedupSweepState::is_running()` — the next Heartbeat skips if the previous sweep is still live.
### Verified
- `cargo test --workspace --no-fail-fast`: **1,223 passing, 0 failed**.
- `cargo clippy -p vestige-mcp --lib --bins -- -D warnings`: clean.
- Five-agent parallel audit (security, dead-code, flow-trace, runtime-safety, release-prep): all GO.
### Migration
None. v2.0.9 is a pure backend upgrade — tool surface, JSON-RPC schema, storage schema, and CLI flags are bit-identical to v2.0.8. Existing databases open without any migration step. The only behavior change is the Autopilot task running in the background, which is `VESTIGE_AUTOPILOT_ENABLED=0`-gated if you want the old passive-library contract.
v2.0.8 Pulse — Reasoning Theater + Pulse Toast + Terrarium + Intel Mac (#44) * docs: anti-hedging banner + master state-and-plan + UI roadmap Project-level CLAUDE.md line 1 is now the anti-hedging banner referencing the global rule at /Users/entity002/CLAUDE.md. When Sam commits to an execution path (content cadence, shipping velocity, outreach, launch), forecasts compute as if the commitment is already met — no discounting by execution probability. VESTIGE_STATE_AND_PLAN.md (1135 lines, 14 parts): single-page reference any AI agent can read to plan the next phase without re-reading the repo. Covers current state of every crate, the 24 MCP tools, the 19 WebSocket event types, the 8 IDE integrations, and v2.1 through v3.0 roadmap. UI_ROADMAP_v2.1_v2.2.md: compiled UI-gap analysis from 4 parallel research agents (April 19). 10 critical UI gaps + 2026 bleeding-edge patterns + unclaimed territory (menu bar widget, voice-first, AR/VR, time-scrubber). * feat(v2.2-pulse): InsightToast + multi-process STORAGE docs Two independent ship items landing together on the v2.2 branch ahead of the Tuesday launch — a new UI surface that makes Vestige's cognitive events visible in real time, and honest documentation of the multi-process safety story that underpins the Stigmergic Swarm narrative. **InsightToast** (apps/dashboard/src/lib/components/InsightToast.svelte, apps/dashboard/src/lib/stores/toast.ts): The dashboard already had a working WebSocket event stream on ws://localhost:3927/ws that broadcast every cognitive event (dream completions, consolidation sweeps, memory promotions/demotions, active- forgetting suppression and Rac1 cascades, bridge discoveries). None of that was surfaced to a user looking at anything other than the raw feed view. InsightToast subscribes to the existing eventFeed derived store, filters the spammy lifecycle events (Heartbeat, SearchPerformed, RetentionDecayed, ActivationSpread, ImportanceScored, MemoryCreated), and translates the narrative events into ephemeral toasts with a bioluminescent colored accent matching EVENT_TYPE_COLORS. Design notes: - Rate-limited ConnectionDiscovered at 1.5s intervals (dreams emit many). - Max 4 visible toasts, auto-dismiss at 4.5-7s depending on event weight. - Click or Enter/Space to dismiss early. - Bottom-right on desktop, top-banner on mobile. - Reduced-motion honored via prefers-reduced-motion. - Zero new websocket subscriptions — everything piggybacks on the existing derived store. Also added a "Preview Pulse" button to Settings -> Cognitive Operations that fires a synthetic sequence of four toasts (DreamCompleted, ConnectionDiscovered, MemorySuppressed, ConsolidationCompleted) so the animation is demoable without waiting for real cognitive activity. **Multi-Process Safety section in docs/STORAGE.md**: Grounds the Stigmergic Swarm story with concrete tables of what the current WAL + 5s busy_timeout configuration actually supports vs what remains experimental. Key honest points: - Shared --data-dir + ONE vestige-mcp + N clients is the shipping pattern for multi-agent coordination. - Two vestige-mcp processes writing the same file is experimental — documented with the lsof + pkill recovery path. - Roadmap lists the three items that would promote it to "supported": advisory file lock, retry-with-jitter on SQLITE_BUSY, and a concurrent-writer load test. Build + typecheck: - npm run check: 0 errors, 0 warnings across 583 files - npm run build: clean static build, adapter-static succeeds * feat(v2.3-terrarium): Memory Birth Ritual + event pipeline fix v2.3 "Terrarium" headline feature. When a MemoryCreated event arrives, a glowing orb materialises in the cosmic center (camera-relative z=-40), gestates for ~800ms growing from a tiny spark into a full orb, then arcs along a dynamic quadratic Bezier curve to the live position of the real node, and on arrival hands off to the existing RainbowBurst + Shockwave + RippleWave cascade. The target position is re-resolved every frame so the force simulation can move the destination during flight without the orb losing its mark. **New primitive — EffectManager.createBirthOrb()** (effects.ts): Accepts a camera, a color, a live target-position getter, and an arrival callback. Owns a sprite pair (outer halo + inner bright core), both depthTest:false with renderOrder 999/1000 so the orb is always visible through the starfield and the graph. - Gestation phase: easeOutCubic growth + sinusoidal pulse, halo tints from neutral to event color as the ritual charges. - Flight phase: QuadraticBezierCurve3 with control point at midpoint raised on Y by 30 + 15% of orb-to-target distance (shooting-star arc). Sampled with easeInOutQuad. Orb shrinks ~35% approaching target. - Arrival: fires onArrive callback once, then fades out over 8 frames while expanding slightly (energy dispersal). - Caller's onArrive triggers the burst cascade at arrivePos (NOT the original spawnPos — the force sim may have moved the target during the ritual, so we re-read nodeManager.positions on arrival). - Dispose path integrated with existing EffectManager.dispose(). **Event pipeline fix — Graph3D.processEvents()**: Previously tracked `processedEventCount` assuming APPEND order, but websocket.ts PREPENDS new events (index 0) and caps the array at MAX_EVENTS. Result: only the first MemoryCreated event after page load fired correctly; subsequent ones reprocessed the oldest entry. Fixed to walk from index 0 until hitting the last-processed event by reference identity — correct regardless of array direction or eviction pressure. Events are then processed oldest-first so causes precede effects. Found while wiring the v2.3 demo button; would have manifested as "first orb only" in production. **Demo trigger** (Settings -> Birth Ritual Preview): Button that calls websocket.injectEvent() with a synthetic MemoryCreated event, cycling through node types (fact / concept / pattern / decision / person / place) to showcase the type-color mapping. Downstream consumers can't distinguish synthetic from real, so this drives the full ritual end-to-end. Intended for demo clip recording for the Wednesday launch. **Test coverage:** - events.test.ts now tests the v2.3 birth ritual path: spawns 2+ sprites in the scene immediately, and fires the full arrival cascade after driving the effects.update() loop past the ritual duration. - three-mock.ts extended with Vector3.addVectors, Vector3.applyQuaternion, Color.multiplyScalar, Quaternion, QuadraticBezierCurve3, Texture, and Object3D.quaternion/renderOrder so production code runs unaltered in tests. Build + typecheck: - npm run check: 0 errors, 0 warnings across 583 files - npm test: 251/251 pass (net +0 from v2.2) - npm run build: clean adapter-static output The Sanhedrin Shatter (anti-birth ritual for hallucination veto) needs server-side event plumbing and is deferred. Ship this as the Wednesday visual mic-drop. * fix(v2.3): 5 FATAL bugs + 4 god-tier upgrades from post-ship audit Post-ship audit surfaced 6 FATALs and 4 upgrades. Shipping 5 of the 6 + all 4 upgrades. FATAL 4 (VRAM hemorrhage from un-pooled label canvases in createTextSprite) is pre-existing, not from this session, and scoped separately for a proper texture-pool refactor. **FATAL 1 — Toast Silent Lobotomy** (stores/toast.ts) Subscriber tracked events[0] only. When Svelte batched multiple events in one update tick (swarm firing DreamCompleted + ConnectionDiscovered within the same millisecond), every event but the newest got silently dropped. Fixed to walk from index 0 until hitting lastSeen — same pattern as Graph3D.processEvents. Processes oldest-first to preserve narrative order. **FATAL 2 — Premature Birth** (graph/nodes.ts + graph/events.ts) Orb flight is 138 frames; materialization was 30 frames. Node popped fully grown ~100 frames before orb arrived — cheap UI glitch instead of a biological birth. Added `addNode(..., { isBirthRitual: true })` option that reserves the physics slot but hides mesh/glow/label and skips the materializing queue. New `igniteNode(id)` flips visibility and enqueues materialization. events.ts onArrive now calls igniteNode at the exact docking moment, so the elastic spring-up peaks on impact. **FATAL 3 — 120Hz ProMotion Time-Bomb** (components/Graph3D.svelte) All physics + effect counters are frame-based. On a 120Hz display every ritual ran at 2x speed. Added a `lastTime`-based governor in animate() that early-returns if dt < 16ms, clamping effective rate to ~60fps. `- (dt % 16)` carry avoids long-term drift. Zero API changes; tonight's fast fix until physics is rewritten to use dt. **FATAL 5 — Bezier GC Panic** (graph/effects.ts birth-orb update) Flight phase allocated a new Vector3 (control point) and a new QuadraticBezierCurve3 every frame per orb. With 3 orbs in flight that's 360 objects/sec for the GC to collect. Rewrote as inline algebraic evaluation — zero allocations per frame, identical curve. **FATAL 6 — Phantom Shockwave** (graph/events.ts) A 166ms setTimeout fired the 2nd shockwave. If the user navigated away during that window the scene was disposed, the timer still fired, and .add() on a dead scene threw unhandled rejection. Dropped the setTimeout entirely; both shockwaves fire immediately in onArrive with different scales/colors for the same layered-crash feel. **UPGRADE 1 — Sanhedrin Shatter** (graph/effects.ts birth-orb update) If getTargetPos() returns undefined AFTER gestation (target node was deleted mid-ritual — Stop hook sniping a hallucination), the orb turns blood-red, triggers a violent implosion in place, and skips the arrival cascade. Cognitive immune system made visible. **UPGRADE 2 — Newton's Cradle** (graph/events.ts onArrive) On docking the target mesh's scale gets bumped 1.8×, so the elastic materialization + force-sim springs physically recoil instead of the orb landing silently. The graph flinches when an idea is born into it. **UPGRADE 3 — Hover Panic** (stores/toast.ts + InsightToast.svelte) Paused dwell timer on mouseenter/focus, resume on mouseleave/blur. Stored remaining ms at pause so resume schedules a correctly-sized timer. CSS pairs via `animation-play-state: paused` on the progress bar. A toast the user is reading no longer dismisses mid-sentence. **UPGRADE 4 — Event Horizon Guard** (components/Graph3D.svelte) If >MAX_EVENTS (200) events arrive in one tick, lastProcessedEvent falls off the end of the array and the walk consumes ALL 200 entries as "fresh" — GPU meltdown from 200 simultaneous births. Detect the overflow and drop the batch with a console.warn, advancing the high-water mark so next frame is normal. Build + test: - npm run check: 0 errors, 0 warnings - npm test: 251/251 pass - npm run build: clean static build * test(v2.3): full e2e + integration coverage for Pulse + Birth Ritual Post-ship verification pass — five parallel write-agents produced 229 new tests across vitest units, vitest integration, and Playwright browser e2e. Net suite: 361 vitest pass (up from 251, +110) and 9/9 Playwright pass on back-to-back runs. **toast.test.ts (NEW, 661 lines, 42 tests)** Silent-lobotomy batch walk proven (multi-event tick processes ALL, not just newest, oldest-first ordering preserved). Hover-panic pause/resume with remaining-ms math. All 9 event type translations asserted, all 11 noise types asserted silent. ConnectionDiscovered 1500ms throttle. MAX_VISIBLE=4 eviction. clear() tears down all timers. fireDemoSequence staggers 4 toasts at 800ms intervals. vi.useFakeTimers + vi.mock of eventFeed; vi.resetModules in beforeEach for module-singleton isolation. **websocket.test.ts (NEW, 247 lines, 30 tests)** injectEvent adds to front, respects MAX_EVENTS=200 with FIFO eviction, triggers eventFeed emissions. All 6 derived stores (isConnected, heartbeat, memoryCount, avgRetention, suppressedCount, uptimeSeconds) verified — defaults, post-heartbeat values, clearEvents preserves lastHeartbeat. 13 formatUptime boundary cases (0/59/60/3599/3600/ 86399/86400 seconds + negative / NaN / ±Infinity). **effects.test.ts (EXTENDED, +501 lines, +21 tests, 51 total)** createBirthOrb full lifecycle — sprite count (halo + core), cosmic center via camera.quaternion, gestation phase (position lock, opacity rise, scale easing, color tint), flight Bezier arc above linear midpoint at t=0.5, dynamic mid-flight target redirect. onArrive fires exactly once at frame 139. Post-arrival fade + disposal cleans scene children. Sanhedrin Shatter: target goes undefined mid-flight → onArrive NEVER called, implosion spawned, halo blood-red, eventual cleanup. dispose() cleans active orbs. Multiple simultaneous orbs. Custom gestation/flight frame opts honored. Zero-alloc invariant smoke test (6 orbs × 150 frames, no leaks). **nodes.test.ts (EXTENDED, +197 lines, +10 tests, 42 total)** addNode({isBirthRitual:true}) hides mesh/glow/label immediately, stamps birthRitualPending sentinel with correct totalFrames + targetScale, does NOT enqueue materialization. igniteNode flips visibility + enqueues materialization. Idempotent — second call no-op. Non-ritual nodes unaffected. Unknown id is safe no-op. Position stored in positions map while invisible (force sim still sees it). removeNode + late igniteNode is safe. **events.test.ts (EXTENDED, +268 lines, +7 tests, 55 total)** MemoryCreated → mesh hidden immediately, 2 birth-orb sprites added, ZERO RingGeometry meshes and ZERO Points particles at spawn. Full ritual drive → onArrive fires, node visible + materializing, sentinel cleared. Newton's Cradle: target mesh scale exactly 0.001 * 1.8 right after arrival. Dual shockwave: exactly 2 Ring meshes added. Re-read live position on arrival — force-sim motion during ritual → burst lands at the NEW position. Sanhedrin abort path → rainbow burst, shockwave, ripple wave are NEVER called (vi.spyOn). **three-mock.ts (EXTENDED)** Added Color.setRGB — production Three.js has it, the Sanhedrin- Shatter path in effects.ts uses it. Two write-agents independently monkey-patched the mock inline; consolidated as a 5-line mock addition so tests stay clean. **e2e/pulse-toast.spec.ts (NEW, 235 lines, 6 Playwright tests)** Navigate /dashboard/settings → click Preview Pulse → assert first toast appears within 500ms → assert >= 2 toasts visible at peak. Click-to-dismiss removes clicked toast (matched by aria-label). Hover survives >8s past the 5.5s dwell. Keyboard Enter dismisses focused toast. CSS animation-play-state:paused on .toast-progress- fill while hovered, running on mouseleave. Screenshots attached to HTML report. Zero backend dependency (fireDemoSequence is purely client-side). **e2e/birth-ritual.spec.ts (NEW, 199 lines, 3 Playwright tests)** Canvas mounts on /dashboard/graph (gracefully test.fixme if MCP backend absent). Settings button injection + SPA route to /graph → screenshot timeline at t=0/500/1200/2000/2400/3000ms attached to HTML report. pageerror + console-error listeners catch any crash (would re-surface FATAL 6 if reintroduced). Three back-to- back births — no errors, canvas still dispatches clicks. Run commands: cd apps/dashboard && npm test # 361/361 pass, ~600ms cd apps/dashboard && npx playwright test # 9/9 pass, ~25s Typecheck: 0 errors, 0 warnings. Build: clean adapter-static. * fix(graph): default /api/graph to newest-memory center, add sort param memory_timeline PR #37 exposed the same class of bug in the graph endpoint: the dashboard Graph page (and the /api/graph endpoint it hits) defaulted to centering on the most-connected memory, ran BFS at depth 3, and capped the subgraph at 150 nodes. On a mature corpus this clustered the visualization around a historical hotspot and hid freshly ingested memories that hadn't accumulated edges yet. User-visible symptom: TimeSlider on /graph showing "Feb 21 → Mar 1 2026" when the database actually contains memories through today (Apr 20). **Backend (`crates/vestige-mcp/src/dashboard/handlers.rs`):** - `GraphParams` gains `sort: Option<String>` (accepted: "recent" | "connected", unknown falls back to "recent"). - New internal `GraphSort` enum + case-insensitive `parse()`. - Extracted `default_center_id(storage, sort)` so handler logic and tests share the same branching. Recent path picks `get_all_nodes(1, 0)` (ORDER BY created_at DESC). Connected path picks `get_most_connected_memory`, degrading gracefully to recent if the DB has no edges yet. - Default behaviour flipped from "connected" to "recent" — matches user expectation of "show me my recent stuff". **Dashboard (`apps/dashboard`):** - `api.graph()` accepts `sort?: 'recent' | 'connected'` with JSDoc explaining the rationale. - `/graph/+page.svelte` passes `sort: 'recent'` when no query or center_id is active. Query / center_id paths unchanged — they already carry their own centering intent. **Tests:** 6 new unit tests in `handlers::tests`: - `graph_sort_parse_defaults_to_recent` (None, empty, garbage, "recent", "Recent", "RECENT") - `graph_sort_parse_accepts_connected_case_insensitive` - `default_center_id_recent_returns_newest_node` — ingest 3 nodes, assert newest is picked - `default_center_id_connected_prefers_hub_over_newest` — wire a hub node with 3 spokes, then ingest a newer "lonely" node; assert the hub wins in Connected mode even though it's older - `default_center_id_connected_falls_back_to_recent_when_no_edges` — fresh DB with no connections still returns newest, not 404 - `default_center_id_returns_not_found_on_empty_db` — both modes return 404 cleanly on empty storage Build + test: - cargo test -p vestige-mcp --lib handlers:: → 6/6 pass - cargo test --workspace --lib → 830/830 pass, 0 failed - cargo clippy -p vestige-core -p vestige-mcp --lib -- -D warnings → clean - npm run check → 0 errors, 0 warnings - npm test → 361/361 pass Binary already installed at ~/.local/bin/vestige-mcp (copied from cargo build --release -p vestige-mcp). New Claude Desktop / Code sessions will pick it up automatically when they respawn their MCP subprocess. The dashboard HTTP server on port 3927 needs a manual relaunch from a terminal with the usual pattern: nohup bash -c 'tail -f /dev/null | \ VESTIGE_DASHBOARD_ENABLED=true ~/.local/bin/vestige-mcp' \ > /tmp/vestige-mcp.log 2>&1 & disown * feat(v2.4): UI expansion — 8 new surfaces exposing the cognitive engine Sam asked: "Build EVERY SINGLE MISSING UI PIECE." 10 parallel agents shipped 10 new viewports over the existing Rust backend, then 11 audit agents line-by-line reviewed each one, extracted pure-logic helpers, fixed ~30 bugs, and shipped 549 new unit tests. Everything wired through the layout with single-key shortcuts and a live theme toggle. **Eight new routes** - `/reasoning` — Reasoning Theater: Cmd+K ask palette → animated 8-stage deep_reference pipeline + FSRS-trust-scored evidence cards + contradiction arcs rendered as live SVG between evidence nodes - `/duplicates` — threshold-driven cluster detector with winner selection, Merge/Review/Dismiss actions, debounced slider - `/dreams` — Dream Cinema: trigger dream + scrubbable 5-stage replay (Replay → Cross-reference → Strengthen → Prune → Transfer) + insight cards with novelty glow - `/schedule` — FSRS Review Calendar: 6×7 grid with urgency color bands (overdue/today/week/future), retention sparkline, expand-day list - `/importance` — 4-channel radar (Novelty/Arousal/Reward/Attention) with composite score + top-important list - `/activation` — live spreading-activation view: search → SVG concentric rings with decay animation + live-mode event feed - `/contradictions` — 2D cosmic constellation of conflicting memories, arcs colored by severity, tooltips with previews - `/patterns` — cross-project pattern transfer heatmap with category filters, top-transferred sidebar **Three layout additions** - `AmbientAwarenessStrip` — slim top band with retention vitals, at-risk count, active intentions, recent dream, activity sparkline, dreaming indicator, Sanhedrin-watch flash. Pure `$derived` over existing stores. - `ThemeToggle` — dark/light/auto cycle with matchMedia listener, localStorage persistence, SSR-safe, reduced-motion-aware. Rendered in sidebar footer next to the connection dot. - `MemoryAuditTrail` — per-memory Sources panel integrated as a Content/Audit tab into the existing /memories expansion. **Pure-logic helper modules extracted (for testability + reuse)** reasoning-helpers, duplicates-helpers, dream-helpers, schedule-helpers, audit-trail-helpers, awareness-helpers, contradiction-helpers, activation-helpers, patterns-helpers, importance-helpers. **Bugs fixed during audit (not exhaustive)** - Trust-color inconsistency between EvidenceCard and the page confidence ring (0.75 boundary split emerald vs amber) - `new Date('garbage').toLocaleDateString()` returned literal "Invalid Date" in 3 components — all now return em-dash or raw string - NaN propagation in `Math.max(0, Math.min(1, NaN))` across clamps - Off-by-one PRNG in audit-trail seeded mock (seed === UINT32_MAX yielded rand() === 1.0 → index out of bounds) - Duplicates dismissals keyed by array index broke on re-fetch; now keyed by sorted cluster member IDs with stale-dismissal pruning - Empty-cluster crash in DuplicateCluster.pickWinner - Undefined tags crash in DuplicateCluster.safeTags - Debounce timer leak in threshold slider (missing onDestroy cleanup) - Schedule day-vs-hour granularity mismatch between calendar cell and sidebar list ("today" in one, "in 1d" in the other) - Schedule 500-memory hard cap silently truncated; bumped to 2000 + banner - Schedule DST boundary bug in daysBetween (wall-clock math vs startOfDay-normalized) - Dream stage clamp now handles NaN/Infinity/floats - Dream double-click debounce via `if (dreaming) return` - Theme setTheme runtime validation; initTheme idempotence (listener + style-element dedup on repeat calls) - ContradictionArcs node radius unclamped (trust < 0 or > 1 rendered invalid sizes); tooltip position clamp (could push off-canvas) - ContradictionArcs $state closure capture (width/height weren't reactive in the derived layout block) - Activation route was MISSING from the repo — audit agent created it with identity-based event filtering and proper RAF cleanup - Layout: ThemeToggle was imported but never rendered — now in sidebar footer; sidebar overflow-y-auto added for the 16-entry nav **Tests — 549 new, 910 total passing (0 failures)** ReasoningChain 42 | EvidenceCard 50 DuplicateCluster 64 | DreamStageReplay 19 DreamInsightCard 43 | FSRSCalendar 32 MemoryAuditTrail 45 | AmbientAwareness 60 theme (store) 31 | ContradictionArcs 43 ActivationNetwork 54 | PatternTransfer 31 ImportanceRadar 35 | + existing 361 tests still green **Gates passed** - `npm run check`: 0 errors, 0 warnings across 623 files - `npm test`: 910/910 passing, 22 test files - `npm run build`: clean adapter-static output **Layout wiring** - Nav array expanded 8 → 16 entries (existing 8 + 8 new routes) - Single-key shortcuts added: R/A/D/C/P/U/X/N (no conflicts with existing G/M/T/F/E/I/S/,) - Cmd+K palette search works across all 16 - Mobile nav = top 5 (Graph, Reasoning, Memories, Timeline, Feed) - AmbientAwarenessStrip mounted as first child of <main> - ThemeToggle rendered in sidebar footer (was imported-but-unmounted) - Theme initTheme() + teardown wired into onMount cleanup chain Net branch delta: 47 files changed, +13,756 insertions, -6 deletions * chore(release): v2.0.8 "Pulse" Bundled release: Reasoning Theater wired to the 8-stage deep_reference cognitive pipeline, Pulse InsightToast, Memory Birth Ritual (v2.3 Terrarium), 7 new dashboard surfaces (/duplicates, /dreams, /schedule, /importance, /activation, /contradictions, /patterns), 3D graph brightness system with auto distance-compensation + user slider, and contradiction-detection + primary-selection hardening in the cross_reference tool. Intel Mac (x86_64-apple-darwin) also flows through to the release matrix from PR #43. Added: - POST /api/deep_reference — HTTP surface for the 8-stage pipeline - DeepReferenceCompleted WebSocket event (primary + supporting + contradicting memory IDs for downstream graph animation) - /reasoning route, full UI + Cmd+K Ask palette - 7 new dashboard surfaces exposing the cognitive engine - Graph brightness slider + localStorage persistence + distance-based emissive compensation so nodes don't disappear into fog at zoom-out Fixed: - Contradiction-detection false positives: adjacent-domain memories no longer flagged as conflicts (NEGATION_PAIRS wildcards removed, shared-words floor 2 → 4, topic-sim floor 0.15 → 0.55, STAGE 5 overlap floor 0.15 → 0.4) - Primary-memory selection: unified composite 0.5 × relevance + 0.2 × trust + 0.3 × term_presence with hard topic-term filter, closing the class of bug where off-topic high-trust memories won queries about specific subjects - Graph default-load fallback from sort=recent to sort=connected when the newest memory is isolated, both backend and client Changed: - Reasoning page information hierarchy: chain renders first as hero, confidence meter + Primary Source citation footer below - Cargo feature split: embeddings code-only + ort-download | ort-dynamic backends; defaults preserve identical behavior for existing consumers - CI release-build now gates PRs too so multi-platform regressions surface pre-merge
2026-04-23 02:21:11 -05:00
## [2.0.8] - 2026-04-23 — "Pulse"
The Pulse release wires the dashboard through to the cognitive engine. Eight new dashboard surfaces expose `deep_reference`, `find_duplicates`, `dream`, FSRS scheduling, 4-channel importance, spreading activation, contradiction arcs, and cross-project pattern transfer — every one of them was MCP-only before. Intel Mac is back on the supported list (Microsoft deprecated x86_64 macOS ONNX Runtime prebuilts; we link dynamically against a Homebrew `onnxruntime` instead). Reasoning Theater, Pulse InsightToast, and the Memory Birth Ritual all ship. No schema migrations.
### Added
- **Reasoning Theater (`/reasoning`)** — Cmd+K Ask palette over the 8-stage `deep_reference` cognitive pipeline: hybrid retrieval → cross-encoder rerank → spreading activation → FSRS-6 trust scoring → temporal supersession → trust-weighted contradiction analysis → relation assessment → template reasoning chain. Every query returns a pre-built reasoning block with evidence cards, confidence meter, contradiction geodesic arcs, superseded-memory lineage, and an evolution timeline. **Zero LLM calls, 100% local.** New HTTP surface `POST /api/deep_reference` wraps `crate::tools::cross_reference::execute`; new WebSocket event `DeepReferenceCompleted` carries primary / supporting / contradicting memory IDs for downstream graph animation.
- **Pulse InsightToast (v2.2 Pulse)** — real-time toast stack that surfaces `DreamCompleted`, `ConsolidationCompleted`, `ConnectionDiscovered`, `MemoryPromoted`/`Demoted`/`Suppressed`, `MemoryUnsuppressed`, `Rac1CascadeSwept` events the moment they fire. Rate-limited to 1 per 1500ms on connection-discovery cascades. Auto-dismiss after 5-6s, click-to-dismiss, progress bar. Bottom-right on desktop, top-center on mobile.
- **Memory Birth Ritual (v2.3 Terrarium)** — new memories materialize in the 3D graph on every `MemoryCreated` event: elastic scale-in from a camera-relative cosmic center, quadratic Bezier flight path, glow sprite fades in frames 5-10, label fades in at frame 40, Newton's Cradle docking recoil. 60-frame sequence, zero-alloc math, camera-relative so the birth point stays visible at every zoom level.
- **7 additional dashboard surfaces** exposing the cognitive engine (v2.4 UI expansion): `/duplicates` (find_duplicates cluster view), `/dreams` (5-stage replay + insight cards), `/schedule` (FSRS calendar + retention forecast), `/importance` (4-channel novelty/arousal/reward/attention radar), `/activation` (spreading-activation network viz), `/contradictions` (trust-weighted conflict arcs), `/patterns` (cross-project pattern-transfer heatmap). Left nav expanded from 8 → 16 entries with single-key shortcuts (R/A/D/C/P/U/X/N).
- **3D Graph brightness system** — auto distance-compensated node brightness (1.0× at camera <60u, up to 2.4× at far zoom) so nodes don't disappear into exponential fog at zoom-out. User-facing brightness slider in the graph toolbar (☀ icon, range 0.5×-2.5×, localStorage-persisted under `vestige:graph:brightness`). Composes with the auto boost; opacity + glow halo + edge weight track the combined multiplier so nodes stay coherent.
- **Intel Mac (`x86_64-apple-darwin`) support restored** via the `ort-dynamic` Cargo feature + Homebrew-installed ONNX Runtime. Microsoft is discontinuing x86_64 macOS prebuilts after ONNX Runtime v1.23.0 so `ort-sys` will never ship one for Intel; the dynamic-link path sidesteps that entirely. Install: `brew install onnxruntime` then `ORT_DYLIB_PATH=$(brew --prefix onnxruntime)/lib/libonnxruntime.dylib`. Full guide bundled in the Intel Mac tarball as `INSTALL-INTEL-MAC.md`. **Closes #41.**
- **Graph default-load fallback** — when the newest memory has zero edges (freshly saved, hasn't accumulated connections yet), `GET /api/graph` silently retries with `sort=connected` so the landing view shows real context instead of a lonely orb. Applies only to default loads; explicit `query` / `center_id` requests are honored as-is. Fires on both backend and client.
### Fixed
- **Contradiction-detection false positives** — adjacent-domain memories are no longer flagged as conflicts just because both contain the word "trust" or "fixed." Four thresholds tightened: `NEGATION_PAIRS` drops the `("not ", "")` + `("no longer", "")` wildcard sentinels; `appears_contradictory` shared-words floor 2 → 4 and correction-signal gating now requires ≥6 shared words + asymmetric presence (one memory carries the signal, the other doesn't); `assess_relation` topic-similarity floor raised 0.15 → 0.55; Stage 5 pairwise contradiction overlap floor 0.15 → 0.4. On an FSRS-6 query this collapses false contradictions from 12 → 0 without regressing the two legitimate contradiction test cases.
- **Primary-memory selection on `deep_reference`** — previously the reasoning chain picked via `max_by(trust)` and the recommended-answer card picked via `max_by(composite)`, so the chain and citation disagreed on the same query. Unified behind a shared composite (50% hybrid-search relevance + 20% FSRS-6 trust + 30% query-topic-term match fraction) with a hard topic-term filter: a memory cannot be primary unless its content contains at least one substantive query term. Three-tier fallback (on-topic + relevant → on-topic any → all non-superseded) so sparse corpora never starve. Closes the class of bug where high-trust off-topic memories won queries against the actual subject.
- **Reasoning page information hierarchy** — reasoning chain renders first as the hero (confidence-tinted border glow, inline metadata), then confidence meter + Primary Source citation card, then Cognitive Pipeline visualization, then evidence grid. "Template Reasoning" relabelled "Reasoning"; "Recommended Answer" relabelled "Primary Source" (it's a cited memory, not the conclusion — the chain is the conclusion).
### Changed
- **CI + release workflows** — `release-build` now runs on pull requests too so Intel Mac / aarch64-darwin / Linux / Windows regressions surface before merge. `x86_64-apple-darwin` back in both `ci.yml` and `release.yml` matrices with `cargo_flags: "--no-default-features --features ort-dynamic,vector-search"`. Intel Mac tarball bundles `docs/INSTALL-INTEL-MAC.md` alongside the binaries.
- **Cargo feature split** — `embeddings` is now code-only (fastembed dep + hf-hub + image-models). New `ort-download` feature carries the prebuilt backend (the historical default); `ort-dynamic` transitively enables `embeddings` so the 27 `#[cfg(feature = "embeddings")]` gates stay active when users swap backends. Default set `["embeddings", "ort-download", "vector-search", "bundled-sqlite"]` — identical behavior for every existing consumer.
- **Platform availability in README** — macOS Apple Silicon + Intel + Linux x86_64 + Windows x86_64 all shipped as prebuilts. Intel Mac needs `brew install onnxruntime` as a one-time prereq.
### Docs
- New `docs/INSTALL-INTEL-MAC.md` with the Homebrew prereq, binary install, source build, troubleshooting, and the v2.1 `ort-candle` migration plan.
- README Intel Mac section rewritten with the working install recipe + platform table updated.
### Migration
None. Additive features and bug fixes only. No schema changes, no breaking API changes, no config changes required.
### Contributors
- **danslapman** (#41, #42) — reported the Intel Mac build regression and investigated `ort-tract` as an alternative backend; closure documented that `ort-tract` returns `Unimplemented` when fastembed calls into it, confirming `ort-dynamic` as the correct path forward.
---
## [2.0.7] - 2026-04-19 — "Visible"
Hygiene release plus two UI gap closures. No breaking changes, no new major features, no schema migrations affecting user data beyond V11 dropping two verified-unused tables.
### Added
- **`POST /api/memories/{id}/suppress`** — Dashboard users can now trigger top-down inhibitory control (Anderson 2025 SIF + Davis Rac1 cascade) without dropping to raw MCP. Optional JSON body `{"reason": "..."}` logged for audit. Each call compounds; response includes `suppressionCount`, `priorCount`, `retrievalPenalty`, `reversibleUntil`, `estimatedCascadeNeighbors`, and `labileWindowHours`. Emits the existing `MemorySuppressed` WebSocket event so the 3D graph plays the violet implosion + compounding pulse shipped in v2.0.6.
- **`POST /api/memories/{id}/unsuppress`** — Reverses a suppression inside the 24h labile window. Returns `stillSuppressed: bool` so the UI can tell a full reversal from a compounded-down state. Emits `MemoryUnsuppressed` for the rainbow-burst reversal animation.
- **Suppress button on the Memories page** — Third action alongside Promote / Demote / Delete, hover-tooltip explaining the neuroscience ("Top-down inhibition (Anderson 2025). Compounds. Reversible for 24h.").
- **Uptime in the sidebar footer** — The Heartbeat WebSocket event has carried `uptime_secs` since v2.0.5 but was never rendered. Now displays as `up 3d 4h` / `up 18m` / `up 47s` (compact two-most-significant-units format) next to memory count + retention.
### Fixed
- **`execute_export` no longer panics on unknown format.** The write-out match arm at `maintenance.rs` was `_ => unreachable!()` — defensive `Err(...)` now returns a clean "unsupported export format" message instead of unwinding through the MCP dispatcher.
- **Dashboard graph page distinguishes empty-database from API failure** (landed in the first half of this branch). Before v2.0.7 any error from `/api/graph` rendered as "No memories yet," which masked real failures. Now the regex + node-count gate splits the two; real errors surface as "Failed to load graph: [sanitized message]" with filesystem paths stripped for info-disclosure hardening.
- **`predict` MCP tool surfaces a `predict_degraded` flag** instead of silently returning empty vecs on lock poisoning. `tracing::warn!` logs the per-channel error for observability.
- **`memory_changelog` honors `start` / `end` ISO-8601 bounds.** Previously advertised in the schema since v1.7 but runtime-ignored. Malformed timestamps now return a helpful error instead of silently dropping the filter. Response includes a `filter` field echoing the applied window.
- **`intention` check honors `include_snoozed`.** Previously silent no-op; snoozed intentions were invisible to check regardless of the arg. Dedup via HashSet guards against storage overlap.
- **`intention` check response exposes `status` and `snoozedUntil`** so callers can distinguish active-triggered from snoozed-overdue intentions.
- **Server tool-count comment at `server.rs:212`** updated (23 → 24) to match the runtime assertion.
### Removed
- **Migration V11: drops dead `knowledge_edges` + `compressed_memories` tables.** Both were added speculatively in V4 and marked deprecated in the same migration that created them. Zero INSERT or SELECT anywhere in `crates/`. Frees schema space for future migrations.
- **`execute_health_check` (71 LOC) + `execute_stats` (179 LOC) in `maintenance.rs`.** Both `#[allow(dead_code)]` since v1.7 with in-file comments routing users to `execute_system_status` instead. Zero callers workspace-wide. Net -273 LOC in the touched file.
- **`x86_64-apple-darwin` job from `.github/workflows/release.yml`.** The Intel Mac build failed the v2.0.5 AND v2.0.6 release workflows because `ort-sys 2.0.0-rc.11` (pinned by `fastembed 5.13.2`) does not ship Intel Mac prebuilts. `ci.yml` had already dropped the target; `release.yml` is now in sync. README documents the build-from-source path. Future releases should publish clean on all three supported platforms (macOS ARM64, Linux x86_64, Windows MSVC).
### Docs
- Reconciled tool / module / test counts across `README.md`, `CONTRIBUTING.md`, `docs/integrations/windsurf.md`, `docs/integrations/xcode.md`. Ground truth: **24 MCP tools · 29 cognitive modules · 1,292 Rust tests + 171 dashboard tests.**
- Historical CHANGELOG entries and `docs/launch/*.md` launch materials left unchanged because they are time-stamped artifacts of their respective releases.
### Tests
- **+7 assertions** covering the v2.0.7 behavioral changes: V11 migration drops dead tables + is idempotent on replay, `predict_degraded` false on happy path, `include_snoozed` both paths + `status` field exposure, malformed `start` returns helpful error + `filter` field echo.
- Full suite: **1,292 Rust passing / 0 failed** across `cargo test --workspace --release`. **171 dashboard tests passing.** Zero clippy warnings on `vestige-core` or `vestige-mcp` under `-D warnings`.
### Audit
Pre-merge audited by 4 parallel reviewers (security, code quality, end-to-end flow trace, external verification). Zero CRITICAL or HIGH findings. Two MEDIUM fixes landed in the branch: graph error-message path sanitization (strip `/path/to/*.{sqlite,rs,db,toml,lock}`, cap 200 chars) and `intention` response `status` field exposure.
---
## [2.0.6] - 2026-04-18 — "Composer"
Polish release aimed at new-user happiness. v2.0.5's cognitive stack was already shipping; v2.0.6 makes it *feel* alive in the dashboard and stays out of your way on the prompt side.
### Added
#### Dashboard visual feedback for six live events
- `MemorySuppressed` → violet implosion + compounding pulse whose intensity scales with `suppression_count` (Anderson 2025 SIF visualised).
- `MemoryUnsuppressed` → rainbow burst + green pulse when a memory is brought back within the 24h labile window.
- `Rac1CascadeSwept` → violet wave across a random neighbour sample while the background Rac1 worker fades co-activated memories.
- `Connected` → gentle cyan ripple on WebSocket handshake.
- `ConsolidationStarted` → subtle amber pulses across a 20-node sample during the FSRS-6 decay cycle (matches feed-entry colour).
- `ImportanceScored` → magenta pulse on the scored node with intensity proportional to composite score.
Before v2.0.6 all six events fired against a silent graph. Users perceived the dashboard as broken or unresponsive during real cognitive work.
#### `VESTIGE_SYSTEM_PROMPT_MODE` environment variable
- `minimal` (default) — 3-sentence MCP `instructions` string telling the client how to use Vestige and how to react to explicit feedback. Safe for every audience, every client, every use case.
- `full` — opt in to the composition mandate (Composing / Never-composed / Recommendation response shape + FSRS-trust blocking phrase). Useful for high-stakes decision workflows; misfires on trivial retrievals, which is why it is not the default.
Advertised in `vestige-mcp --help` alongside `VESTIGE_DASHBOARD_ENABLED`.
### Fixed
#### Dashboard intentions page
- `IntentionItem.priority` was typed as `string` but the API returns the numeric FSRS-style scale (1=low, 2=normal, 3=high, 4=critical). Every intention rendered as "normal priority" regardless of its real value. Now uses a `PRIORITY_LABELS` map keyed by the numeric scale.
- `trigger_value` was typed as a plain string but the API returns `trigger_data` as a JSON-encoded payload (e.g. `{"type":"time","at":"..."}`). The UI surfaced raw JSON for every non-manual trigger. A new `summarizeTrigger()` helper parses `trigger_data` and picks the most human-readable field — `condition` / `topic` / formatted `at` / `in_minutes` / `codebase/filePattern` — before truncating for display. Closes the loop on PR #26's snake_case TriggerSpec fix at the UI layer.
### Docs
- `README.md` — new "What's New in v2.0.6" header up top; v2.0.5 block strengthened with explicit contrast against Ebbinghaus 1885 passive decay and Anderson 1994 retrieval-induced forgetting; new "Forgetting" row in the RAG-vs-Vestige comparison table.
- Intel-Mac and Windows install steps replaced with a working `cargo build --release -p vestige-mcp` snippet. The pre-built binaries for those targets are blocked on upstream toolchain gaps (`ort-sys` lacks Intel-Mac prebuilts in the 2.0.0-rc.11 release pinned by `fastembed 5.13.2`; `usearch 2.24.0` hit a Windows MSVC compile break tracked as [usearch#746](https://github.com/unum-cloud/usearch/issues/746)).
### Safety
No regressions of merged contributor PRs — v2.0.6 only touches regions that are non-overlapping with #20 (resource URI strip), #24 (codex integration docs), #26 (snake_case TriggerSpec), #28 (deep_reference query relevance), #29 (older glibc feature flags), #30 (`VESTIGE_DASHBOARD_ENABLED`), #32 (dream eviction), and #33 (keyword-first search).
---
feat(v2.0.5): Intentional Amnesia — active forgetting via top-down inhibitory control First AI memory system to model forgetting as a neuroscience-grounded PROCESS rather than passive decay. Adds the `suppress` MCP tool (#24), Rac1 cascade worker, migration V10, and dashboard forgetting indicators. Based on: - Anderson, Hanslmayr & Quaegebeur (2025), Nat Rev Neurosci — right lateral PFC as the domain-general inhibitory controller; SIF compounds with each stopping attempt. - Cervantes-Sandoval et al. (2020), Front Cell Neurosci PMC7477079 — Rac1 GTPase as the active synaptic destabilization mechanism. What's new: * `suppress` MCP tool — each call compounds `suppression_count` and subtracts a `0.15 × count` penalty (saturating at 80%) from retrieval scores during hybrid search. Distinct from delete (removes) and demote (one-shot). * Rac1 cascade worker — background sweep piggybacks the 6h consolidation loop, walks `memory_connections` edges from recently-suppressed seeds, applies attenuated FSRS decay to co-activated neighbors. You don't just forget Jake — you fade the café, the roommate, the birthday. * 24h labile window — reversible via `suppress({id, reverse: true})` within 24 hours. Matches Nader reconsolidation semantics. * Migration V10 — additive-only (`suppression_count`, `suppressed_at` + partial indices). All v2.0.x DBs upgrade seamlessly on first launch. * Dashboard: `ForgettingIndicator.svelte` pulses when suppressions are active. 3D graph nodes dim to 20% opacity when suppressed. New WebSocket events: `MemorySuppressed`, `MemoryUnsuppressed`, `Rac1CascadeSwept`. Heartbeat carries `suppressed_count`. * Search pipeline: SIF penalty inserted into the accessibility stage so it stacks on top of passive FSRS decay. * Tool count bumped 23 → 24. Cognitive modules 29 → 30. Memories persist — they are INHIBITED, not erased. `memory.get(id)` returns full content through any number of suppressions. The 24h labile window is a grace period for regret. Also fixes issue #31 (dashboard graph view buggy) as a companion UI bug discovered during the v2.0.5 audit cycle: * Root cause: node glow `SpriteMaterial` had no `map`, so `THREE.Sprite` rendered as a solid-coloured 1×1 plane. Additive blending + `UnrealBloomPass(0.8, 0.4, 0.85)` amplified the square edges into hard-edged glowing cubes. * Fix: shared 128×128 radial-gradient `CanvasTexture` singleton used as the sprite map. Retuned bloom to `(0.55, 0.6, 0.2)`. Halved fog density (0.008 → 0.0035). Edges bumped from dark navy `0x4a4a7a` to brand violet `0x8b5cf6` with higher opacity. Added explicit `scene.background` and a 2000-point starfield for depth. * 21 regression tests added in `ui-fixes.test.ts` locking every invariant in (shared texture singleton, depthWrite:false, scale ×6, bloom magic numbers via source regex, starfield presence). Tests: 1,284 Rust (+47) + 171 Vitest (+21) = 1,455 total, 0 failed Clippy: clean across all targets, zero warnings Release binary: 22.6MB, `cargo build --release -p vestige-mcp` green Versions: workspace aligned at 2.0.5 across all 6 crates/packages Closes #31
2026-04-14 17:30:30 -05:00
## [2.0.5] - 2026-04-14 — "Intentional Amnesia"
Every AI memory system stores too much. Vestige now treats forgetting as a first-class, neuroscientifically-grounded primitive. This release adds **active forgetting** — top-down inhibitory control over memory retrieval, based on two 2025 papers that no other AI memory system has implemented.
### Scientific grounding
- **Anderson, M. C., Hanslmayr, S., & Quaegebeur, L. (2025).** *"Brain mechanisms underlying the inhibitory control of thought."* Nature Reviews Neuroscience. DOI: [10.1038/s41583-025-00929-y](https://www.nature.com/articles/s41583-025-00929-y). Establishes the right lateral PFC as the domain-general inhibitory controller, and Suppression-Induced Forgetting (SIF) as compounding with each stopping attempt.
- **Cervantes-Sandoval, I., Chakraborty, M., MacMullen, C., & Davis, R. L. (2020).** *"Rac1 Impairs Forgetting-Induced Cellular Plasticity in Mushroom Body Output Neurons."* Front Cell Neurosci. [PMC7477079](https://pmc.ncbi.nlm.nih.gov/articles/PMC7477079/). Establishes Rac1 GTPase as the active synaptic destabilization mechanism — forgetting is a biological PROCESS, not passive decay.
### Added
#### `suppress` MCP Tool (NEW — Tool #24)
- **Top-down memory suppression.** Distinct from `memory.delete` (which removes) and `memory.demote` (which is a one-shot hit). Each `suppress` call compounds: `suppression_count` increments, and a `k × suppression_count` penalty (saturating at 80%) is subtracted from retrieval scores during hybrid search.
- **Rac1 cascade.** Background worker piggybacks the existing consolidation loop, walks `memory_connections` edges from recently-suppressed seeds, and applies attenuated FSRS decay to co-activated neighbors. You don't just forget "Jake" — you fade the café, the roommate, the birthday.
- **Reversible 24h labile window** — matches Nader reconsolidation semantics on a 24-hour axis. Pass `reverse: true` within 24h to undo. After that, it locks in.
- **Never deletes** — the memory persists and is still accessible via `memory.get(id)`. It's INHIBITED, not erased.
#### `active_forgetting` Cognitive Module (NEW — #30)
- `crates/vestige-core/src/neuroscience/active_forgetting.rs` — stateless helper for SIF penalty computation, labile window tracking, and Rac1 cascade factors.
- 7 unit tests + 9 integration tests = 16 new tests.
#### Migration V10
- `ALTER TABLE knowledge_nodes ADD COLUMN suppression_count INTEGER DEFAULT 0`
- `ALTER TABLE knowledge_nodes ADD COLUMN suppressed_at TEXT`
- Partial indices on both columns for efficient sweep queries.
- Additive-only — backward compatible with all existing v2.0.x databases.
#### Dashboard
- `ForgettingIndicator.svelte` — new status pill that pulses when suppressed memories exist.
- 3D graph nodes dim to 20% opacity and lose emissive glow when suppressed.
- New WebSocket events: `MemorySuppressed`, `MemoryUnsuppressed`, `Rac1CascadeSwept`.
- `Heartbeat` event now carries `suppressed_count` for live dashboard display.
### Changed
- `search` scoring pipeline now includes an SIF penalty applied after the accessibility filter.
- Consolidation worker (`VESTIGE_CONSOLIDATION_INTERVAL_HOURS`, default 6h) now runs `run_rac1_cascade_sweep` after each `run_consolidation` call.
- Tool count assertion bumped from 23 → 24.
- Workspace version bumped 2.0.4 → 2.0.5.
### Tests
- Rust: 1,284 passing (up from 1,237). Net +47 new tests for active forgetting, Rac1 cascade, migration V10.
- Dashboard (Vitest): 171 passing (up from 150). +21 regression tests locking in the issue #31 UI fix.
- Zero warnings, clippy clean across all targets.
### Fixed
- **Dashboard graph view rendered glowing squares instead of round halos** ([#31](https://github.com/samvallad33/vestige/issues/31)). Root cause: the node glow `THREE.SpriteMaterial` had no `map` set, so `Sprite` rendered as a solid-coloured 1×1 plane; additive blending plus `UnrealBloomPass(strength=0.8, radius=0.4, threshold=0.85)` then amplified the square edges into hard-edged glowing cubes. The aggressive `FogExp2(..., 0.008)` swallowed edges at depth and dark-navy `0x4a4a7a` lines were invisible against the fog. Fix bundled:
- Generated a shared 128×128 radial-gradient `CanvasTexture` (module-level singleton) and assigned it as `SpriteMaterial.map`. Gradient stops: `rgba(255,255,255,1.0) → rgba(255,255,255,0.7) → rgba(255,255,255,0.2) → rgba(255,255,255,0.0)`. Sprite now reads as a soft round halo; bloom diffuses cleanly.
- Retuned `UnrealBloomPass` to `(strength=0.55, radius=0.6, threshold=0.2)` — gentler, allows mid-tones to bloom instead of only blown-out highlights.
- Halved fog density `FogExp2(0x050510, 0.008) → FogExp2(0x0a0a1a, 0.0035)` so distant memories stay visible.
- Bumped edge color `0x4a4a7a → 0x8b5cf6` (brand violet). Opacity `0.1 + weight*0.5 → 0.25 + weight*0.5`, cap `0.6 → 0.8`. Added `depthWrite: false` so edges blend cleanly through fog.
- Added explicit `scene.background = 0x05050f` and a 2000-point starfield distributed on a spherical shell at radius 6001000, additive-blended with subtle cool-white/violet vertex colors.
- Glow sprite scale bumped `size × 4 → size × 6` so the gradient has visible screen footprint.
- All node glow sprites share a single `CanvasTexture` instance (singleton cache — memory leak guard for large graphs).
- 21 regression tests added in `apps/dashboard/src/lib/graph/__tests__/ui-fixes.test.ts`. Hybrid strategy: runtime unit tests via the existing `three-mock.ts` (extended to propagate `map`/`color`/`depthWrite`/`blending` params and added `createRadialGradient` to the canvas context mock), plus source-level regex assertions on `scene.ts` and `nodes.ts` magic numbers so any accidental revert of fog/bloom/color/helper fails the suite immediately.
- `apps/dashboard/package.json` version stale at 2.0.3 — bumped to 2.0.5 to match the workspace.
- `packages/vestige-mcp-npm/.gitignore` missing `bin/vestige-restore` and `bin/vestige-restore.exe` entries — the other three binaries were already ignored as postinstall downloads.
---
feat: v2.0.4 "Deep Reference" — cognitive reasoning engine + 10 bug fixes New features: - deep_reference tool (#22): 8-stage cognitive reasoning pipeline with FSRS-6 trust scoring, intent classification (FactCheck/Timeline/RootCause/Comparison/ Synthesis), spreading activation expansion, temporal supersession, trust-weighted contradiction analysis, relation assessment, dream insight integration, and algorithmic reasoning chain generation — all without calling an LLM - cross_reference (#23): backward-compatible alias for deep_reference - retrieval_mode parameter on search (precise/balanced/exhaustive) - get_batch action on memory tool (up to 20 IDs per call) - Token budget raised from 10K to 100K on search + session_context - Dates (createdAt/updatedAt) on all search results and session_context lines Bug fixes (GitHub Issue #25 — all 10 resolved): - state_transitions empty: wired record_memory_access into strengthen_batch - chain/bridges no storage fallback: added with edge deduplication - knowledge_edges dead schema: documented as deprecated - insights not persisted from dream: wired save_insight after generation - find_duplicates threshold dropped: serde alias fix - search min_retention ignored: serde aliases for snake_case params - intention time triggers null: removed dead trigger_at embedding - changelog missing dreams: added get_dream_history + event integration - phantom Related IDs: clarified message text - fsrs_cards empty: documented as harmless dead schema Security hardening: - HTTP transport CORS: permissive() → localhost-only - Auth token panic guard: &token[..8] → safe min(8) slice - UTF-8 boundary fix: floor_char_boundary on content truncation - All unwrap() removed from HTTP transport (unwrap_or_else fallback) - Dream memory_count capped at 500 (prevents O(N²) hang) - Dormant state threshold aligned (0.3 → 0.4) Stats: 23 tools, 758 tests, 0 failures, 0 warnings, 0 unwraps in production Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 16:15:01 -05:00
## [2.0.4] - 2026-04-09 — "Deep Reference"
Context windows hit 1M tokens. Memory matters more than ever. This release removes artificial limits, adds contradiction detection, and hardens security.
### Added
#### cross_reference Tool (NEW — Tool #22)
- **Connect the dots across memories.** Given a query or claim, searches broadly, detects agreements and contradictions between memories, identifies superseded/outdated information, and returns a confidence-scored synthesis.
- Pairwise contradiction detection using negation pairs + correction signals, gated on shared topic words to prevent false positives.
- Timeline analysis (newest-first), confidence scoring (agreements boost, contradictions penalize, recency bonus).
#### retrieval_mode Parameter (search tool)
- `precise` — top results only, no spreading activation or competition. Fast, token-efficient.
- `balanced` — full 7-stage cognitive pipeline (default, no behavior change).
- `exhaustive` — 5x overfetch, deep graph traversal, no competition suppression. Maximum recall.
#### get_batch Action (memory tool)
- `memory({ action: "get_batch", ids: ["id1", "id2", ...] })` — retrieve up to 20 full memory nodes in one call.
### Changed
- **Token budget raised: 10K → 100K** on search and session_context tools.
- **HTTP transport CORS**: `permissive()` → localhost-only origin restriction.
- **Auth token display**: Guarded against panic on short tokens.
- **Dormant state threshold**: Aligned search (0.3 → 0.4) with memory tool for consistent state classification.
- **cross_reference false positive prevention**: Requires 2+ shared words before checking negation signals.
### Stats
- 23 MCP tools, 758 tests passing, 0 failures
- Full codebase audit: 3 parallel agents, all issues resolved
---
## [2.0.0] - 2026-02-22 — "Cognitive Leap"
The biggest release in Vestige history. A complete visual and cognitive overhaul.
### Added
#### 3D Memory Dashboard
- **SvelteKit 2 + Three.js dashboard** — full 3D neural visualization at `localhost:3927/dashboard`
- **7 interactive pages**: Graph (3D force-directed), Memories (browser), Timeline, Feed (real-time events), Explore (connections), Intentions, Stats
- **WebSocket event bus** — `tokio::broadcast` channel with 16 event types (MemoryCreated, SearchPerformed, DreamStarted/Completed, ConsolidationStarted/Completed, RetentionDecayed, ConnectionDiscovered, ActivationSpread, ImportanceScored, Heartbeat, etc.)
- **Real-time 3D animations** — memories pulse on access, burst particles on creation, shockwave rings on dreams, golden flash lines on connection discovery, fade on decay
- **Bloom post-processing** — cinematic neural network aesthetic with UnrealBloomPass
- **GPU instanced rendering** — 1000+ nodes at 60fps via Three.js InstancedMesh
- **Text label sprites** — distance-based visibility (fade in <40 units, out >80 units), canvas-based rendering
- **Dream visualization mode** — purple ambient, slow-motion orbit, sequential memory replay
- **FSRS retention curves** — SVG `R(t) = e^(-t/S)` with prediction pills at 1d/7d/30d
- **Command palette** — `Cmd+K` navigation with filtered search
- **Keyboard shortcuts** — `G` Graph, `M` Memories, `T` Timeline, `F` Feed, `E` Explore, `I` Intentions, `S` Stats, `/` Search
- **Responsive layout** — desktop sidebar + mobile bottom nav with safe-area-inset
- **PWA support** — installable via `manifest.json`
- **Single binary deployment** — SvelteKit build embedded via `include_dir!` macro
#### Engine Upgrades
- **HyDE query expansion** — template-based Hypothetical Document Embeddings: classify_intent (6 types) → expand_query (3-5 variants) → centroid_embedding. Wired into `semantic_search_raw`
- **fastembed 5.11** — upgraded from 5.9, adds Nomic v2 MoE + Qwen3 reranker support
- **Nomic Embed Text v2 MoE** — opt-in via `--features nomic-v2` (475M params, 305M active, 8 experts, Candle backend)
- **Qwen3 Reranker** — opt-in via `--features qwen3-reranker` (Candle backend, high-precision cross-encoder)
- **Metal GPU acceleration** — opt-in via `--features metal` (Apple Silicon, significantly faster embedding inference)
#### Backend
- **Axum WebSocket** — `/ws` endpoint with 5-second heartbeat, live stats (memory count, avg retention, uptime)
- **7 new REST endpoints** — `POST /api/dream`, `/api/explore`, `/api/predict`, `/api/importance`, `/api/consolidate`, `GET /api/search`, `/api/retention-distribution`, `/api/intentions`
- **Event emission from MCP tools** — `emit_tool_event()` broadcasts events for smart_ingest, search, dream, consolidate, memory, importance_score
- **Shared broadcast channel** — single `tokio::broadcast::channel(1024)` shared between dashboard and MCP server
- **CORS for SvelteKit dev** — `localhost:5173` allowed in dev mode
#### Benchmarks
- **Criterion benchmark suite** — `cosine_similarity` 296ns, `centroid` 1.3µs, HyDE expand 1.4µs, RRF fusion 17µs
### Changed
- Version: 1.8.0 → 2.0.0 (both crates)
- Rust edition: 2024 (MSRV 1.85)
- Tests: 651 → 734 (352 core + 378 mcp + 4 doctests)
- Binary size: ~22MB (includes embedded SvelteKit dashboard)
- CognitiveEngine moved from main.rs binary crate to lib.rs for dashboard access
- Dashboard served at `/dashboard` prefix (legacy HTML kept at `/` and `/graph`)
- `McpServer` now accepts optional `broadcast::Sender<VestigeEvent>` for event emission
### Technical
- `apps/dashboard/` — new SvelteKit app (Svelte 5, Tailwind CSS 4, Three.js 0.172, `@sveltejs/adapter-static`)
- `dashboard/events.rs` — 16-variant `VestigeEvent` enum with `#[serde(tag = "type", content = "data")]`
- `dashboard/websocket.rs` — WebSocket upgrade handler with heartbeat + event forwarding
- `dashboard/static_files.rs``include_dir!` macro for embedded SvelteKit build
- `search/hyde.rs` — HyDE module with intent classification and query expansion
- `benches/search_bench.rs` — Criterion benchmarks for search pipeline components
---
## [1.8.0] - 2026-02-21
### Added
- **`session_context` tool** — one-call session initialization replacing 5 separate calls (search × 2, intention check, system_status, predict). Token-budgeted responses (~15K tokens → ~500-1000 tokens). Returns assembled markdown context, `automationTriggers` (needsDream/needsBackup/needsGc), and `expandable` memory IDs for on-demand retrieval.
- **`token_budget` parameter on `search`** — limits response size (100-10000 tokens). Results exceeding budget moved to `expandable` array with `tokensUsed`/`tokenBudget` tracking.
- **Reader/writer connection split** — `Storage` struct uses `Mutex<Connection>` for separate reader/writer SQLite handles with WAL mode. All methods take `&self` (interior mutability). `Arc<Mutex<Storage>>``Arc<Storage>` across ~30 files.
- **int8 vector quantization** — `ScalarKind::F16``I8` (2x memory savings, <1% recall loss)
- **Migration v7** — FTS5 porter tokenizer (15-30% keyword recall) + page_size 8192 (10-30% faster large-row reads)
- 22 new tests for session_context and token_budget (335 → 357 mcp tests, 651 total)
### Changed
- Tool count: 18 → 19
- `EmbeddingService::init()` changed from `&mut self` to `&self` (dead `model_loaded` field removed)
- CLAUDE.md updated: session start uses `session_context`, 19 tools documented, development section reflects storage architecture
### Performance
- Session init: ~15K tokens → ~500-1000 tokens (single tool call)
- Vector storage: 2x reduction (F16 → I8)
- Keyword search: 15-30% better recall (FTS5 porter stemming)
- Large-row reads: 10-30% faster (page_size 8192)
- Concurrent reads: non-blocking (reader/writer WAL split)
---
## [1.7.0] - 2026-02-20
### Changed
- **Tool consolidation: 23 → 18 tools** — merged redundant tools while maintaining 100% backward compatibility via deprecated redirects
- **`ingest``smart_ingest`** — `ingest` was a duplicate of `smart_ingest`; now redirects automatically
- **`session_checkpoint``smart_ingest` batch mode** — new `items` parameter on `smart_ingest` accepts up to 20 items, each running the full cognitive pipeline (importance scoring, intent detection, synaptic tagging, hippocampal indexing). Old `session_checkpoint` skipped the cognitive pipeline.
- **`promote_memory` + `demote_memory``memory` unified** — new `promote` and `demote` actions on the `memory` tool with optional `reason` parameter and full cognitive feedback pipeline (reward signal, reconsolidation, competition)
- **`health_check` + `stats``system_status`** — single tool returns combined health status, full statistics, FSRS preview, cognitive module health, state distribution, warnings, and recommendations
- **CLAUDE.md automation overhaul** — all 18 tools now have explicit auto-trigger rules; session start expanded to 5 steps (added `system_status` + `predict`); full proactive behaviors table
### Added
- `smart_ingest` batch mode with `items` parameter (max 20 items, full cognitive pipeline per item)
- `memory` actions: `promote` and `demote` with optional `reason` parameter
- `system_status` tool combining health check + statistics + cognitive health
- 30 new tests (305 → 335)
### Deprecated (still work via redirects)
- `ingest` → use `smart_ingest`
- `session_checkpoint` → use `smart_ingest` with `items`
- `promote_memory` → use `memory(action="promote")`
- `demote_memory` → use `memory(action="demote")`
- `health_check` → use `system_status`
- `stats` → use `system_status`
---
## [1.6.0] - 2026-02-19
### Changed
- **F16 vector quantization** — USearch vectors stored as F16 instead of F32 (2x storage savings)
- **Matryoshka 256-dim truncation** — embedding dimensions reduced from 768 to 256 (3x embedding storage savings)
- **Convex Combination fusion** — replaced RRF with 0.3 keyword / 0.7 semantic weighted fusion for better score preservation
- **Cross-encoder reranker** — added Jina Reranker v1 Turbo (fastembed TextRerank) for neural reranking (~20% retrieval quality improvement)
- Combined: **6x vector storage reduction** with better retrieval quality
- Cross-encoder loads in background — server starts instantly
- Old 768-dim embeddings auto-migrated on load
---
## [1.5.0] - 2026-02-18
### Added
- **CognitiveEngine** — 28-module stateful engine with full neuroscience pipeline on every tool call
- **`dream`** tool — memory consolidation via replay, discovers hidden connections and synthesizes insights
- **`explore_connections`** tool — graph traversal with chain, associations, and bridges actions
- **`predict`** tool — proactive retrieval based on context and activity patterns
- **`restore`** tool — restore memories from JSON backup files
- **Automatic consolidation** — FSRS-6 decay runs on a 6-hour timer + inline every 100 tool calls
- ACT-R base-level activation with full access history
- Episodic-to-semantic auto-merge during consolidation
- Cross-memory reinforcement on access
- Park et al. triple retrieval scoring
- Personalized w20 optimization
### Changed
- All existing tools upgraded with cognitive pre/post processing pipelines
- Tool count: 19 → 23
---
## [1.3.0] - 2026-02-12
### Added
- **`importance_score`** tool — 4-channel neuroscience scoring (novelty, arousal, reward, attention)
- **`session_checkpoint`** tool — batch smart_ingest up to 20 items with Prediction Error Gating
- **`find_duplicates`** tool — cosine similarity clustering with union-find for dedup
- `vestige ingest` CLI command for memory ingestion via command line
### Changed
- Tool count: 16 → 19
- Made `get_node_embedding` public in core API
- Added `get_all_embeddings` for duplicate scanning
---
## [1.2.0] - 2026-02-12
### Added
- **Web dashboard** — Axum-based on port 3927 with memory browser, search, and system stats
- **`memory_timeline`** tool — browse memories chronologically, grouped by day
- **`memory_changelog`** tool — audit trail of memory state transitions
- **`health_check`** tool — system health status with recommendations
- **`consolidate`** tool — run FSRS-6 maintenance cycle
- **`stats`** tool — full memory system statistics
- **`backup`** tool — create SQLite database backups
- **`export`** tool — export memories as JSON/JSONL with filters
- **`gc`** tool — garbage collect low-retention memories
- `backup_to()` and `get_recent_state_transitions()` storage APIs
### Changed
- Search now supports `detail_level` (brief/summary/full) to control token usage
- Tool count: 8 → 16
---
## [1.1.3] - 2026-02-12
### Changed
- Upgraded to Rust edition 2024
- Security hardening and dependency updates
### Fixed
- Dedup on ingest edge cases
- Intel Mac CI builds
- NPM package version alignment
- Removed dead TypeScript package
---
2026-01-27 02:34:10 -06:00
## [1.1.2] - 2025-01-27
### Fixed
- Embedding model cache now uses platform-appropriate directories instead of polluting project folders
- macOS: `~/Library/Caches/com.vestige.core/fastembed`
- Linux: `~/.cache/vestige/fastembed`
- Windows: `%LOCALAPPDATA%\vestige\cache\fastembed`
- Can still override with `FASTEMBED_CACHE_PATH` environment variable
---
## [1.1.1] - 2025-01-27
### Fixed
- UTF-8 string slicing issues in keyword search and prospective memory
- Silent error handling in MCP stdio protocol
- Feature flag forwarding between crates
- All GitHub issues resolved (#1, #3, #4)
### Added
- Pre-built binaries for Linux, Windows, and macOS (Intel & ARM)
- GitHub Actions CI/CD for automated releases
---
## [1.1.0] - 2025-01-26
### Changed
- **Tool Consolidation**: 29 tools → 8 cognitive primitives
- `recall`, `semantic_search`, `hybrid_search``search`
- `get_knowledge`, `delete_knowledge`, `get_memory_state``memory`
- `remember_pattern`, `remember_decision`, `get_codebase_context``codebase`
- 5 intention tools → `intention`
- Stats and maintenance moved from MCP to CLI (`vestige stats`, `vestige health`, etc.)
### Added
- CLI admin commands: `vestige stats`, `vestige health`, `vestige consolidate`, `vestige restore`
- Feedback tools: `promote_memory`, `demote_memory`
- 30+ FAQ entries with verified neuroscience claims
- Storage modes documentation: Global, per-project, multi-Claude household
- CLAUDE.md templates for proactive memory use
- Version pinning via git tags
### Deprecated
- Old tool names (still work with warnings, removed in v2.0)
---
## [1.0.0] - 2025-01-25
### Added
- FSRS-6 spaced repetition algorithm with 21 parameters
- Bjork & Bjork dual-strength memory model (storage + retrieval strength)
- Local semantic embeddings with fastembed v5 (BGE-base-en-v1.5, 768 dimensions)
- HNSW vector search with USearch (20x faster than FAISS)
- Hybrid search combining BM25 keyword + semantic + RRF fusion
- Two-stage retrieval with reranking (+15-20% precision)
- MCP server for Claude Desktop integration
- Tauri desktop application
- Codebase memory module for AI code understanding
- Neuroscience-inspired memory mechanisms:
- Synaptic Tagging and Capture (retroactive importance)
- Context-Dependent Memory (Tulving encoding specificity)
- Spreading Activation Networks
- Memory States (Active/Dormant/Silent/Unavailable)
- Multi-channel Importance Signals (Novelty/Arousal/Reward/Attention)
- Hippocampal Indexing (Teyler & Rudy 2007)
- Prospective memory (intentions and reminders)
- Sleep consolidation with 5-stage processing
- Memory compression for long-term storage
- Cross-project learning for universal patterns
### Changed
- Upgraded embedding model from all-MiniLM-L6-v2 (384d) to BGE-base-en-v1.5 (768d)
- Upgraded fastembed from v4 to v5
### Fixed
- SQL injection protection in FTS5 queries
- Infinite loop prevention in file watcher
- SIGSEGV crash in vector index (reserve before add)
- Memory safety with Mutex wrapper for embedding model
---
## [0.1.0] - 2025-01-24
### Added
- Initial release
- Core memory storage with SQLite + FTS5
- Basic FSRS scheduling
- MCP protocol support
- Desktop app skeleton