The living field is now interactive, killing Classic's main reason to
exist. Clicking a node in the WebGPU field opens the same Memory Detail
inspector (content, FSRS bars, retention forecast, promote/demote,
explore) that Classic's Three.js picking drove.
How: NodeRenderer.pickAt(ndcX, ndcY) — the one sanctioned GPU readback,
input-driven and click-frequency only, so the render loop's determinism
contract (spec §6) holds. It copies the live NodeState buffer (post
force-sim positions) to a MAP_READ staging buffer, reprojects every node
on the CPU through the SAME deterministic orbit camera the frame used
(engine params phase + canvas aspect, column-major viewProj), and picks
the nearest node whose projected disc (r·f/w with a floor for faint
nodes, 1.6x halo slop) contains the click. NodeState gains COPY_SRC for
the copy; a fresh staging buffer per click is created and destroyed.
ObservatoryStage gains an onpick prop wired to the canvas layer
(crosshair cursor when interactive); the graph page passes onNodeSelect
so field picks open the existing panel.
Verified live: click at field center hit a real memory, panel opened
with real FSRS data (retention 65.4%, forecast 65%->37% @30d), zero
console errors. svelte-check 940 files 0/0; 96 observatory tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The main graph page defaults to the Observatory engine — GPU force sim,
HDR bloom, and the recall wavefront sweeping the REAL memory graph on a
12s loop — instead of the flat Three.js view. Visuals to the max, per
the locked ALIVE-field direction.
- ObservatoryStage gains embedded (fills parent, not viewport) and
chrome ('full' | 'none') props; chrome='none' is a pure living canvas
plus loading/error text, so the page's own DOM chrome stays in charge.
- New Field | Classic renderer toggle in the control bar. Field is the
default wherever WebGPU exists; no WebGPU forces classic. Choice
persists in localStorage.
- Classic (Three.js) remains one click away and untouched: node picking,
colour modes, node count, brightness, temporal scrubbing and legends
are classic-renderer features and now only render there. Dream,
Observatory takeover, Memory Cinema (protected) and Reload work in
both modes.
Verified live: fresh load defaults to Field (148 real nodes, 2865 real
edges, recall ribbon igniting on camera, zero console errors); Classic
toggle restores search/colour/brightness with a single canvas; the
choice round-trips through localStorage. svelte-check 940 files 0
errors 0 warnings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Observatory is no longer a separate URL you have to know about. It
is now a first-class part of the main graph page, following the proven
Memory Cinema pattern (which remains untouched per the protected-block
rule):
- The full experience is factored into a reusable ObservatoryStage
component (engine, plans, overlays moved verbatim from the route).
- The graph control bar gains an Observatory button beside Dream and
Memory Cinema; clicking it takes over the screen full-bleed (z-50).
- Inside the stage: an on-screen switcher for the 5 cognitive moments
(RECALL / BIRTH / RESCUE / HORIZON / FIREWALL) and an EXIT control
(Esc works too) that returns to the graph exactly as it was. Both are
hidden in capture mode so recordings stay chrome-free.
- {#key demo} remounts the stage per moment: fresh engine, plans, and
clock, deterministic from frame 0.
- The /observatory route stays as a thin wrapper so deep links and the
?frame=N / ?capture=1 recording contract are unchanged; switching a
moment there rewrites the URL so links stay shareable.
Verified live in the running dashboard: button renders between Dream
and Cinema, click boots the WebGPU takeover (148 real nodes, 2865
edges), RESCUE chip switches the moment (telemetry: SALIENCE-RESCUE),
EXIT unmounts cleanly back to the graph (canvas count 2 -> 1).
svelte-check 940 files 0 errors 0 warnings; 96 observatory tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gate the auto-dedup consolidation pass behind VESTIGE_AUTO_CONSOLIDATE_MERGE (default on) and exclude protected (pinned) nodes so they are never absorbed or deleted by the unattended cycle.
Reviewed and verified green locally before merge:
- 8 new #142 tests pass; regression guards proven to bite pre-fix (5 protection tests fail when the pin filter is removed)
- full vestige-core lib suite: 541 passed / 0 failed
- clippy --workspace --all-targets -D warnings: 0 warnings
Fixes#142.
Co-authored-by: Michael Kurras <michael.kurras@wuestpartner.com>
Two demo-readiness fixes so the Observatory reads as a living brain
doing real work, not a sparse placeholder:
1. Graph query switched from sort=recent to sort=connected (max_nodes
200). 'recent' centered on the newest memory, a lonely node whose
depth-3 neighborhood is only ~12 nodes, so the field looked empty.
'connected' surfaces the populous hotspot: ~148 real memories and
~2865 real edges, laid out as two dense clusters. Verified live on
recall-path and salience-rescue: 148 nodes / 2865 edges at 110-119fps.
2. Verdict card now holds. The 'root cause found' card faded fully out
by frame 660 in a 720-frame (12s) loop, so it flashed for ~1s then
vanished. Widened the default fade window to [600,620,705,719]: it
fades in, holds fully readable through the field's decay to rest, and
only fades out just before the seamless loop wrap. ~1.75s of readable
verdict instead of a blink. GPU envelopes and the seam-zero loop test
are unaffected (DOM overlay window is independent of the sim).
Verified live against the real brain: 96 observatory tests green, zero
console errors, verdict readable at frames 660 and 695 (both blank before).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Observatory is a full-bleed, zero-library WebGPU surface that renders
the memory graph as a living cognitive field. Five deterministic demo
moments driven by a URL contract (?demo=<name>&seed=...&frame=N):
recall-path, engram-birth, salience-rescue, forgetting-horizon, firewall.
Capture mode (?frame=N) freezes the sim deterministically so the same URL
produces identical pixels, the viral-clip primitive.
Architecture: bare-metal WebGPU engine (no Three.js), seeded demo clock,
per-demo plan + renderer modules, WGSL shaders (simulate, nodes, edges,
path, birth particles, rescue, forgetting, firewall) plus a post-processing
chain (tone mapping, MIP). DOM is instrument overlays only (telemetry strip,
timeline spine, rescue verdict); the layout gives /observatory the same
full-bleed bypass as marketing routes so recordings stay clean.
Reads the real memory graph. Verified live: svelte-check 939 files 0 errors,
96 observatory unit tests green, all 5 demos load at 108-119fps with zero
console errors against the live brain.
Known follow-up: engram-birth capture-mode particle cluster needs a render
fix pass before it is camera-ready; the other 4 demos are camera-ready.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The background consolidation cycle's auto_dedup_consolidation pass silently
concat-merged near-duplicate memories (cosine >= 0.85) into [MERGED] blocks and
hard-deleted the originals, with no opt-out and while ignoring `dedup protect`
pins — so a pinned memory could be absorbed/deleted unattended.
- Gate the pass behind VESTIGE_AUTO_CONSOLIDATE_MERGE (default on; set
0/false/off/no to disable), parsed like the sibling VESTIGE_BACKFILL_AUTOFIRE,
at the function top so every consolidation caller is covered consistently.
- Exclude protected (pinned) nodes from merge clusters at both loops, so a
protected node is never an anchor nor a member — never absorbed, never deleted.
protected_node_ids() is fetched once before the reader-lock window (lock-safe).
- Tests: default-unchanged regression, flag-off suppression, full protection
matrix, liveness, and an explicit #142 regression guard.
- Docs: CONFIGURATION.md env-var row + CHANGELOG entry.
Default behavior is unchanged. TOCTOU: the protected set is snapshotted once per
pass (consistent with the function's existing point-in-time idiom). Out of scope
(follow-up): a reversible audit trail for merges that still happen when enabled,
and the [MERGED] concat-bloat itself.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A second adversarial audit of shipped main (post the 29+3 earlier fixes) found
10 more real bugs in areas the first pass under-covered (FTS sanitizer,
protocol/HTTP, connectors, frontend). None regressions — all pre-existing, and
several are "twin sites" of a class fixed elsewhere but missed here.
Majors:
- FTS5: sanitize_fts5_terms leaked bare operators on doubled input ("foo AND AND
AND"), aborting MATCH with a syntax error or silently flipping AND->OR. Now
filters operator tokens (repetition-proof).
- Server crash (DoS): unbounded MCP `hours_back`/`hours_forward` panicked via
Duration::minutes in CaptureWindow; unclamped `limit` in match_context
panicked via negative Vec::with_capacity / limit*2 overflow. Both now
bounded/checked.
- Connectors: the source idempotency key omitted source_project, so two repos
(or two Redmine instances) with overlapping ids clobbered each other's memory.
Key + unique index (migration V19) now include source_project.
Minors/nits:
- list_memories now honors node_type/tag on the search path (were dropped).
- HTTP Accept honors */* and type wildcards (was hard 406 for curl et al.).
- Bearer scheme matched case-insensitively (RFC 7235).
- Dream insight time-span no longer seeds from now/-365d sentinels (fabricated a
TemporalTrend for old clusters).
- WebSocket disconnect() detaches onclose before close() so it can't resurrect
the socket via scheduleReconnect.
- Redmine thread truncation keeps the NEWEST journals (was keeping oldest, so
new activity never re-indexed).
Tests: FTS operator-leak regression added. Full workspace green (1559 tests,
clippy -D warnings clean); dashboard check + 937 tests green.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The /duplicates, /contradictions, and /patterns routes shipped hardcoded mock
data — and /duplicates rendered a "Live" badge over it. That is a launch
credibility risk: a visitor who spots the canned data distrusts every real
claim (including the CauseBench benchmark).
Replaces the three mocks (mockFetchDuplicates, MOCK_CONTRADICTIONS,
mockFetchCrossProject) with real dashboard HTTP endpoints backed by the existing
core capabilities:
- GET /api/duplicates -> dedup cluster detection
- GET /api/contradictions -> trust-weighted contradiction analysis
- GET /api/patterns/cross-project-> cross-project pattern transfer
Adds the handlers (dashboard/handlers.rs), route registrations (dashboard/mod.rs),
frontend api client methods + response types, and rewrites the three routes to
fetch live. The "Live" badge is now truthful.
Verified this session:
- cargo build -p vestige-mcp: compiles
- pnpm --filter @vestige/dashboard check: 905 files, 0 errors, 0 warnings
- live backend on a 1073-memory DB returns real rows from all three endpoints
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- #117 Agent Black Box: the trace recorder had zero production callers, so
agent_traces/receipts/memory_prs never populated. handle_tools_call now
records the opening mcp.call event (record_call) before dispatch and the
downstream memory events (record_result) after a successful call, under a
shared run_id. Also fixed the args capture so tracing works in pure stdio
mode (was gated on event_tx, which is None without a dashboard socket).
- #124 Recurring intentions now re-arm: mark_triggered advances a recurring
trigger's next_occurrence and returns the intention to Active (was firing
once and staying Triggered forever). Added Trigger::re_arm (recurses into
Compound).
- #137 Co-access prediction channel is now live: search_unified feeds the
retrieved set to speculative_retriever.record_usage, so co-access patterns
populate (were permanently empty). The temporal channel was already fixed
(#136); the file-context channel stays dormant by design (search has no file
context to supply).
Tests: Black Box trace population, recurring re-arm. Full workspace green
(1558 tests, clippy -D warnings clean).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A backend-wide audit (18 feature areas, adversarially verified) surfaced 31
real bugs. This fixes 29 of them; each was re-verified by an independent
adversarial pass and the whole workspace stays green (1556 tests, clippy -D
warnings clean).
Data integrity & storage:
- Migrations no longer brick the DB on a mid-migration failure: each runs in a
transaction (atomic schema change + version bump); V7 repages under WAL.
- decide_memory_pr rejects re-deciding a finalized PR (audit ledger + no
resurrection of a rejected memory).
- suppress reverse is now a true inverse (was leaving stability permanently
halved).
- update_node_content flips has_embedding=0 when the embedder isn't ready, so
the stale embedding is regenerated instead of matching old content forever.
- plan_merge validates survivor_id is a member (was an unchecked-unwrap panic).
- Redmine detail-fetch failure aborts the page (retry) instead of storing a
journal-less record and skipping it forever.
- ContentStore cache counter accounts for replaced entries; changelog no longer
loads the whole connections table; source_sync clamps max_pages.
Cognitive correctness:
- Contradiction heuristic requires a real polarity flip (was demoting correct
memories on benign "do not"/"cannot" notes).
- Hybrid search relevance is the RRF fused score, min-max normalized, so the
best match ranks first (was capped and outranked by recency/importance).
- Sentiment-boosted stability is clamped to MAX_STABILITY.
- Chain confidence uses the correct geometric-mean root; looks_like_failure no
longer over-fires on "$500"; contains_marker_word is UTF-8-boundary-safe.
- Prediction merge can't cross min_confidence from below; temporal prediction
wraps around midnight; match_context tag overlap is clamped to 1.0.
MCP / CLI:
- UTF-8 panic in the " at " intention parser fixed (boundary-safe match).
- vestige backup no longer fails on encrypted DBs (best-effort raw checkpoint).
- --ago-days uses checked Duration + subtraction (no overflow panic).
- smart_ingest honors an explicit forceCreate:false (was silently inverted).
- append_trace_event propagates the seq query error (no duplicate seq=0).
- RewardPattern::matches requires real overlap (was matching everything).
Deferred: the dead trace-recorder wiring (Black Box/Receipts/Memory-PR) is a
feature-completion task for its own change; two dormant speculative-prediction
channels with no production caller are left as-is (fixing dead code adds risk
without user benefit).
Regression tests added for the migration brick, suppress inverse, backfill
bound, contradiction false-positive, and forceCreate handling.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Surface the contributor credit as its own subsection rather than a
trailing sentence: @Vrakoss for the Windows repro (#101), @randomnimbus
(Peter Lauzon) for the backfill report + fix (#103), whose commit is
already co-authored in the shipped v2.2.1 release (f7530af).
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* patch(backfill-safety): VESTIGE_BACKFILL_AUTOFIRE gate (default OFF) + bounded promote_memory_backfill
Off-by-default env gate around step-8.5 auto-fire in run_consolidation (decouples
backfill from consolidation cadence). New promote_memory_backfill caps stability at
MIN(stability*1.5, stability+365.0) (the bound retroactive_backfill.rs:300 already
computes but discarded); both backfill entry points use it. Fixes the false 'capped'
comment. Cloud-sync excluded at build (--no-default-features). Pending upstream PR to
samvallad33/vestige. omega-backfill-safety-v2.2.0 off tag v2.2.0 (3bcd4667).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* release: v2.2.1 — Windows embeddings fix + backfill safety + first-run guide
Board-clearing patch release.
Fixes:
- #101 Windows embeddings: release.yml already restores vector-search on the
x86_64-pc-windows-msvc target (merged in #102); this release rebuilds the
Windows binary so users actually get working embeddings.
- #103 Retroactive Salience Backfill safety (from community PR #104, adjusted):
* promote_memory_backfill bounds the stability multiply to
MIN(stability*1.5, stability+365.0) on both auto-fire and manual paths.
* VESTIGE_BACKFILL_AUTOFIRE gate — default ON (preserves the shipped/documented
v2.2.0 behavior), disable with 0/false/off/no. Env value is trimmed.
* Corrected the false "capped" comment and the promote_memory_backfill doc.
* Added 3 tests: +365 cap binds, *1.5 multiply below crossover, gate parsing.
Docs:
- #83 First-Run: new docs/GETTING-STARTED.md + README pointer.
- Consolidated roadmap issues #82,#84-#92 into docs/ROADMAP.md (Tracked Issues).
- Documented VESTIGE_BACKFILL_AUTOFIRE in docs/CONFIGURATION.md.
- CHANGELOG v2.2.1 entry.
Version bumped to 2.2.1 across all manifests + Cargo.lock + dashboard build.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Peter Lauzon <inbijiburu@protonmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Windows x86_64-pc-windows-msvc release binary was built with
`--no-default-features --features embeddings,ort-download`, dropping
`vector-search` (the usearch HNSW index). Without that feature the
storage layer's `#[cfg(feature = "vector-search")]` paths compile out,
so embeddings are never persisted or queried. On Windows the binary
reports "Embedding Service: Not Ready", 0% coverage, `consolidate`
generates 0 embeddings, and no model download is ever attempted. The
same machine and model cache work on v2.1.23, which predates the flag.
`vector-search` was likely dropped to sidestep the usearch MSVC build
failure (C1021 from a bare-fp16 `#warning`), but that was already fixed
properly by pinning usearch with `features=["fp16lib"]`, so omitting
the feature is both unnecessary and the cause of the regression.
Verified locally: building vestige-mcp with
`embeddings,ort-download,vector-search` compiles and links cleanly, and
the reporter's repro (ingest -> consolidate -> stats) downloads the
nomic model and reaches 100% embedding coverage.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Vestige is the MCP memory layer underneath every agent, not an add-on for one
tool. Quick start leads with the universal mcp.json config (works with any
agent), then per-agent shortcuts (Cursor first). 'Works in every editor' ->
'Works with every AI agent' with Cursor/Windsurf/VS Code/Cline/Continue/Zed/
Goose leading and Claude Code as one option among many. Added a confirm-it-worked
step and surfaced the flagship backfill command.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The real cause was not a flaky runner image: the macOS Test job restored a
cached `target/` built against a previous runner Xcode, and that stale build
dir carried a clang compiler-rt search path (.../clang/<N>/lib/darwin) that no
longer exists on the current image, so the linker failed with
'ld: library clang_rt.osx not found' on every commit.
Fix: stop caching `target/` on the test job (cache only the download-heavy
registry/git dirs) and bump the cache key to v2 to discard the poisoned
caches. Also deleted the existing poisoned macOS caches. Reverted the macos-14
pin (it didn't help and that image is deprecating) back to macos-latest, which
is fine now that target/ is always built clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The MCP Registry rejects descriptions over 100 chars (422). Tightened to the
backward-reach hook so server.json matches the published v2.2.0 registry entry.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Updates the official MCP Registry manifest (server.json) and the Claude
Desktop .mcpb bundle manifest to 2.2.0, and refreshes their descriptions to
lead with the v2.2.0 flagship (Retroactive Salience Backfill).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The rolling macos-latest image intermittently ships a broken compiler-rt
path, causing 'ld: library clang_rt.osx not found' on the Rust link step of
an otherwise-green commit (a README-only change failed CI this way). Pinning
all five macOS jobs (CI test + CI release-build + Release) to macos-14 gives a
stable Xcode/clang toolchain so the linker step is deterministic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces 44 em-dashes with commas, colons, periods, and parentheses so the
prose reads naturally without them. No content changes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The v2.2.0 version bump (2.1.27 -> 2.2.0) updated the crate Cargo.toml files
but not Cargo.lock, leaving the lockfile pinning vestige-core/vestige-mcp at
2.1.27. The Release workflow builds with `cargo build --locked`, which refuses
to update the lockfile, so every platform target failed with:
error: cannot update the lock file ... because --locked was passed
Regenerated via `cargo update -w` (workspace members only, no dependency bumps).
Verified: `cargo build --locked -p vestige-mcp --release` now succeeds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Opens with the pitch's pattern-interrupt first sentence ('Your bug was born
days before it crashed'), then tells the story in Sam's own voice — why he built
it, the soccer/causal-gap framing, the DeepMind theorem + CauseBench receipts
(0% vs 60%, kept honestly separate as theorem-vs-measurement). Links the
60-second spoken pitch (demo/PITCH-v2-causebench.md). Real citations only
(arXiv:2508.21038, Nature DOI 10.1038/s41586-024-08168-4).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete rewrite that leads with the visceral problem (the agent that forgets
the lesson you taught it), then the v2.2.0 flagship (Retroactive Salience
Backfill — memory with hindsight) and the claim-contradiction breakthrough.
Updates 25→13 tools, v2.1.23→v2.2.0, refreshes all metrics (86k LOC, 23MB,
1550 tests). Real citations only (Zaki/Cai 2024 Nature 637:145-155, no
fabricated URLs). All internal doc links verified to exist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second swarm pass (complete every-line sweep), verified against real code
(38/101 confirmed real; 63 false positives excluded). This commit lands the
main-compatible subset:
- redmine SSRF guard: rewrite host check to use host_str()+std::net::IpAddr
instead of the `url` crate (url is not a direct dep of vestige-core on main;
the previous form only compiled on the feature branch). Same protection:
blocks localhost + loopback/private/link-local/unspecified IPs.
- bin/restore: guard wrapper[0] index (empty backup array would panic)
- bin/cli: char-boundary-safe node.id truncation (2 byte-slice panics);
XML-escape the model/home strings before launchd plist substitution
- prospective_memory: Duration::try_hours/try_days (panic on out-of-range
user config); case-insensitive " at " split now uses the lowercased index
so the contains() check and the split agree
core 477/0, mcp builds, clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Verified main-compatible moderate fixes from the complete sweep:
- predictive_retrieval get_proactive_suggestions: clone session_context and
drop the read guard before predict_needed_memories re-acquires it (re-entrant
RwLock read can deadlock when a writer is queued between)
- hippocampal_index create_semantic_associations: snapshot (id, summary) pairs
under the read lock, drop it, THEN run the O(n) cosine scan (was blocking all
writers for the full scan duration)
- prospective_memory check_triggers: don't auto-expire an intention that was
JUST triggered this iteration (the expire ran unconditionally after
mark_triggered, clobbering a fresh trigger)
core 477/0, clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool Consolidation v2.2.0 (34->12 advertised surface: recall/memory/codebase/
intention/smart_ingest/source_sync/memory_status/maintain/dedup/graph/
session_start/suppress) onto the retroactive-salience-backfill base.
Conflict resolution:
- server.rs: took #99's canonical 12-tool surface, then re-added
as a 13th ADVERTISED tool (ToolDescription + dispatch arm + test). Backfill
is the flagship 'Memory with hindsight' (Cai 2024 Nature) cognitive primitive
— a distinct capability, not a maintenance op to fold into `maintain` or hide.
- Cargo.toml: kept usearch features=["fp16lib"] with the fuller MSVC-C1021
explanation comment (Windows build fix, #71).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire Step 8.5 into run_consolidation (bounded + idempotent via durable
Causal edge), share looks_like_failure/extract_entities across MCP tool +
CLI + auto-fire, add whole-word failure markers (API_TIMEOUT no longer
false-fires), --json CLI for CauseBench, and refactor the Redmine SSRF
guard to std::net (drops the dangling url-crate dep).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds docs/launch/tool-consolidation-v2.2.0.md — the single sequenced plan that
reconciles the two prior planning notes:
- Layer 1 (this PR): 34 → 12 advertised tools, safe commit order, alias policy,
preserved invariants, and the test that proves each.
- Layer 2 (follow-up): tiny always-on default surface + SessionStart/Stop hooks.
Also refreshes stale in-code comments to match the consolidated surface:
- server.rs handle_tools_list header (was "v2.1.21: 25 tools") and the
size-annotation rationale (now lists recall/memory_status/dedup/graph).
- tools/mod.rs module doc (the facade vs. granular-handler relationship).
No behavior change. Gates: cargo test --workspace, cargo clippy -D warnings,
pnpm dashboard check + build — all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool Consolidation v2.2.0, Layer 1 commit 5/6. Advertised tools 21 → 15.
Folds consolidate + dream + gc + importance_score + backup + export + restore
into one action-dispatched tool:
action = consolidate | dream | gc | importance_score | backup | export | restore
- Thin facade forwards the same args envelope to each existing handler; the
`action` discriminator is cloned out before the envelope is moved into a
callee. No handler uses deny_unknown_fields, so per-action params validate.
- Safety defaults preserved (all handler-internal): gc dry_run=true by default,
restore path-confinement, export traversal guard. Verified by
test_maintain_actions_and_safety (gc dry-run + restore missing-path error).
- Events preserved end-to-end:
- Pre-dispatch Started events (ConsolidationStarted/DreamStarted) re-emitted
in the `maintain` arm keyed on action.
- emit_tool_event normalizes the `maintain` name to its effective action, so
the existing ConsolidationCompleted/DreamCompleted/ImportanceScored arms
fire unchanged — no duplicated emit logic.
- All 7 old names remain hidden warn!+redirect aliases (removed v2.3.0), keeping
their own pre-emits.
- Tests: count 21→15, 7 negatives, new dispatch/safety test.
Gates: cargo test --workspace, cargo clippy -D warnings — clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool Consolidation v2.2.0, Layer 1 commit 4/6 (3b). Advertised tools 24 → 21.
Folds explore_connections + predict + memory_graph + composed_graph into one
action-dispatched tool:
action ∈ {chain, associations, bridges, predict, memory_graph,
recent, get, memory, neighbors, never_composed, bounty_mode, label}
- Transparent facade: each action forwards the same args envelope to the
existing handler, which re-reads its own discriminator/params. No underlying
arg struct uses deny_unknown_fields, so cross-fields are ignored.
- All actions read-only except `label` (the one mutator), which is logged for
audit via tracing::info!(event_id, outcome_type).
- outcome_type enum sourced from composed_graph::OUTCOME_TYPES (now pub(crate))
rather than re-listed, so the vocabulary stays single-sourced.
- All 4 old names remain hidden warn!+redirect aliases (removed v2.3.0).
- Size annotation: graph=250_000 (memory_graph layout + bounty_mode pagination),
kept in sync across loop, helper, and both annotation tests.
- Tests: count 24→21, 4 negatives, test_graph_actions_and_aliases exercising
read-only actions + aliases (incl. the memory_graph facade branch).
Note: the design draft mislabeled graph::execute as sync; it is `pub async fn`.
The per-commit build gate caught it — the facade awaits it correctly.
Gates: cargo test --workspace, cargo clippy -D warnings — clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool Consolidation v2.2.0, Layer 1 commit 3/6 (3a). Advertised tools 27 → 24.
Folds system_status + memory_health + memory_timeline + memory_changelog
into one view-dispatched tool:
view = health (default) | retention | timeline | changelog
- Thin facade: each view forwards the same args envelope to the existing
handler. No underlying arg struct uses deny_unknown_fields, so the `view`
discriminator is ignored by each handler and per-view fields validate as
before. The cognitive lock is never held across a forwarded call.
- view='health' returns the byte-for-byte system_status shape (audit scripts
parse it), incl. schema_introspection passthrough — verified by
test_default_view_is_health asserting equality with execute_system_status.
- All 4 old names remain hidden warn!+redirect aliases (removed v2.3.0).
- Size annotation moved: memory_timeline (200k) → memory_status, kept in sync
across the real loop, expected_max_result_size(), and both annotation tests.
- Tests: count 27→24, 4 negative asserts, test_memory_status_views_and_aliases
exercising all 4 views + 4 aliases.
Gates: cargo test --workspace, cargo clippy -D warnings — clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tool Consolidation v2.2.0, Layer 1 commit 2/6. Advertised count unchanged
at 27 (pure rename).
`session_start` is the imperative-outcome name for the one-call session
initializer. `session_context` remains a hidden warn!+redirect alias
(≥1 minor release, removed v2.3.0), calling the same handler unchanged.
Tests: positive assert swapped to session_start + negative assert for the
old name. Gates: cargo test --workspace, cargo clippy -D warnings — clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All verified against real code:
- github fetch_updated: propagate fetch_comments errors instead of
unwrap_or_default() (silent failure stored a comment-less record with a
corrupted hash AND advanced the cursor past it = permanent gap)
- relationships load_relationships: advance next_id past loaded rel-N ids so
new_id() can't collide with persisted ids
- speculative store_pending_predictions: merge instead of clear (two predict()
calls without an intervening record_usage() wiped the first batch's accounting)
- embeddings/code is_comment_only: stop treating leading '#'/'*' as comments
(was deleting #include, #define, *ptr, CSS '*', multiplication)
- importance_signals: reconcile total_count to the surviving pattern sum after
decay/prune (was inflated, driving novelty toward zero over time)
- importance on_retrieved_with_context: set context in the SAME critical section
as the event push via record_retrieval() (two-lock approach raced; last_mut()
could land on a concurrently-pushed event)
core 535/0, clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All verified against real code:
- connectors: empty list_live_ids() no longer mass-tombstones the entire source
(treat empty as "cannot enumerate", like None) — was catastrophic data loss
- redmine: SSRF guard — require http(s), reject loopback/private/link-local hosts
+ localhost (escape hatch VESTIGE_ALLOW_PRIVATE_CONNECTOR_HOSTS for local tests)
- KnowledgeEdge::is_valid now honors valid_from via was_valid_at(now) (was
ignoring it; a future-dated edge read as valid). No production callers.
- emotional_memory: flashbulb counter reconciles to the FINAL is_flashbulb
decision after the importance override (was undercounting via ==0 guard)
- chains path_to_chain: fixed off-by-one — step i now uses the INCOMING edge
connections[i-1], not the outgoing connections[i]; removed the synthetic
connection hack that masked the misalignment
- merge_supersede compose_merged_content: exact normalized dedup instead of
substring containment (was silently dropping "cat" inside "cathedral")
core 535/0, clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Multi-model audit (deepseek-v4/minimax/kimi/qwen) surfaced these; verified
against the real code and fixed the confirmed ones:
- github connector: host-pin failed OPEN when api_root was unparseable/hostless
— the bearer token would ride a Link `next` url to an attacker host. Now
fail-closed: no pinned host => drop the url. (CRITICAL: SSRF / token exfil)
- GithubConfig/RedmineConfig derived Debug leaked the token/api_key into any
{:?} log line or panic message. Replaced with manual redacting Debug impls.
- cross_project priority calc used `as u32 - i` which underflows/panics (debug)
or wraps + corrupts the sort (release). Use saturating_sub.
Verified false-positive (no change): path-traversal in get_file_context — it
only inspects the path string, never reads the file.
core: 535 passed / 0 failed, clippy clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam's locked stage pitch for a multi-pitch event + separate networking hour.
Keeps the World Cup soccer analogy (the weapon that makes anyone get "causally
upstream"), the detonation line + silence, "realizes", and "next layer of the
dev stack". Closer fits reality: "come find me after, I'll show you in 30s" (demo
is 1:1 at networking on a pre-loaded laptop, never installing on their system).
Two seams closed: "hours"->"days", "agents that touch" (plural). Added networking
playbook: pre-warm the seeded demo, demo from strength, the pilot-hook answer for
"does it work on mine?".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam's canonical 60s spoken pitch, every sentence workshopped. Two seams closed
from the assembled draft: opener "hours"->"days" (matches "three days ago"), and
the reveal names "Vestige" (was a naked "memory"). Includes the win-the-room
line list, stage rules (never throat-clear the open; dare don't demo; end on
"come prove me wrong"), and a delivery map of where to slow/pause/drop voice.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam chose to keep Vestige over Postdict: it sounds natural, it's the live + loved
product (561 stars, repo, npm packages), costs zero to keep, and "vestige = a
trace of what remains from the past" is backward-looking = on-thesis. The
category lives in the tagline ("the first memory that finds the cause, not the
lookalike"), not the name. Reverted the pitch to "I created Vestige from my tiny
Chicago apartment", kept the "our"->"my" solo-founder fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam's own tightened version, with 2 corrections: "our memory" -> "my memory"
(solo-founder first-person rule) and the name is Postdict (not Vestige). Adds
the "tiny Chicago apartment" line (underdog-relatable, investor-loved). The 2024
Nature reference verified true. This is the canonical stage script.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam is a solo founder and built Postdict alone — the pitch must say "I built,"
"I ported," "I already did it," never "we." For an early-stage solo founder that
is a strength (ships without a team = what investors bet on). Only remaining
"we" is "now we're handing debugging to AI agents" — there it means all of us as
an industry, not the company. Added delivery rule #4: "I built this" is a flex.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sam delivers this on a stage to 50-100 people — voice only, no screen. Rewrote
from a terminal-demo script into a pure ~60s spoken pitch built for the ear:
short sentences, hard stops, [pause] cues (silence = the loudest move on stage),
and one memorizable detonation line ("a root cause never looks like the bug it
creates"). Opens about the audience's pain, not the product; promises the
laptop demo afterward rather than fumbling a terminal live. Includes a 30s
hallway version and a 5s one-liner.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The detonation version of the funding pitch. Deliberately REJECTS a "X companies
got hacked" hook (commodity security-FUD, needs an uncitable stat that torches
the honest+reproducible moat, and shrinks the market from "every agent in
production" to "security"). Instead opens with the WOUND every engineer has
lived — "production breaks, the cause is a change you made days ago and forgot"
— then detonates the industry's flawed axiom ("relevance ≠ resemblance; a root
cause never looks like the bug it creates"), proves it live, defends the moat
(Nature port + their architecture IS the axiom), and ends on TAM.
Uses `postdict` on screen (the new name); includes the interactive-shell alias
so it can be recorded with the new name today. Contrast re-verified end-to-end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>