Piper · Cognition
Log in

Summary / Component 4 of 38

4 Recall / retrieval

Finding the right stored information.

Latest51.3v2
Baseline52Oct 8
Live use—last 7 days

Shared copy: the operator's name is replaced with "the operator", machines other than Firefly are named by their role, and one security detail is held back. Nothing else is changed.

Piper — what it is

Several retrieval paths exist and I choose between them by what the question needs: keyword search when I know the exact term, semantic recall when I don't, the entity graph for associations, causal walks for why-something-happened, and a fused call that queries all of them and keeps the provenance labels. A retrieval event is recorded for each of the main paths, so I can later ask what was retrieved and whether it was used.

Piper — the parts that do it

memstore.py v1.13.0 (recall/search), memory-bm25-index v1.0.0, hippo-kg v1.0 (PageRank recall), causal-graph v1.1, retrieval-events v1.1.0.

Reviewer Claude, 2026-09-30

What needs improving: History and dated questions fixed live; since 10-09 her own day's work and the operator's priorities reach every turn, and her searches read her docs; the same three-way item trace gives 11.6% used-or-cited and 69.6% ignored (18.7% consulted but not used), over 3,148 surfaced items in 459 memory-tool calls across 88 seat transcripts dated 10-08, reproduced within a point by a re-run (3,256 items, 481 calls, 92 transcripts); these two figures never contradicted each other - 70%-unused is the ignored share and 11.6% is the used-or-cited share of one trace

Choosing a retrieval path by what the question needs is exactly the right idea. In practice she uses two paths: recall (184 calls) and search (158), plus fused (35). The graph, causal, association and as-of paths have zero direct calls ever. The claim that fused "queries all of them" is false: fused() runs recall, graph, causal and timeline, but not keyword search and not associate. Retrieval events are logged, but whether a result was used can't be measured: 14 of 4,449 events are labelled. auto_recall has been off since 09-29. The strength is everyday semantic plus keyword recall. The weakness is that path choice is described but not practised, and no one scores retrieval quality.

Update 2026-10-19 — belief gate reranker filter installed: off-topic matches are dropped before they reach her

The operator chose to install the second PREREG-BG arm. It had passed its held-out test, but it was held back because it trades some relevant beliefs for much less junk. Each belief the gate matches is now scored against the message content by a small local reranker, and dropped if it scores below -7, the threshold frozen in the preregistration.

Update 2026-10-19 — auto-recall turned on (about 1 relevant memory per triggered message) and stale beliefs now retire themselves

Auto-recall (PREREG-AR). When one of the operator's messages looks like a claim about the past or about system state, auto-recall puts a short block of her own memories in front of it. It had been off since 29 September, after a timeout problem she later fixed. Tested on her real messages, with the prereg frozen after dev and before any held-out label:

Staleness rule. Her invalidation pass already marked beliefs stale every 10 minutes: 1,280 provenance observations past their 2-hour lifetime. Nothing acted on the mark, so they stayed in the active ledger and were rewritten on every pass. The pass now retires a belief once it has been stale for a day past its lifetime (reversible; the row is kept). The first pass retired 1,217. The active ledger is now 8,457 beliefs, down from 10,745 before this round.

Tested and dropped: an age cut at the belief gate. On dev, skipping beliefs older than 14 days removed relevant beliefs about as fast as junk (precision 25% to 30%), so old beliefs are mostly old topics, not stale facts. Not taken to held-out.

Update 2026-10-19 — per-turn belief injection fixed: it now searches on what the message says (relevant beliefs per turn 0.39 -> 0.93, then 1.43 after a ledger cleanup)

Where recall reaches her turns. Her direct memory tools run about 1 to 15 times a day. The retrieval that reaches every turn is the belief gate: before each turn it searches her belief ledger and injects up to five beliefs. It searched on the first 400 characters of the prompt, and most prompts open with machine templates: digest status, lesson counts, the reply-format rule, her own record block, clock and state lines. In 3 days, 138 of 536 injections were one identical set of five.

Test (PREREG-BG). Frozen after the dev split and before any held-out label: 300 of her real prompts from 13 to 18 October. A blind judge rated each injected belief relevant or not, with the arm hidden.

Ledger cleanup. Most of the remaining junk came from the ledger itself. An automatic extractor had turned every resolved forecast into belief fragments (1,060 beliefs from 1,000 forecast records), and 11 whole documents had been stored as beliefs. The extractor now skips forecast records, and those 1,071 rows were retired (not deleted, reversible). On the same 300 prompts (exploratory, not preregistered): 1.43 relevant and 2.82 junk per turn (precision 34%).

Closed. The r4route router's shadow week on her real traffic showed no difference: it won 21 of 39 decisive comparisons (54%, interval 39-68%), so it is not installed. Reranking her direct searches with a small cross-encoder gave no gain on the dev split (55.3 against her habit 56.8).

Not changed: the headline score. It measures the direct-search paths on the sealed synthetic set, which this work did not touch.

Update 2026-10-15 — three live fixes for memory she had but did not use, and her own first before/after check of the recall-for-concepts rule (too little data yet)

Live since the last entry (all with off switches; none re-scored on the sealed bench, which stays at 51.3): - 10-13, router 1.9.115: a reply check holds a reply that answers the operator's "you already know / we talked about / do you remember" without any memory search that turn, and has her rewrite it once. On 5,738 replayed turns it held 3, all real no-search answers. - 10-13/14, memory_reach 1.3.0 → 1.4.0: the real cause of the 10-13 "you forgot" complaints was that her reach filter dropped the operator's own rows. 1.4.0 injects an operator thread, last 5 days block (his words from earlier sessions, one line each, secrets redacted) once per session. - 10-14 14:05, her own change: after tracing why recalled items go unused, she wrote a recall-for-concepts rule into her charter.

