Backward reach and reversible merges

Vestige

Merge candidates classified by Fellegi-Sunter record linkage into match, possible and non-match, where the uncertain classes need an explicit confirmation and every applied operation carries its own undo payload.

Carries 2 of 7 rubric mechanisms. Most systems here carry none or one (43%), and a dash means the mechanism was not found at this commit — not that the system needed it. Each mark is one LLM reviewer's reading of the code at this commit rather than a run of it — known limits.

  • Tombstone
  • Trust state
  • Bi-temporal
  • Scope enforced
  • Mutation audit
  • Human review
  • Negative evals

1. Executive Summary

Vestige is a local-first memory layer for MCP agents: one 25MB Rust binary, one SQLite file, AGPL-3.0, about 97,000 lines across two crates with 1,088 test functions. It models memory on cognitive science — FSRS-6 spaced repetition, the Bjork dual-strength model, ACT-R activation, top-down inhibitory suppression — and cites the papers in the code.

Three things earn the report.

Merge decisions use record-linkage theory instead of a similarity threshold. crates/vestige-core/src/advanced/merge_supersede.rs applies Fellegi-Sunter with two thresholds, classifying every candidate pair as match, possible or non_match. The header says why: a single cosine threshold "over-merges and destroys the audit trail". The consequence reaches the tool surface — the dedup tool's apply action accepts a match plan directly, and 'possible'/'non_match' need confirm=true. Uncertainty is routed back to the caller rather than resolved by rounding — and the caller is the precise word, which is why the human-review mark does not hold on a second reading. confirm is a field in the tool call: crates/vestige-mcp/src/trace_recorder.rs:460-466 reads args.get("confirm").and_then(|v| v.as_bool()).unwrap_or(false), and the tool description at server.rs:472 documents it as part of the call shape — "'purge' (for good; confirm=true)". A boolean the model sets in its own arguments guards against a slip, the way --force does; it does not put a person in the loop. The separation of scan, plan_* and apply is still the right shape, and it is what makes the plan inspectable by whoever is watching — but nothing requires that anyone is.

Every applied operation carries the payload that reverses it. merge_operations is described in the migration as "the 'git reflog for your agent's memory'": one row per applied merge or supersede, with undo_payload holding "everything needed to reverse it", signals recording "why the memories combined", and an undo op type that points back at what it reverted. The tool description states the invariant plainly — "Old memories are invalidated, never deleted."

And there is a protect action that pins a memory against auto-merge, supersede and forget — an explicit opt-out from every automatic lifecycle mechanism, which is a thing this atlas asks for and rarely finds.

The benchmark story is the thing to read here, and it opens with a retraction. docs/BENCHMARKS.md withdraws the project's own prior benchmark in its first paragraph:

"Vestige previously advertised a benchmark called CauseBench. It is formally withdrawn. Its harness no longer exists, its repro command 404'd, and its published numbers are retracted. CauseBench must never be cited, in release notes, READMEs, issues, launch posts, or conversation — not even as 'an earlier result'."

A separate LongMemEval run is invalidated in the same notice. The page then says why it is written the way it is: "After a retraction, a number that cannot be reproduced by a stranger is worse than no number at all." Section 10 has what replaced it.

2. Mental Model

A memory is a knowledge_node carrying an unusual amount of cognitive state: FSRS-6 stability, difficulty, reps and lapses; the Bjork dual-strength triple of storage, retrieval and retention strength; sentiment score and magnitude for emotional weighting; and an ACT-R activation value computed during consolidation.

Beside it, memory_states holds a four-value availability state — active, dormant, silent, unavailable — with suppression_until and a suppressed_by JSON array naming which other memories are inhibiting this one. That last field is the design's core idea: memories compete, and losing competition is a recorded event rather than a lower score.

The flagship retrieval primitive is backfill, and it inverts the usual direction. When a failure is recorded, it reaches backward in time to promote the earlier memory that caused it — selected by shared entity (the same file, environment variable or service) rather than by similarity, because, in the tool's own words, the root cause is one "a vector search structurally cannot surface because it isn't similar to the failure, only causally upstream". It is described as a faithful port of Cai 2024 and is backward-only by construction.

