decline_reason() only ever read a candidate's own grade, so a candidate
boundary-classify graded high/complete-triple -- meaning it cleared FR-4.2
fine -- fell through to the generic 'did not clear the filing threshold'
line when stability-classify downgraded it afterward. That's the opposite of
what happened, and it directly contradicted the correct FR-4.5 section
rendered a few lines below it in the same judgment-calls drawer, poisoning
the next audit's step-2b recall with a false reason.
Found live: real audit of anxious (2026-07-30) downgraded
agent-wip/release-policy-derivation at 11.85% of audited spend -- the one
gate it DID clear -- and the drawer said it didn't. Filed and now fixed as
kotkan/claude-plugin-inference-arbitrage#16.
Fix keeps FR-4.2's own check order first (a candidate can coincidentally be
named in an unrelated stability finding without having actually cleared
those checks) and only replaces the final fallback, since a candidate that
reaches it cleared every earlier check on its own grade -- it cannot have
also failed the filing threshold on its own merits.
New regression case (h) in tests/memory.test.sh. Suite: all tests pass.
An audit that forgets every run makes the analyst re-derive the same judgment
calls from scratch each time, and loses the declined-candidate reasoning that is
the most expensive thing a run produces.
Two new audit-snapshot subcommands, both with `pages`' contract — filesystem in,
JSON out, no MCP call ever made here:
memory-queries what to search before grading
memory-notes the drawers and kg facts to write after the run
Placement: target-scoped findings go to the audited plugin's own wing (room
`inference-arbitrage-audits`), mirroring FR-6.1's "the finding belongs on the
target's surface"; cross-target calibration goes to `claude-plugins` (room
`inference-arbitrage-lessons`) on every run regardless of outcome. Rooms are
namespaced by this plugin's name because plugin-named wings really do collide
with unrelated ones (`cluster`, `imagex`), and a namespaced room makes that a
shelving overlap rather than a content collision.
Reading is advisory and never a gate: nothing recalled may override
boundary-classify (FR-4.2) or stability-classify (FR-4.5), excuse skipping the
marker search, or re-grade a returned verdict.
The memory renderers deliberately do NOT reuse render_run/render_latest.
`snapshot.notes` is caller-supplied free text that legitimately reaches a wiki
page in this plugin's own repo, and must never reach a drawer in a wing shared
with other projects. They read from a fixed allowlist of structured fields —
allowlist, never blocklist, since a blocklist is one new snapshot field away
from leaking.
The MCP calls are not covered by tests/memory.test.sh and are not faked there.
That is the point of putting all the judgment in the script: what remains
untestable is one verbatim tool call with nothing in it to get wrong. The live
round trip was verified by hand against the real anxious snapshot.