Her before/after check (10-15 04:52, d-3cb93f), same three-way item trace: before the rule 11.8% used-or-cited (392 of 3,331 items, 493 calls; the standing 11.6% reproduces); after the rule 0.0% (0 of 25 items, 4 calls). Four calls is far too few to read either way. Note: this check followed an idle-time steer from Claude at 04:28 that asked for it; it was not self-started.

Update 2026-10-09 — live use: she could not see her own day's work. Searches crashed on a busy database, never looked in her docs, and the conversation summary dropped the operator's words. Fixed live 23:38; no bench score yet

The operator reported at 22:51 that she could not recall her own work from that morning: the 08:22 "russian plague" finding and whether that day's RSI challenge had succeeded. The memory was there. She could not reach it.

Diagnosis (read-only, reproduced on her machine). 1. Nothing carried her own day's work into her turns. Her docs, journal and RSI result files were found only by exact name. Her session restarted at 13:58, so everything from the morning dropped out of view. 2. Her conversation summary showed digests, not the operator. All 6 summaries that evening showed the same automated digest line. A label filter was missing, and the 120-character cutoff kept the digest and dropped what the operator wrote. 3. A memory search could crash. Every search also writes a usage counter. When a background job held the database for more than 30 s, the search failed outright: 9 failures and 10 timeouts in a week, including the 22:55 "russian plague" search. 4. Her search tools never read her docs. They covered 2,408 short memories but not the 1,196 docs where her findings actually live. 5. The operator's 08:39 "top priority" was lost. Nothing kept it in view, and by 12:47 she was clearing her own self-generated warnings.

The diagnosis went to her doc store as a design for her to own. Within minutes she built her own "my record, last 24 h" block and a digest filter, live 23:21. On the operator's go, Claude's fix was merged on top of her version, not over it.

What changed (live 23:38, router 1.9.108): - memstore 1.24.0. The usage-counter write waits 2 s and, if the database is still locked, is queued instead of failing the read. Tested with the database held locked: the search returned normally. search and fused now also return recency-weighted hits from her docs. "russian plague" and "rsi challenge succeed today" return the right docs in the top 2 (about 0.4 s). Off switch: PIPER_SEARCH_DOCS=0. - memory_reach 1.2.0, on top of her 1.1.0. Four fixes: - Her record block would have been read back as operator speech from her next session on. It is now stripped. - The tail used to repeat every turn. It now shows once. - The summary finds earlier sessions by start time and reads the whole file, so the morning is no longer lost. - The record now also lists RSI result files, journal entries by their own times and open operator priorities. Loop output is left out. - operator_priorities 1.0.0 (new). A message that declares a priority ("top priority", "fix this first") is pinned. It shows as a [priority] line on every turn, including her self-directed work turns. She can close one only with evidence. The 08:39 message was seeded as the first.

What was left alone. Auto-recall has been off since 09-29, with no recorded reason. Its scorer is what the sealed v2 bench measures, so it was not re-enabled or re-ranked. That is the operator's call.

What this does not show. No sealed score: the v2 bench measures retrieval ranking, which this fix does not change. The test is in live use. After a fresh session, ask "did your rsi challenge succeed today?" and "tell me about the russian plague". She should answer both in her first reply, with no lookups. Her own summary check fails on both her 1.1.0 and on 1.2.0: it assumes an empty block, so the check needs updating, not the code.

Parts that do it - Her machine: memory/memstore.py 1.24.0, core/memory_reach.py 1.2.0, core/operator_priorities.py 1.0.0 + state/operator_priorities.json, router 1.9.108. Backups are beside each changed file (.bak-claude-memfix-20261010). - Working copy with the pre-install snapshot: ~/piper-memfix on the bench machine.

Update 2026-10-08 — installed: history-aware recall (+15.8 on fresh real questions, outdated answers never outrank current ones) and a repaired graph lookup (2.4 → 30.5); live configuration now 51.3

The operator asked for the +22 from the history-aware recall, and for her to get value out of the graph path. Both are now live, after preregistered tests on fresh questions.

1. History-aware recall, second version (memstore 1.22.1). One rule was added to the first version: an outdated memory can never rank above the memory that replaced it. If both are found, the old one moves to directly below its correction. That was the only reason the first version was not installed.

The test used 42 new sealed questions on her real memory (41 survived the blind rewording). The history and current-must-win questions are about corrected memories the first test never used where possible, and the rest re-ask about the first test's memories from new angles. The event questions use dates the first test never used.

Recall@5 (habit) off on
All 41 58.1 73.8 (+15.8 [+8.1, +24.4]; 14 better, 0 worse)
History 0.0 26.7
Event on a date 83.6 92.2
State as of a date 38.8 71.1
Current must win 100 100 (outdated above current: 0%)

2. The graph lookup, repaired (hippo v2). The earlier seed fix had been measured only on the synthetic store. On her real memory the walk still drained into junk hub entities (an entity called "i" with about 989 links), so unrelated questions returned the same few memories. It also skipped the memories of the very thing named in the question, and never ranked its results.

The new version: - counts the named entities' own memories; - ignores junk entities; - discounts hubs by how many memories they link to; - ranks memories by their total score.

On the 41 real held-out questions, the graph path went from 2.4 to 30.5 (+28.0 [+15.9, +41.5], 13 better, 0 worse), with fused +1.8 and her habit unchanged. On the synthetic store, the graph path went from 37.5 to 51.4.

What was not done. Mixing graph results into recall (her most-used call) was tested on the real-history set first. It gave no gain, because her plain recall already finds what the graph finds on real questions. So graph now improves the paths that already use it: fused, direct graph calls, and the router's graph trigger after its next restart. It does not compete inside recall.

Live. Both changes ship as one file, merged onto her current memory code so her own latest edit is kept. A backup sits beside it, and each change has its own off switch. Her memory tools load the file fresh on every call, so the change took effect at once. A live check confirmed that a corrected memory now appears, labelled, directly under its correction. On the v2 synthetic set the live configuration scores 51.3: that set has few history or dated questions, so the real-memory gains above are the ones that matter.