Diagram — suppression compounds per call and expires, merges keep an undo payload, and purge is the one irreversible transition — leaving a content-free tombstone row
Diagram source
%% caption: suppression compounds per call and expires, merges keep an undo payload, and purge is the one irreversible transition — leaving a content-free tombstone row
stateDiagram-v2
    [*] --> Active: captured
    Active --> Dormant: time_decay
    Dormant --> Active: access or cue_reactivation
    Active --> Silent: competition_loss
    Silent --> Active: interference_resolved
    Active --> Unavailable: user_suppression, compounds per call
    Unavailable --> Active: suppression_expired or reverse within 24h
    Active --> Active: manual_override
    Dormant --> Active: backfill promotes it as an upstream cause
    Active --> Merged: plan classified match, applied
    Active --> Merged: plan classified possible, applied with confirm=true
    Merged --> Active: undo, from the stored undo_payload
    Active --> Purged: irreversible, content-free tombstone row remains
    Purged --> [*]

Every transition on that diagram writes a state_transitions row with a reason_type from a nine-value vocabulary — the labels on the arrows are the literal values in the schema.

3. Architecture

Two crates: vestige-core (62,000 lines) holds storage, the neuroscience modules, search, merge/supersede and the dream cycle; vestige-mcp (35,000 lines) is the tool surface. The result is a single binary with an npx installer, an offline embedding model downloaded once, no API key and no telemetry.

The schema is fifteen-plus numbered migrations with a schema_version table and assertions in the migration code itself — migration V13's test block checks that deletion_tombstones exists after it runs.

One migration comment deserves quoting in full, because it is the correct handling of a defect this atlas keeps finding in other systems:

DEPRECATED (v2.0.5): knowledge_edges is unused. All graph edges use memory_connections (migration V3). This table was designed for bi-temporal edge support but was never wired. Retained for schema compatibility with existing databases. Do NOT add queries against this table.

An unwired table, labelled as unwired, with the reason, the replacement and an instruction. Four systems in this atlas ship the same situation without the comment; a reader auditing this schema cannot be misled.

4. Essential Implementation Paths

Capture — the memory tool → SqliteStorage insert (crates/vestige-core/src/storage/sqlite.rs:874-935), which writes valid_from/valid_until from the caller when supplied.

Recall — hybrid search with a validity boost (crates/vestige-core/src/search/temporal.rs:121) and spreading activation via the graph tool's associations action.

Point in time — sqlite.rs:3686: `SELECT * FROM knowledge_nodes WHERE (valid_from IS NULL OR valid_from <= ?1) AND (valid_until IS NULL OR valid_until

= ?1), with KnowledgeNode::is_valid_at` as the in-memory equivalent and unit tests for the future-dated and past-dated cases.

Merge — dedup scan (read-only, cosine clusters plus Fellegi-Sunter) → plan_merge/plan_supersede (a merge_plans row, status pending) → apply (guarded by confirm=true for possible and non_match) → merge_operations with the undo payload → undo.

Suppress — the suppress tool applies top-down inhibition; a background Rac1 worker cascades decay to co-activated neighbours; reversible within 24 hours.

Backfill — from a recorded failure, reach backward by shared entity and promote the causal antecedent.

5. Memory Data Model

Twenty-five-plus tables. The ones that carry the design:

Table Role
knowledge_nodes Content plus FSRS-6, dual-strength, sentiment, activation, valid_from/valid_until
memory_states active | dormant | silent | unavailable, with suppression_until and suppressed_by
state_transitions Append-only, from_state, to_state, a nine-value reason_type, reason_data
merge_plans pending | applied | cancelled, with the Fellegi-Sunter confidence and classification
merge_operations The reflog: undo_payload, signals, reason, reverts_op_id
deletion_tombstones Content-free: id, time, reason, node type, tags, and counts of what the purge touched
memory_access_log search_hit | promote | demote, timestamped
fsrs_cards, fsrs_config Scheduling state and per-user parameters
composition_events, composition_members, composition_outcomes Which memories were used together, and what happened next

deletion_tombstones is worth reading carefully because of what it deliberately does not keep. The migration comment: purge "permanently removes memory content and embeddings, but keeps a content-free audit/sync record so users can verify that a memory was removed without Vestige retaining the text it was told to forget." The row keeps the counts of what the purge affected — edges pruned, insights rewritten, insights deleted, children orphaned — so the blast radius is auditable without the content being retained. That is a genuinely thoughtful resolution of the tension between an audit trail and a right to erasure.

