Governed memory · internal benchmark · B2

A snapshot is right the day you write it — and wrong forever after

Our first benchmark beat an agent with no memory, and we said the credible opponent was a well-written CLAUDE.md snapshot. This is that fight. Same task, one difference: the decision changed after the snapshot was taken.

The honest scope of this result

A snapshot loses. But so do we — to a plain vector store — on simple supersession.

The result below is real and reproducible. But it proves something narrower than "governance handles change," and it is worth being precise about which.

The opponent here is a CLAUDE.md snapshot: a thing that structurally cannot update. It lost for being uninformed, not for being ungoverned. So we built the fight we had been avoiding — the same task against an ungoverned memory store holding both decisions, with perfect recall and timestamps (deliberately more than a real vector index gets):

armcorrectshipped the STALE valuemedian timetokens
static — the snapshot (this page)0/54419s16,655
ungoverned — both docs, dated5/5026s3,802
mla — governed memory5/5076s6,771

An ungoverned store solves plain supersession perfectly — three times faster than us, on half the tokens. It sorts by date and it is simply right. No governance required. Where governance buys nothing, its overhead buys nothing either, and that is our number to own.

The claim, stated narrowly and defensibly: governance earns its keep in exactly one place — when the newest document is not the authoritative one. A rejected proposal is newer than the decision it failed to overturn. A reverted change is newer than what it reverted. A draft is newer than the approved spec. A vector store sorts by time and hands you the wrong one with total confidence — and we measured that separately at 0/5 (trust-containment), where it did not go wrong so much as get stuck. "We handle change" was too broad. "We handle change when time doesn't tell you who's right" is true.

The decision rule that forced this correction was pre-registered before the fixture existed: if the ungoverned arm scores ≥4/5, raw retrieval with timestamps solves supersession, our "change" claim does not extend to it, and this page gets corrected. It scored 5/5.

Preliminary · internal N = 5 per arm 10 runs fixture generated per run
run date 2026-07-11 claude 2.1.197 mla 0.2.14 model claude-opus-4-8 base bcc9c646 host darwin 25.5
The question: what is the export API rate limit right now?
5/5mla
current
vs
0/5static snapshot
current

The static arm holds a competent, accurate team decision record in CLAUDE.md — the kind a careful team really commits. It was simply written before the decision was revised. Governed memory tracked the revision; the file did not. mla returned the current value in all 5 trials, without a single filesystem search. The snapshot arm never got there: twice it confidently reported the stale number, and three times it searched until the clock ran out, unable to confirm whether what it held was still true.

What changed under the agent's feet

The fixture is generated fresh on every run

Nothing here is authored or memorized. Each run invents two random values, seeds the first as a governed decision, then supersedes it — and verifies the store actually serves the new one before any agent starts.

T0 · decided
Rate limit set to 106
Seeded into governed memory and accepted. Also written into the static arm's CLAUDE.md as a decision record — accurate at the time.
T1 · revised
Superseded by 872
A new accepted revision retires the previous one. The governed store now serves 872. The file still says 106 — as files do.
Now · asked
"What is the limit currently?"
Only 872 is correct. The value exists in the governed store and nowhere the agent can read.
Outcome

Right vs. stale

the snapshot cannot know it went out of date
metricmlastatic
reported current value5/5 ✓0/5 ✗
retrievalgroundednone
filesystem searches0 (every trial)7 (5–13)
agent time (median)59 s3/5 hit the cap

Cliff's δ = −1.00 on searches — perfect separation, not a shifted average. mla never opened the repo; the snapshot arm never stopped looking.

Cost of being wrong

3.5× the tokens

the losing arm is also the expensive one
metricmlastatic
context tokens (median)200k705k
range164k–253k534k–1.54M
retrieve calls3–60 (no access)
separationδ = −1.00 · p ≈ 0.01

Uncertainty is not free. Unable to verify whether its note was current, the snapshot arm searched, re-read, and reasoned — spending 3.5× the context to arrive at the wrong answer, or at none.

Every trial, nothing averaged away
mla — governed memory
mla 1✓ current (872)59 s · 0 searches · 5 retrieves · grounded
mla 2✓ current (872)61 s · 0 searches · 4 retrieves · grounded
mla 3✓ current (872)43 s · 0 searches · 3 retrieves · grounded
mla 4✓ current (872)39 s · 0 searches · 3 retrieves · grounded
mla 5✓ current (872)64 s · 0 searches · 6 retrieves · grounded
static — a competent CLAUDE.md snapshot
static 1✗ no answerhit 450 s cap · 7 searches
static 2✗ no answerhit 450 s cap · 7 searches
static 3✗ stale (106)214 s · 8 searches · answered from the file
static 4✗ stale (106)250 s · 5 searches · answered from the file
static 5✗ no answerhit 450 s cap · 13 searches

Both failure modes are worth naming. Stale is the dangerous one — a confident, precise, wrong number an engineer would act on. No answer is the honest one — the agent sensed its note might be out of date and hunted for confirmation it could never obtain. Neither is a working memory.

Why this number is trustworthy

The fixture proves itself before any agent runs

The failure mode we feared was the opposite of a flattering one: an unfair win. If the store hadn't finished indexing the new value, mla would fail for a reason that has nothing to do with the claim. So the harness refuses to run until it has confirmed the store serves the current value — and refuses to score a trial whose backend was unhealthy.

01 · fixture
Generated, not authored
Two random values per run, distinct by construction. Nothing to memorize or pre-train on.
02 · seal
Supersession verified
The harness polls retrieval until the store demonstrably serves T1. A fixture that hasn't indexed is re-seeded, never run.
03 · snapshot
Steelmanned, not strawmanned
The static arm gets an accurate, well-formed decision record. It contains T0 only — it cannot leak T1.
04 · isolation
Sandboxed
No ~/.meetless, no localhost network, fake HOME, mla off $PATH. It tries anyway — transcripts show it reaching for the store.
05 · oracle
Answer never on disk
The expected value is injected at launch and deleted from the harness's own environment before the agent spawns.
06 · health
A dead backend is not a loss
If retrieval is unreachable, the trial is marked invalid and the run aborts — an outage can never be scored as an mla failure.
Vector 06 is not hypothetical. During an earlier run the retrieval service died mid-flight; every call returned unreachable, the agent burned the full timeout retrying, and the row landed as success=false. That number would have been wrong in our favor's opposite direction — and worse, it would have been publishable. The guard exists because we got caught by it.
Re-run, 13 Jul 2026

We re-ran this because our own evidence was thinner than the claim

The original static 0/5 was true, but only 2 of those 5 trials actually demonstrated the thing we said it demonstrated.

Two of the five had been stalled by the machine going to sleep mid-run — a suspended process runs no timers, so our cap never fired and the trial produced no answer at all. A third ran out the clock. Only two trials actually showed the static arm confidently returning the superseded value, which is the claim the page was making.

The error ran in our favour — it made the opponent look worse than it is — so we re-ran it rather than footnoting it. On the honest re-run, 4 of 5 static trials returned the stale value and the fifth timed out. The conclusion survived; the evidence for it is now real. Had it gone the other way we would have retracted the number.

Originally publishedHonest re-run
static: returned the STALE value2/54/5
static: no answer (stall / timeout)3/51/5
static: task passed0/50/5
mla: task passed5/55/5

How to read this

# reproduce
cd tools/bench-mla
node run.mjs --tasks governed-freshness --arms static,mla --trials 5
node analyze.mjs            # runs/ → results/summary.json
governed-freshness · 5 trials · 2 arms · fixture regenerated per run · static sandboxed (deny-read + deny-localhost); mla via plugin MCP