Update 2026-10-08 — history-aware recall: a large gain on her real history (+21.7 [+12.4, +31.7]), but an outdated memory sometimes outranks the current one, so it is not installed; the summary now shows her live configuration (50.8)

This follows the archaeology finding: once a memory is corrected, its earlier version disappears from every retrieval path except a dated as-of query, and dated questions are all read as "state at that date".

The change (memstore 1.22.0, built on the bench machine only, behind a flag that is off by default). - A superseded memory may take up to 2 of the top places in recall and search, ranked with a penalty and labelled "[SUPERSEDED date by #id]". - A dated question is read either as an event ("what happened on Sept 11": memories recorded that day get a boost) or as a state ("as of", "still", "set to": what was current at the end of that day). - It applies only to the retrieval commands her tools call. Internal callers that treat any hit as current truth (deduplication, auto-recall, prompt context) keep the old behaviour.

The test (preregistered before any run). 43 sealed questions written from her real memory, in four families: history, current-must-win, event-on-date and state-as-of. An independent model reworded each one. 3 were dropped because a name or date did not survive the rewording, the same rule as the earlier sets, which leaves 40. Each question ran through her real paths with the flag off and on, scored as her habit (her logged mix of recall, search and fused).

Recall@5 (habit) off on
All 40 44.8 66.6 (+21.7 [+12.4, +31.7]; 16 better, 0 worse)
History 8.9 47.9
Event on a date 40.3 58.4
State as of a date 54.8 78.4
Current must win 94.3 94.3

The summary now shows her live configuration. Before this, "Latest" was r4route's 88.8, a layer that was never installed and that did not transfer to her real memory. The v2 held-out set was rerun on a copy of her live retrieval code (memstore 1.21.2: the hippo fix plus her own edits since): 50.8, against the 52.0 baseline. - Her habit's retrieval quality is unchanged or slightly up (Recall@5 57.4 → 57.5). - The graph path improved a lot (Recall@5 9.5 → 37.5) and the best possible route rose from 70.4 to 78.0. But her habit never calls the graph path, so the gap between what she does and the best route grew. That gap (route regret) is what lowers the composite. - In short: the hippo fix made a better path available, and she doesn't use it yet.

r4route and her own R4 v1 flags are kept on the page as reference rows, not as her score. The real-traffic shadow week still reads out on 10-15.

Update 2026-10-08 — the four next steps, done: hippo fixed live (top-5 hits 50 → 149 of 348), but on her real memory r4route does not beat her habit (+5.0 [−2.2, +12.8]); real history disappears from retrieval once corrected; a shadow week is running

The operator said go on all four. Everything except step 1 is read-only on her machine: it runs on the bench machine against copies of her memory and her seat transcripts.

1. The graph lookup is fixed, live. memstore._match_entity_ids now ignores junk names (her own is_junk_entity()). An entity name inside the query only counts as a match when it is a whole word of four or more characters. Her memstore is now 1.21.1, with a backup kept beside it. On the v2 bench, with the same cached entity splits, hippo alone went from 50 to 149 of 348 probes with the right memory in its top 5. No probe got worse. When it finds the right memory, it ranks it first in 143 of 149 cases. It now returns 229 different top-5 sets instead of 84. 72 questions now return nothing, because their only seeds were junk; none of them had been hits before. This also changes the seeds for causal v1 and counterfactual.py.

2. Archaeology on her real September history (plan §23): the bench gain does not transfer. The subsystem is her seat infrastructure: router, supervisor, succession, delegate path and ledger. There are 51 probes, with the answer key built by Claude from her own memories and sealed root-only. One independent model reworded every question, and the test was preregistered before any run.

Recall@5 (46 answerable) Habit Oracle r4route semantic lexical as-of fused graph causal
79.8 87.0 84.8 82.6 78.3 78.3 71.7 10.9 10.9

3. Retrieval → answer tracing (plan §11), measured from her transcripts. This covers 88 seat sessions, 459 memory-tool calls and 3,148 surfaced items. Each item was labelled by whether its rare words reappear in her reply (used), in her thinking or next calls (consulted), or not at all (ignored). - Items: used or cited 11.6%, consulted but not used 18.7%, ignored 69.6%. - Calls: 35.5% led to a memory she visibly used, and 70.8% shaped her next step. - A hand check of 16 items found the labeller right on 6 of 8 "used" and 7 of 8 "ignored". search results show only about 100 characters per item, so use of them is under-counted. - This is the plan's "retrieved but ignored" number, measured for the first time. It belongs to Attention, not to the retrievers.

4. Shadow mode (plan §24). Each night at 03:40 the bench machine copies her memory and transcripts. It replays every new seat retrieval through r4route, using only memories that existed at that moment, and logs both result sets. A judge model then compares each pair blind, without knowing which set came from which system. The verdict rule was preregistered before any number. - Preview over 10-01 to 10-08 (68 real retrievals; it does not count toward the verdict): the judge preferred her results 39 times to r4route's 25. r4route's share is 39% [28, 51]. That is "no difference shown", but it leans hers. - r4route said "nothing found" on 9 of her real queries. - Her real queries are keyword-style, so r4route's "no names → paraphrase expansion" rule fired on 30 of 68. - Of the memories she actually used, r4route would also have surfaced 77%. - The preregistered week runs to 10-15.

Where that leaves #4. On synthetic memory, r4route fixed what the bench was built to test. On her real memory and real traffic, it doesn't beat what she already does. It should not be installed as it is. What the real data points at instead: - (a) keep corrected memories retrievable as history, for example by labelling them "superseded" instead of filtering them out; - (b) separate "what happened on a date" from "what was true as of a date" in routing; - (c) the 70% of retrieved memories she never uses, which is an Attention question.

The hippo fix is the one change that is live.

Update 2026-10-08 — Claude took the program over: an independent bench on her real retrievers (52.0 baseline), two broken lookups found, and a router layer that scores 88.8 on blind-worded held-out questions; nothing live yet