The composition tables are the other unusual idea: recording which memories were retrieved together, what produced the composition, and what happened afterwards, with the comment noting that memory_id values are "intentionally historical references instead of foreign keys" so the record survives the memories it describes.

6. Retrieval Mechanics

Hybrid search over embeddings and FTS, with three things layered on top that are not common here.

A validity boost (search/temporal.rs) modulates the score by whether the node's interval contains the query time, rather than filtering hard — so a memory that has stopped being valid ranks lower rather than vanishing, while the dedicated point-in-time query filters hard when a caller asks for an instant.

Spreading activation through memory_connections gives the graph tool its associations, chain and bridges actions — a reasoning path from one memory to another rather than a ranked list.

Backward reach. backfill is the flagship and the honest description of its own necessity is the interesting part: the causal memory "ranks 7th of 8 under both dense cosine and BM25, while the decoy ranks 1st" on the verbatim queries agents typed. The mechanism exists because the ranking demonstrably fails, and the project measured its own ranking failing before building around it.

There is no tenant or namespace scope. Tags are the only partition, and the error message at sqlite.rs:8445 — "Filter by tags to reduce scope" — is about scan cost rather than isolation. scope_enforced is withheld: this is a single-user store by design.

7. Write Mechanics

Writes are local and synchronous; there is no cloud call and no model call on the write path beyond embedding.

Correction is a three-step pipeline and the steps are separated on purpose. scan is read-only. plan_merge and plan_supersede produce a preview — a merge_plans row with the diff in payload and no mutation. apply executes one, and refuses without confirm=true when the classification is anything weaker than match.

Purge is the one irreversible operation and it is gated behind the same caller-set confirm=true. It removes content and embeddings, scrubs insights.source_memories, detaches temporal-summary children, prunes graph edges, and writes the content-free tombstone.

What the tombstone does not do is prevent re-assertion. It is keyed on the memory id, and its consultation point is portable sync — "Hard purge tombstones win over newer local edits during portable sync" — so importing a database that still has the memory will not resurrect it. Writing the same content again through the normal capture path will.

8. Agent Integration

Thirteen MCP tools, consolidated from a larger set with the folding documented in comments: recall, memory, codebase, intention, smart_ingest, source_sync, memory_status, maintain, dedup, graph, session_start, suppress, backfill. session_start combines search, intentions, status, predictions and codebase context into one token-budgeted call, "instead of 5 separate calls".

A dashboard, connectors with cursor checkpoints and upstream reconciliation, and a portable export/import that merges into a non-empty database while applying tombstones and keeping newer local rows on timestamp conflicts.

9. Reliability, Safety, and Trust

Bitemporal — awarded. valid_from and valid_until are separate columns from created_at/updated_at, written from caller-supplied values on insert, read by a dedicated point-in-time query, used as a ranking boost, and unit-tested with future-dated and past-dated cases.

Audit log — awarded, and it is well-motivated. state_transitions is append-only, indexed on memory and time, and every row names why the state moved from a fixed vocabulary — access, time_decay, cue_reactivation, competition_loss, interference_resolved, user_suppression, suppression_expired, manual_override, system_init. merge_operations is a second append-only record with the reversal payload, and memory_access_log a third for reads. A reader can reconstruct why a memory is where it is.

Human review — awarded. The confirmation gate is real and it is graded by uncertainty rather than applied uniformly: a match applies, a possible or non_match requires an explicit confirm=true from the caller. protect lets a person exempt a memory from every automatic lifecycle mechanism, and undo reverses an applied operation from its stored payload.

Trust state — withheld, and the distinction is worth naming. memory_states is a four-value field consulted on the read path, which is the shape of the mark. It fails the definition because the axis is availability, not credence: silent means another memory outcompeted this one, unavailable means someone suppressed it. Nothing says whether a memory is true. merge_plans has an epistemic-looking classification — match | possible | non_match — but that is a judgement about whether two memories are the same thing, not about whether either is correct.

Tombstone — withheld. deletion_tombstones is content-free by design and keyed on the memory id, and it is consulted during portable sync rather than on capture. It is a deletion receipt for replication, and it is a good one.

Negative eval — no. 1,088 test functions, and none found asserting that particular material must not be retrieved. The Silent Rotation benchmark's "converged wrong" column is the nearest thing in spirit — it measures the fleet adopting a planted decoy — and it is not in this tree.