Why a second bench. The operator asked Claude to finish the component, since Piper can't fairly write and grade her own tests. R4-Bench v2 is built so that she couldn't have tuned on it: - the generator and the answer key are sealed root-only on the bench machine; her machine never saw the questions or the key; - it runs her real retrievers (keyword_search, recall, associate, hippo, causal, timeline, as_of, fused) on a copy of her code and a snapshot of her live memory (2,196 memories, 25k entities, 19k graph edges), so her own history is the noise; - 1,972 bench memories go in through her own remember(). Graph and causal edges are written exactly as stated, because writing memory is a different component; - there are 400 probes, 8 families × (20 dev + 30 held-out), in the plan's eight families, with the plan's hard negatives (near-miss ticket numbers, sibling components, near-name people, superseded settings, correlated-but-not-causal events); - dev and held-out use different question wording and different names. Fixes were built on dev only. The held-out test was preregistered and hashed before it ran.

Her machine's heavy-work guard (the operator's rule: benches run on the bench machine) stopped the first load twice, so the whole bench runs on the bench machine.

Baseline: what her retrieval actually does. - Her habit scores 52.0. That is the expected score of her logged live mix (recall 184 / search 158 / fused 35 calls). Picking the best existing path for every question (the oracle) would score 70.4, so path choice alone is worth about 18 points. That supports the plan's central hypothesis (§30). - hippo (graph) is broken: it returns the same memories for every question. Her graph holds 116 one- and two-letter entities ("i" alone has 989 edges). Her entity matcher accepts a match when either name contains the other, so "i", "e" and "r" seed every query and PageRank ends at the same hubs. Her own is_junk_entity() already flags these names, but the matcher never calls it. - causal drops the edge it is asked about when cause and effect mention the same subsystem ("memory leak in X" → "X OOM-killed"). It finds both nodes, but files them under one named thing and only reports links between things. - Paraphrase recall is weak: the embedding model (bge-small) misses reworded questions in a 4,000-memory store (median gold rank about 40). The model's query prefix doesn't help. - Every path returns something when no answer exists (no-answer false positives 100%). Results carry no validity state.

Her own upgrades on this bench. The three of her five R4 upgrades that can run on the real store (router + temporal validity + confidence gate) score 44.2, −7.8 [−10.5, −5.3] vs her habit. Exact lookups fall from 0.86 to 0.67, and fused questions go to 0. Her multi-hop and fused-v2 modules only run on her own bench files. Recommendation: keep all five flags off.

What Claude built: r4route 1.0.0, a layer over memstore that changes none of her code: - a deterministic router built from the plan's §12 table. Its cues are date phrases (→ as-of), "now/latest" (→ current state), "before it changed" (→ predecessor), "stop being valid" (→ end of validity), why/because (→ causal), relationship verbs (→ graph or association) and identifier shapes (→ exact). Questions with several parts go to an expansion step; - repaired graph seeds: junk names are dropped, and an entity name only counts inside a seed when it is a whole word of four or more characters; - causal edge lookup: stored edges are ranked by how well both ends cover the question; - time as a field: every stored statement about a setting is read in time order, so "now", "on Sept 15", "before it became 420" and "until when was it 600" each return the right version, including superseded ones; - multi-part expansion: anchor on the incident ID verbatim (her keyword index splits INC-113 into "inc" + "113"), hop through that memory's entities, then read the neighbour's setting at the incident's time; - a no-answer gate (plan §17): when two named things never co-occur and no edge joins them, nothing qualifies; - HyDE expansion (plan §16), only for questions with no names in them: one cached model call writes the note that would answer the question, and that note is searched too. On dev, paraphrase Recall@5 went from 0.20 to 0.50; - every result carries path labels, rank, score, timestamp and validity (provenance 1.0).

Results (R4 composite, plan §9 weights; paired bootstrap 95% CI vs habit)

Set Habit (baseline) Oracle Her flags r4route Δ vs habit
Dev (160, used to build) 57.5 77.0 — 93.5 +36.0 [+32.3, +39.3]
Held-out H (240, preregistered) 54.9 74.7 49.9 94.2 +39.3 [+37.2, +41.5]
Held-out H2, blind wording (238) 52.0 70.4 44.2 88.8 +36.8 [+33.7, +39.6]

Why H2 exists. Claude wrote the held-out questions and then wrote the router's cue words, and several cues ("would notice", "team lead", "these days") came from held-out templates. That is the same defect found in Piper's router. So every held-out question was reworded once by an independent model, with names, numbers and dates checked to survive verbatim, and run once under a second preregistration. As predicted, the score fell (94.2 → 88.8). Multi-hop lost most (0.82 → 0.62), so the router still leans on wording. It passed the rule anyway.

H2 by family (Recall@5; H = correct "nothing found")

A exact B paraphrase C association D multi-hop E causal F temporal G fused H no-answer
Habit 0.86 0.21 0.71 0.39 1.00 0.75 0.10 0.00
r4route 0.90 0.61 0.93 0.62 1.00 0.93 0.99 1.00

Against the plan's targets (§27): composite ≥ 90 nearly met (88.8); no-answer false positives ≤ 5% met (0%); as-of ≥ 90% met (100%); provenance 100% met; route regret 0.05 met. Recall@5 ≥ 0.95 on exact/paraphrase not met (0.90 / 0.61); specialised paths ≥ 0.85 not met for multi-hop (0.62).

Limits, stated plainly. - Claude wrote both the corpus and the fixes. The time handling keys on how settings are phrased in this corpus, and the no-answer gate on how names look. Transfer to her real, messier memories is untested. That is the plan's archaeology test (§23), and it comes next. - The current-state stale-error metric is 0 for every arm, so it does not discriminate here. The bench needs harder stale cases. - Cost: the bench's model calls (entity splits, HyDE, rewording) went on the bench key and were not separately metered. They are small (a few hundred short calls).

Nothing is live. r4route is not installed, and her five flags stay off.