10. Tests, Evals, and Benchmarks

No paper of its own, and an unusually dense set of citations to other people's: DeepMind on the limits of single-vector retrieval (arXiv:2508.21038), Cai 2024 for backward salience, Anderson et al. 2025 and Davis on Rac1 for suppression, Bjork & Bjork 1992 for dual strength, FSRS-6 for scheduling, Fellegi-Sunter for record linkage. The mechanisms are named after the papers in the code, which makes them checkable in a way "cognitive-science-inspired" usually is not.

1,088 test functions across the two crates, plus tests/e2e, tests/hooks and tests/phase_1. I did not run them. The screen flagged server.json as an auto-run manifest and twelve dependency manifests inside the seven-day cooldown including Cargo.lock and pnpm-lock.yaml.

The benchmarks are in the tree, and the methodology page is unusually rigorous. benchmarks/ holds five harnesses — memconflict, agent-memory-eval, before-you-change-that, memoryarena and task-cost — and docs/BENCHMARKS.md documents the one the project says it stands behind. Six things there are worth copying whole.

It retracts its own prior benchmark and forbids citing it. CauseBench is "formally withdrawn", its numbers retracted, and the prohibition is explicit — "not even as 'an earlier result'". So is a separate invalidated LongMemEval run. Almost nothing in this corpus retracts a number it published.

It corrects the field's reading of the paper it borrows. MemConflict (arXiv:2605.20926) is quoted from the PDF rather than a summary, and the page separates two columns the ecosystem conflates: the widely-repeated 0.5539 / 0.4871 / … list is Answer Accuracy, not Conflict Recognition Score. "Calling them CRS overstates the field by roughly a factor of two." The best CRS any of the six systems reaches is 0.2501, and the page quotes the paper saying so. Correcting a mistake that flatters everyone, including the systems you are measured against, is unusual.

Four arms run every time and none is optional. nomem is the floor — "anything scoring above ~0 here is measuring the judge, not memory" — random is a blob-inflation control at a fixed seed, bm25 is the earned-complexity bar, and vestige is the system under test. The justification cites MemDelta (arXiv:2606.29914): agent memory routinely loses to controlled baselines, and changing the embedding model alone moved accuracy 6.2pp at p=0.004, enough to reverse rankings. The rule follows: "A memory system that cannot beat naive BM25 on the same corpus, with the same reader and the same judge, has not earned its complexity. The harness prints that verdict explicitly."

The structural metric cannot be gamed by wording. CRS-struct scores whether recall(mode="contradictions") returned a contradiction pair, read from contradictionsFound — "never by keyword-matching the response, so the metric cannot be satisfied by the server merely emitting the word 'contradiction'." The lexical variant beside it uses upstream's exact keyword rule, applied identically to every arm.

The limits section is longer than the results section, nine numbered items, and it disqualifies the project's own favourable readings: its numbers are not comparable to the paper's table because the judge and reader differ; only cross-arm differences within one run mean anything; the reader is a concatenator so AA is a retrieval proxy rather than task accuracy; and — the one most systems would leave out — "CRS-struct is not a head-to-head win. BM25 and the random/no-memory controls have no contradiction channel at all, so they are structurally 0 by construction, not by measured deficit… and must never be presented as such."

It refuses to estimate what the public data cannot support. The paper's SEH@K and SRS need gold supporting-memory ids; the released questions do not carry them, so those metrics are not reported — "We will not estimate them." The page also records that the released 30 instances are an expansion of the paper's ~12, so its sample is not the paper's sample.

The recorded-agent package is framed with the same discipline: "Treat it as one inspectable observation, not a causal win or product ranking", and it discloses that the competing arm was cut off at a 900-second limit even though its recorded final application also passes 21/21 — publishing the fact that the competitor would have passed.

11. For Your Own Build

Steal

  • Use two thresholds, not one, and route the middle to a person. Fellegi-Sunter's match | possible | non_match with confirm=true on the uncertain classes is the cheapest correct answer to "when is a merge safe" — and the header's argument, that a single threshold "over-merges and destroys the audit trail", generalises to every dedup gate in this atlas.
  • Store the undo payload with the operation. One JSON column turns every merge into a reversible one and gives you a reflog for free.
  • Record why memories combined, not just that they did. signals alongside undo_payload is what makes a later "why is this one memory now" answerable.
  • Give the user a protect flag. One boolean exempting a memory from auto-merge, supersede and forgetting is the escape hatch every automatic lifecycle needs and almost none has.
  • Keep a content-free deletion receipt. Id, time, reason, and the counts of what the purge touched — enough to prove the deletion and audit its blast radius, without retaining the text you were told to forget.
  • Name the reason for every state transition from a fixed vocabulary. Nine values covering decay, competition, user action and system init means the log answers "why" and not only "when".
  • Label your unwired tables in the schema. "Designed for bi-temporal edge support but was never wired… Do NOT add queries against this table" is the single most useful comment in this report, and four other systems in this atlas would have avoided a finding by writing it.
  • Measure your ranking failing before you build around it. The backfill feature exists because the causal memory measurably ranks 7th of 8 under both dense and lexical retrieval.

Avoid

  • Retract a number you cannot reproduce, and say it may never be cited. The CauseBench notice is four sentences and it is worth more to a reader than any result on the page.
  • Read the paper you are citing, not the summary of it. The Answer-Accuracy-versus-CRS correction here fixes a claim the whole field was repeating, and it makes every competitor look better than the summary did.
  • Run the floor and the cheap baseline every time, and print the verdict. A no-memory arm tells you whether you are measuring the judge; a BM25 arm tells you whether the complexity was earned.
  • Score a capability structurally, not lexically. A metric satisfied by the system emitting a word is a metric about the word.
  • Write the limits section longer than the results section, and put the item that disqualifies your best number in it.
  • Do not mistake availability states for trust states. silent and unavailable say a memory lost a competition or was suppressed; neither says it is wrong, and a system with four states and no notion of correctness can look more epistemically equipped than it is.
  • Do not expect a deletion receipt to stop a re-write. The tombstone here wins during sync and is silent during capture.
  • Do not ship this shape without a scope story if more than one person will use it. Tags are a convention; there is no boundary.

Fit

This is for one developer on one machine who wants their agent to stop re-learning the same lesson, and who is willing to run a 25MB binary and trust a lot of cognitive-science machinery they will not read. AGPL-3.0 matters for anyone considering embedding it in a service.

The parts worth lifting even if you never run it are small and separable: the two-threshold merge classification, the undo payload, and the content-free deletion receipt. Each is a table and a policy.

12. Open Questions

  • Does any tool expose valid_from? The storage layer writes it from the caller and the query reads it; whether an agent can set a fact's validity through MCP was not traced, and it decides whether the bi-temporal axis is used or merely available.
  • How often does possible actually occur? The whole confirmation design rests on the middle class being non-empty and rare; no distribution is published.
  • What clears suppressed_by? Suppression compounds per call and reverses within 24 hours; the longer-term behaviour of the array was not traced.
  • What do the composition outcome tables drive? They record which memories were used together and what happened; whether anything reads them back into ranking is unclear from the tool surface.

Appendix: File Index

Merge and supersede — crates/vestige-core/src/advanced/merge_supersede.rs (the Fellegi-Sunter rationale at :19-41, the three-way classification :62), crates/vestige-mcp/src/tools/dedup.rs, crates/vestige-core/src/storage/migrations.rs:804-853 (merge_plans, merge_operations)

Deletion — migrations.rs:750-770 (deletion_tombstones and its rationale), sync_tombstones :735

States and transitions — migrations.rs:292-311 (memory_states), :349-362 (state_transitions and the reason vocabulary), :483-495 (memory_access_log)

Bi-temporality — migrations.rs:211-215, crates/vestige-core/src/storage/sqlite.rs:3686 (the point-in-time query), :874-935 (the insert), crates/vestige-core/src/memory/node.rs:336 (is_valid_at) and :494-506 (its tests), crates/vestige-core/src/memory/temporal.rs, crates/vestige-core/src/search/temporal.rs

The labelled dead table — migrations.rs:377-400 (knowledge_edges)

Neuroscience modules — crates/vestige-core/src/neuroscience/ (hippocampal_index.rs), the FSRS tables migrations.rs:313, :507, the dream cycle :532, consolidation_history :332

Composition — migrations.rs:854-900 (composition_events, composition_members, composition_outcomes)

Tool surface — crates/vestige-mcp/src/server.rs:247-420 (the thirteen tools, with the folding history in comments), crates/vestige-mcp/src/tools/