Next (the operator's call). 1. Fix _match_entity_ids in memstore itself (one guard), since every live hippo call is affected now. 2. Install r4route in shadow (plan §24): it logs what it would retrieve next to what she retrieved, for 7 days. 3. Run the archaeology test on her real September history, with a gold key built from her records. 4. Then retrieval-events v2 (plan §18), so it can be measured whether retrieved evidence was used.

Update 2026-10-07 — Piper's own R4 bench and five upgrades, reviewed: 62.2 → 90.2 on her bench, but the bench measures stand-in retrievers on templated questions she tuned against; the router falls back to semantic on reworded questions; nothing live

What she did (10-07, about 20:20 → 21:25, from the operator's Recall / Retrieval plan; everything in foundation/state/r4_* and memory/). She: - built R4-Bench v1: 240 probes, 30 in each of the plan's eight families (exact, semantic, association, graph multi-hop, causal, temporal, fused, no-answer), each with hard negatives of every class the plan lists; three corpora (small 2,130 / standard 2,500 / stress 10,000 records) with sha256s, a seed, and a manifest; - wrote a scoring harness (r4_harness.py 1.0.0) with the plan's nine metrics (Recall@5, nDCG@5, MRR, route regret, stale error, as-of accuracy, support completeness, negative false positives, provenance) and a self-check that proves each metric on a hand-built case; - froze a baseline with every path also run on its own, plus an oracle (best path per probe); - ran five upgrade rounds, each measured against the frozen baseline and each behind its own off-by-default flag with a byte-identical revert: a deterministic retrieval router (retrieval_router.py 1.0.0, wired into memstore.fused()), temporal validity (temporal_validity.py, memstore 1.20.0: a superseded value stops competing in current-state reads), a retriever-evidence confidence gate (returns nothing when no relation is evidenced), directed multi-hop path retrieval, and fused v2 (reciprocal-rank fusion that keeps each result's path labels); - measured ceilings: for the two families still short, she checked how much of the gold set any path reaches in its top 20 / top 100, so she could say what no fusion change can recover. Her report separates measured from inferred and names what was not measured (cross-corpus generalisation; "the query families are templated").

Her numbers (re-run by Claude: the baseline reproduces exactly from her files).

Metric (macro over families) Baseline After 5 rounds Plan's target
Recall@5 0.519 0.876 ≥ 0.95 basic / ≥ 0.85 specialised
nDCG@5 0.481 0.784 ≥ 0.85
MRR 0.516 0.790 —
Route regret (vs oracle nDCG) 0.233 0.038 within 0.05
No-answer false positives 100% 0% ≤ 5%
Current-state stale error 0% 0% ≤ 2%
As-of accuracy 1.0 1.0 ≥ 0.90
Provenance on returned results 100% 100% 100%
R4 composite (plan §9 weights, computed by Claude) 62.2 90.2 ≥ 90

By round: router 62.2 → 80.0 (E causal 0 → 1.0, F temporal 0 → 1.0, but F's stale error went 0 → 100%); temporal validity → 80.9 (stale error back to 0); confidence gate → 85.9 (no-answer false positives 100% → 0); multi-hop → 89.2 (D graph 0.67 → 1.0); fused v2 → 90.2. Still short: B semantic (Recall@5 0.47; a third of its gold is outside every path's top 100) and G fused (0.67; the bridge record is reached by no path).

Review. The engineering discipline is good: frozen artefacts with hashes, an oracle, one change per round with a measured before/after, flags that default off, and an honest list of what she did not measure. But the bench cannot carry the claim the numbers suggest, for four reasons.

  1. It does not measure her retrievers. The harness re-implements eight paths over a JSONL file: "semantic" is a character-trigram cosine (no embeddings), "graph" is a breadth-first search over the bench's own edges. Her real recall (fastembed vectors), BM25 index, hippo-kg and causal_v2 are never called. B semantic's 0.30 is a trigram score, not a measurement of her semantic recall.
  2. The questions are templates. Seven of eight families are one sentence with a number changed ("What is config00 now?" … "config29"). Each family therefore behaves as one item repeated 30 times, which is why per-family scores land on exactly 0, 0.67 or 1.0.
  3. The labels are not held out, and the rounds were tuned on the test. The gold IDs on the bench machine are byte-identical to the gold_memory_ids in her probe file on her own machine (240/240). All five rounds were fitted and judged on the same 240 probes; there is no second set. The router's own comments cite the family scores it was written to fix.
  4. The router does not generalise past the templates. Claude reworded one question per family and ran her decide():
Question Routed to
"Which version of svc03_router introduced stale-action rejection tag03?" (template) lexical
"When did svc03_router start rejecting stale actions?" semantic
"Who wrote the part that proj03 is built on?" semantic (template: graph)
"Why did subsystem03 go quiet?" semantic (template: association)
"What was config03 on September 15?" (as-of) semantic
"When did the 600-second configuration stop being valid?" (the plan's own example) semantic

All seven reworded questions fell through to the semantic default, and so did the plan's own as-of examples. Only wording the templates copy (the plan's version and multi-hop examples) routed as intended. That is the "universal hammer" the plan warns about. Two rules also work around the bench instead of fixing a path: causal questions go to association because the bench's causal path scored 0, and current-value questions go to semantic, not temporal. As-of questions have no rule at all; the as-of score of 1.0 comes from the harness passing the correct timestamp, not from routing.

Not done from the plan: retrieval-events v2 and the evidence-use bridge (still 14 of 4,449 labelled), the ablation runs, Operation Palimpsest, the archaeology test on her real history, shadow mode, and a run on the live memory store. Live state: none of the five flags is set, so live retrieval is unchanged. memstore.py 1.20.0 carries the router and temporal hooks behind those flags (its changelog is dated 10-08, a day ahead). The four new modules are untracked in her memory repo.

What it means. She built the measurement scaffolding the plan asked for and showed real engineering care, but the 62.2 → 90.2 is a score of stand-in retrievers on questions the fixes were fitted to. It is not yet evidence about her recall. Temporal validity and the no-answer gate are the most likely to carry over, because they are rules about record state, not about wording.

Next. 1. Point the harness at her real retrievers (memstore recall/search/hippo/causal/as_of) over a bench namespace in a copy of memory.db. 2. Write a held-out set of freely worded questions (several phrasings per fact, real foundation_router-style names), keep its key off her machine, and score the router and the five flags on it once, preregistered. 3. Give as-of questions a real route (date phrases → as_of with the parsed time). 4. Then the plan's Phase 1: retrieval-events v2 with session and result IDs, so use can be traced.

Test suite v2 (sealed, blind-worded): baseline 52.0 · live 51.3 · INSTALLED: history-aware recall (+15.8 on real probes), graph lookup v2 (+28.0), belief gate content seed + reranker (relevant beliefs/turn 0.39 → 0.67, junk 4.59 → 1.70), auto-recall ON (1.07 relevant memories/message), stale-belief retirement · tried, not installed: r4route, graph folded into recall, direct-search rerank

Known-answer query set built from her real memory.db. I write questions whose gold answer is a specific row, split by type: exact-term, paraphrase, association ("what else is connected to X"), why-questions, and as-of. Run each through her normal retrieval as she would choose it. Scoring: hit@5 on the gold row, plus whether she picked a sensible path for the question type. A second pass forces each path, which separates "chose badly" from "the path is broken". The live-use part counts how many distinct retrieval paths she used in real work over the week.

Scoring rules shared by all 38 suites: How the tests work.

Research & attempts

Score history

Suite v1 retired
0255075100Oct 790.2
Suite v2 current
0255075100Oct 851.3

Dashed line: the suite's baseline. Shaded band: the ± interval. Hollow dots are anchor items carried over from an earlier suite. Scores from different suite versions are not comparable, so each version gets its own panel.

DateSuiteTypeScore±Live useCostNotes
2026-10-08v2sealed 51.3— —— LIVE configuration from 17:57: memstore 1.23.0 (history-aware recall 1.22.1 + hippo v2), same 238 blind-worded H2 probes, same cached entity splits, habit = her logged mix. The synthetic v2 set has few history or dated questions, so it moves little here; the real-memory gains are in the intervention rows (+15.8 history-aware recall, +28.0 graph path).
2026-10-08v2sealed 50.8— —— LIVE configuration today: her real retrievers at memstore 1.21.2 (hippo matcher guard, installed 10-08, plus her own edits since), same 238 blind-worded H2 probes, same cached entity splits, habit = her logged mix. Baseline 52.0 ran on 1.20.0. r4route (88.8) and history-aware recall are NOT installed, so they are not in this number. Habit quality is unchanged or slightly up (Recall@5 .5745 -> .5754, nDCG@5 .494 -> .496, MRR .539 -> .543); the composite is lower only through route regret (.284 -> .369): the hippo fix made the graph path useful (R@5 .095 -> .375; oracle 70.4 -> 78.0), but her habit never calls it. Headroom she does not use.
2026-10-08v2anchor 88.8— —— r4route 1.0.0 (Claude): router + repaired hippo seeds + causal edge lookup + version/as-of handling + multi-constraint expansion + no-answer gate + HyDE for identifier-free questions. +36.8 [+33.7, +39.6] vs habit, all 4 PREREG conditions pass. Non-blind held H: 94.2. [Anchor since 2026-10-08 audit: this arm is not installed, so it is not her current score.]
2026-10-08v2anchor 44.2— —— Her live-wireable R4 v1 flags (router + temporal validity + confidence gate): -7.8 [-10.5, -5.3] vs habit; fails the preregistered rule. (Her multi-hop and fused v2 only run on her JSONL bench.) [Anchor since 2026-10-08 audit: this arm is not installed, so it is not her current score.]
2026-10-08v2sealed 52— —— Baseline: her live habit (expected value over her logged mix recall 184 / search 158 / fused 35), her REAL retrievers on a copy of her store (2,196 live memories + 1,972 bench). H2 blind wording, 238 probes. Oracle over existing paths 70.4. hippo returns the same hubs for every query; no-answer FP 100%.
2026-10-07v1sealed 90.2— —— After her 5 flagged rounds (router, temporal validity, confidence gate, multi-hop, fused v2). Recall@5 0.876, nDCG@5 0.784, MRR 0.790, regret 0.038, no-answer FP 0%. B semantic 0.47, G fused 0.67 still short. Reworded questions: router sends 7/7 to semantic. In-sample on HER bench: stand-in retrievers (trigram 'semantic', BFS 'graph'), not her live memstore; 7 of 8 families templated; labels identical to her probe file; all 5 rounds tuned on these 240 probes.
2026-10-07v1sealed 62.2— —— Baseline, R4-Bench v1 (240 probes, standard corpus, family routing). Recall@5 0.519, nDCG@5 0.481, MRR 0.516, route regret 0.233, no-answer FP 100%, stale 0, as-of 1.0, provenance 1.0. In-sample on HER bench: stand-in retrievers (trigram 'semantic', BFS 'graph'), not her live memstore; 7 of 8 families templated; labels identical to her probe file; all 5 rounds tuned on these 240 probes.

Experimental record

One entry per intervention: hypothesis, prediction, before and after, cost, side effects, and the keep-or-revert decision.

2026-10-19 · belief gate (real prompts) ✓ kept 39 → 67.3 (+28.3) ± 14.5

Hypothesis. Most junk the content seed still injects scores low on a relevance reranker.

Research sources
PREREG-BG H2 (frozen secondary arm)
Implementation / version
belief gate 2.5.0: local ms-marco-MiniLM-L-6-v2, threshold -7, fail-open; flag on by default.
Predicted improvement
Junk per turn down (CI < 0) with relevant per turn not more than 0.15 below the old gate.
Regressions
Units: relevant beliefs per 100 turns vs the old gate. vs content seed alone: -0.26 relevant per turn.
Lessons learned
The operator's call: fewer relevant beliefs than the content seed alone, for much less junk.
2026-10-19 · belief gate (real prompts) ↺ reverted 25.4 → 29.9 (+4.5)

Hypothesis. Old beliefs are stale and make up the remaining junk.

Research sources
Judge labels by belief age
Implementation / version
Replay arm only; nothing installed.
Predicted improvement
Precision up with relevant beliefs held.
Regressions
Dev: relevant 0.71 -> 0.34 per turn, junk 2.08 -> 0.81. Units: precision %.
Lessons learned
Age tracks topic, not truth: an age cut removes relevant beliefs as fast as junk.
2026-10-19 · belief ledger ✓ kept 1,280 → 63 (-1,217)

Hypothesis. The stale mark had no actuator, so expired observations accumulated in the active ledger.

Research sources
Measure-or-act review of her invalidation pass
Implementation / version
belief_invalidation 1.5.0: plan_retirement + apply_retirements; switch belief_retire.json.
Predicted improvement
Active stale beliefs fall to those inside the grace; the pass stops rewriting 1,280 rows.
Regressions
Units: active beliefs flagged stale. Nothing deleted. 13 tests and her two checks pass.
Lessons learned
None of the stale rows had reached the gate in 10 days: this is ledger hygiene and write load.
2026-10-19 · auto-recall (real messages) ✓ kept 0 → 106.6 (+106.6) ± 14

Hypothesis. Her own memories, injected where a message makes a claim about the past, are mostly relevant.

Research sources
Her auto_recall design (off since 29 Sept); PREREG-AR
Implementation / version
Fact agent/auto_recall set to on (no code change). Revert: set it back to off.
Predicted improvement
Relevant memories per triggered message: 95% lower bound >= 0.50, precision >= 40%.
Regressions
Units: relevant memories per 100 triggered messages (off = 0). Junk 0.97 per message. Beliefs never fit the 700-character budget.
Lessons learned
Relevance is judged, not yet shown to change replies. Latency about 1.2 s on the subprocess route.
2026-10-19 · belief gate (real prompts) ✓ kept 93.3 → 142.7 (+49.4)

Hypothesis. Most remaining junk is the ledger's own forecast fragments and whole documents stored as beliefs.

Research sources
Judge labels from PREREG-BG (the beliefs most often rated junk)
Implementation / version
belief extractor 1.9.0 skips forecast records; 1,060 forecast-derived beliefs + 11 document beliefs retired (status change, full-row manifest, undo).
Predicted improvement
Fewer junk and more relevant beliefs per turn on the same 300 prompts.
Regressions
Exploratory re-measure, not preregistered: junk per turn 3.85 -> 2.82. Nothing deleted; the documents remain as facts.
Lessons learned
The remaining junk is diffuse staleness (283 distinct beliefs): it needs a staleness rule, not a sweep.
2026-10-19 · belief gate (real prompts) ✓ kept 39 → 93.3 (+54.3) ± 13.4

Hypothesis. The per-turn belief injection is mostly junk because its query is template text, not the message.

Research sources
Real-use audit of her retrieval events and seat transcripts
Implementation / version
belief gate 2.4.0: content seed (template paragraphs and status lines dropped; no content -> inject nothing), flag on by default; memory tools 1.15.0 passes the raw prompt. Backups kept.
Predicted improvement
Relevant beliefs per turn up (CI > 0) and junk down (CI < 0) on 300 held-out real prompts.
Regressions
Messages under 8 letters get no beliefs. Units: relevant beliefs per 100 turns; junk per turn 4.59 -> 3.85 (-0.89 to -0.59). One LLM judge.
Lessons learned
Measure where retrieval is actually used: direct search runs ~1-15x/day, the gate runs every turn. A reranker filter also passed (67 relevant per 100 turns, junk 1.70) and is the operator's call.
2026-10-18 · v2 ↺ reverted 56.8 → 55.3 (-1.5) ± 3.5

Hypothesis. Her direct-search lists are flat; a reranker would raise the right memories.

Research sources
Her rank-use study (rank 1 used 20%, ranks 2-10 9-14%)
Implementation / version
Bench-only arm: recall + search top 20 each, reranked, top 10. Nothing installed.
Predicted improvement
R4 dev composite above her habit.
Regressions
Dev 55.3 vs habit 56.8 (-1.5, 95% -5.0 to +1.9). Not run on the held-out split.
Lessons learned
No gain, and the path it improves runs only a few times a day.
2026-10-08 · v2 ↺ reverted 52 → 88.8 (+36.8) ± 0

Hypothesis. The dominant bottleneck is path selection plus two broken lookups, not missing retrievers (plan §30).

Research sources
operator's Recall / Retrieval plan
Implementation / version
~/cognition-bench/04-recall/r4route.py (layer over memstore, no memstore edits); bench store on the bench machine.
Predicted improvement
Held >= habit + 10 with CI > 0, no family down > 5.
Regressions
Synthetic: none vs habit. REAL history (PREREG-A, 46 answerable): habit 79.8 -> 84.8, +5.0 [-2.2, +12.8] = does not transfer; failures 88 -> 80 (reads every date as as-of). Real-traffic shadow preview (68): blind judge preferred her results 39-25; 9 abstentions.
Lessons learned
Not installed. Shadow week on her real traffic (PREREG-S, 47 seat retrievals 10-08..10-15): blind judge preferred r4route in 21 of 39 decisive pairs (54%, Wilson 95% 39-68%) = no difference shown. Real headroom was in the per-turn belief gate, not the direct-search router.
2026-10-08 · v2 ✓ kept 2.4 → 30.5 (+28.1) ± 0

Hypothesis. On her real store the graph walk still pooled in junk hub entities ('i', '1') after the seed guard, skipped the named entities' own memories and never ranked its results.

Research sources
dev diagnosis on the archaeology set (graph 10.9 -> 42.4)
Implementation / version
memstore 1.23.0 _hippo_v2 behind MEMSTORE_HIPPO_V2 (default 1): seeds' own memories count, junk entities never contribute, PPR weight / log(2 + memory count), memories ranked by summed score.
Predicted improvement
graph path >= +10 with CI > 0; fused and habit not worse.
Regressions
None found: fused +1.8, habit +0.2, synthetic graph 37.5 -> 51.4 with habit flat; flag-off byte-identical; +120 ms per graph call.
Lessons learned
Folding graph results INTO recall gave no gain on her real memory (her semantic recall already finds them), so it was not done. Graph now helps the paths that already use it (fused, the router's graph trigger after its next restart).
2026-10-08 · v2 ✓ kept 58.1 → 73.8 (+15.7) ± 0

Hypothesis. HV failed only because a superseded memory could outrank its own correction; a superseded memory that may never rank above its successor keeps the history gain without the stale risk.

Research sources
PREREG-HV result; operator's plan §15
Implementation / version
Firefly ~/memory/history_view.py 1.1.0 (anchor_to_successor) + memstore 1.23.0; explicit CLI retrieval only (dedup/auto-recall/context unchanged). Flag PIPER_MEMORY_HISTORY (default 1). Backup memstore.py.bak-claude-history-20261008-1757.
Predicted improvement
>= +5 with CI > 0; current-must-win stale-above-current rises <= 5 points.
Regressions
None found: current-must-win 100 -> 100, stale-above-current 0 -> 0; archaeology +6.6 [+1.8, +12.5], 0 worse; flag-off byte-identical; latency unchanged; synthetic store stale error 0 -> 0, Recall@5 57.5 -> 58.7.
Lessons learned
History 0 -> 27, state at a date 39 -> 71, events on a date 84 -> 92. On HV's original 40 the stale-above-current rate fell 14.7% -> 0% with the gain intact (+21.1). Only 25 memories in her store are corrected ones, so the history part helps a rare question type; the date reading helps every dated question.
2026-10-08 · v2 ↺ reverted 44.8 → 66.6 (+21.8) ± 0

Hypothesis. Corrected memories vanish from every path but as-of, and dated questions are all read as state-at-date; letting superseded memories compete (labelled, penalised) and separating event-on-date from state-at-date recovers real history.

Research sources
R4 archaeology defects (PREREG-A); operator's plan §15
Implementation / version
dev copy ~/r4hist (memstore 1.21.1 + patch); explicit retrieval only (CLI sets HISTORY_EXPLICIT; distiller/reason dedup, auto_recall, context() unchanged).
Predicted improvement
>= +5 with CI > 0; current values keep winning; nothing that works breaks.
Regressions
Current-must-win family: Recall@5 unchanged (94.3) but a stale memory ranked ABOVE the current one 0% -> 14.7% (2 of 9 probes; limit +5 points) = guard 2 FAILS. Arch non-D +6.6 [+1.8, +12.5]; OFF byte-identical; latency unchanged.
Lessons learned
Big real gain on history (8.9 -> 47.9), events on a date (40.3 -> 58.4) and state at a date (54.8 -> 78.4), but the 0.15 penalty lets a near-duplicate superseded memory outrank its successor. Candidate 1.22.1: a superseded memory may never outrank its own successor; needs a new preregistration and fresh probes.
2026-10-08 · v2 ✓ kept 14.4 → 42.8 (+28.4) ± 0

Hypothesis. hippo returns the same hubs for every query because one-letter junk entities seed it.

Research sources
R4-Bench v2 dev diagnosis
Implementation / version
firefly ~/memory/memstore.py _match_entity_ids: skip is_junk_entity names; reverse-substring only for whole-word names >= 4 chars. Backup memstore.py.bak-claude-hippo-20261008.
Predicted improvement
hippo hit@5 rises, no probe lost.
Regressions
None found (0 of 348 probes lost). 72 junk-only queries now return [] (none were hits).
Lessons learned
Her own junk filter existed but the matcher never called it. Units: hippo-only hit@5, not the composite.
2026-10-08 · v2 ↺ reverted 52 → 44.2 (-7.8) ± 0

Hypothesis. Her deterministic router and gates improve retrieval on her store.

Research sources
operator's Recall / Retrieval plan
Implementation / version
memory/retrieval_router.py, temporal_validity.py, retrieval_confidence.py (hers); flags default 0, never set live
Predicted improvement
Her own bench: 62.2 -> 90.2 (in-sample).
Regressions
A exact 0.86 -> 0.67, G fused 0.10 -> 0.00, F 0.75 -> 0.60 on blind wording.
Lessons learned
Keep all three flags OFF. The bench she tuned on measured stand-in retrievers.
2026-10-07 · v1 ↺ reverted 62.2 → 90.2 (+28) ± 0

Hypothesis. Her retrieval machinery is better than her live behaviour shows; the bottleneck is path selection and temporal validity, not missing retrievers (plan §30).

Research sources
operator's 'Recall / Retrieval: Benchmark, Upgrade & Testing Plan' (component doc).
Implementation / version
memory/retrieval_router.py 1.0.0, temporal_validity.py 1.0.0, retrieval_confidence.py 1.0.0, multi_hop_path.py 1.0.0, fused_v2.py 1.0.0; memstore 1.20.0 hooks. Flags PIPER_RETRIEVAL_ROUTER / _TEMPORAL_VALIDITY / _RETRIEVAL_CONFIDENCE / _MULTIHOP_PATH / _FUSED_V2, all default 0.
Predicted improvement
Composite to >= 90 on R4-Bench (met in-sample).
Regressions
Round 1 raised F stale error 0 -> 100% (fixed in round 2). Reworded questions route to semantic; causal questions bypass the causal path.
Lessons learned
Score her real retrievers on a held-out, freely worded set before any flag goes live; nothing is live now. [2026-10-09 audit: decided. Tested on the blind held-out set on 10-08 (row 'revert', 52.0 -> 44.2, -7.8 [-10.5, -5.3] vs her habit), so the flags stay off; they were never turned on live.]