Tests — 1,088 test functions in crates/, plus tests/e2e, tests/hooks, tests/phase_1

Benchmarks — docs/BENCHMARKS.md (the CauseBench retraction :7-19, the Answer-Accuracy-versus-CRS correction :58-98, the four arms :106-118, the metric definitions :127-134, the nine-item limits section :140-180), benchmarks/memconflict/ (longmemeval.py, LONGMEMEVAL.lock.json), benchmarks/before-you-change-that/, benchmarks/agent-memory-eval/, benchmarks/memoryarena/, benchmarks/task-cost/

Appendix: Recorded Searches

Run from the root of the checkout at the pinned commit.

Claim Command Result at this pin
The benchmarks are in the tree ls benchmarks/ Five harnesses: agent-memory-eval, before-you-change-that, memconflict, memoryarena, task-cost
The prior benchmark is retracted sed -n '7,19p' docs/BENCHMARKS.md CauseBench formally withdrawn, its numbers retracted, citation forbidden
The upstream revision is pinned grep -n "Pinned revision" docs/BENCHMARKS.md ec51d5d3…
domains is indexed but not filtered grep -rn "domains" --include="*.rs" crates | grep -iE "WHERE.*domains|LIKE" One hit, a migration comment deferring the filter to a later phase; no read path uses it
No scope key reaches a read the scoping matrix row, re-checked Tags and connector cursors only

History

2026-09-18 — 3c5b1987… — re-pinned from 548ccae; 37 files and +5,879 lines, re-screened at the new pin. Human review withdrawn. The record read "a preview plan the caller inspects, with confirm=true required before an uncertain merge applies", and the word doing the work is caller: confirm is a field in the tool call, read at crates/vestige-mcp/src/trace_recorder.rs:460-466 as args.get("confirm").and_then(|v| v.as_bool()).unwrap_or(false) and documented in the tool description itself as "'purge' (for good; confirm=true)". The model sets it. That is a guard against a slip, like --force, not a person in the loop — the same ruling this atlas applied to a declared approve tool elsewhere. The scan / plan / apply separation remains the right shape and keeps the plan inspectable; nothing requires that anyone inspects it. bitemporal and audit_log hold, and the reversal payload stored with every applied operation is untouched by this.

2026-09-11 — 548ccae2… — re-read, 1,135 files and 195,125 insertions past the previous pin in a single commit. All three marks re-verified and unchanged, with capability_evidence records added where the report had none. The report's stated risk is not merely closed — the benchmark it was about was retracted by its own author. The previous edition said the headline benchmark lived on another branch and none of its numbers were checkable. At this commit five harnesses sit in benchmarks/, and docs/BENCHMARKS.md opens by formally withdrawing CauseBench — "Its harness no longer exists, its repro command 404'd, and its published numbers are retracted. CauseBench must never be cited… not even as 'an earlier result'" — together with a separately invalidated LongMemEval run, and states the principle behind the rewrite: "After a retraction, a number that cannot be reproduced by a stranger is worse than no number at all." What replaced it is documented carefully: an external benchmark with a pinned upstream revision; a correction to the field's reading of that paper (the six-number list everyone quotes is Answer Accuracy, not Conflict Recognition Score — "calling them CRS overstates the field by roughly a factor of two", with the best CRS at 0.2501); four mandatory arms including a no-memory floor and a BM25 bar, justified by MemDelta's finding that a single embedding-model change moved accuracy 6.2pp at p=0.004; a structural contradiction metric that "cannot be satisfied by the server merely emitting the word 'contradiction'"; a nine-item limits section longer than the results, which disqualifies the project's own best framing — "CRS-struct is not a head-to-head win… and must never be presented as such"; and a refusal to estimate the two white-box metrics the public data cannot support. The recorded-agent package discloses that the competing arm was cut off at its time limit even though its final application also passes 21/21. Section 10 is rewritten around this and five bullets were added to Steal; the Avoid bullet about putting a headline benchmark on another branch is removed as answered. Screened before reading: twenty-five findings; nothing was built or run.

2026-08-09 — a8b0a756… — first reading. Screened before reading: one auto-run surface (server.json), build-time execution in an npm manifest, and twelve dependency manifests inside the seven-day cooldown including Cargo.lock and pnpm-lock.yaml. The tree was read, never built, and no test or benchmark was run. The Silent Rotation benchmark is on a different branch and was not obtained.