What
scripts/check-agent-record.py does not validate that a recorded path:line
anchor points at what the record says it points at — and for ACTIVE rows it does
not validate anchors at all.
Demonstrated by mutation on PR #624's head during a scoped review:
| Mutation |
Result |
server_main.cpp:289 → server_main.cpp:99999 in an ACTIVE row |
NOT CAUGHT — check-agent-record.py exit 0, full agent-preflight.sh exit 0 |
delete the row spec's entire ## Now section (5,686 chars) |
NOT CAUGHT — preflight exit 0; check-doc-checkpoint.py exit 0 on the committed mutation |
ENGINE_ROWS 153 → 152 |
caught (control — the ratchet half IS live) |
Two distinct gaps:
ACTIVE is not in EVIDENCED_STATES. check-agent-record.py:1088 gates
anchor validation on EVIDENCED_STATES (:430-437), which excludes ACTIVE.
So an ACTIVE row's anchors are unchecked even for range.
- Shorthand anchors are invisible. A cell written as
`server_main.cpp:289`, `:312`, `:505`, `:560` exposes only the first as a
candidate; :312/:505/:560 are not anchors to any checker. And even in an
evidenced state, the check is that some anchor is in range — never that it
resolves to the named symbol.
Why it matters now
PR #624 shipped three anchors that had drifted by 4 lines, because a later commit
on the same branch inserted a comment above them. A fresh reviewer found them by
hand; no gate did, and no gate could have. They were then repaired by hand and
re-derived by hand a second time. That is three manual passes on something a
checker could assert mechanically.
The failure mode is quiet and cumulative: an anchor rots silently, and the record
keeps pointing confidently at the wrong line until someone reads it.
Scope
Two candidate fixes, either or both:
- Add
ACTIVE to EVIDENCED_STATES so its anchors are at least range-checked.
Cheap; catches the out-of-range case.
- Resolve shorthand
:NNN anchors against the nearest preceding path in the
same cell, and assert the line contains the symbol named beside it rather
than merely existing. Stronger, and it is what a reader assumes the record means.
Both change a checker's semantics, so per AGENTS.md this needs its own spec plus a
red-before mutation and green-after evidence. The mutations above are the
red-before evidence and reproduce in one command each.
Related: the same PR's drift is recorded in .agents/specs/serve-recipe-args.md.
Found during the scoped re-review of #624 (#606).
What
scripts/check-agent-record.pydoes not validate that a recordedpath:lineanchor points at what the record says it points at — and for
ACTIVErows it doesnot validate anchors at all.
Demonstrated by mutation on PR #624's head during a scoped review:
server_main.cpp:289→server_main.cpp:99999in anACTIVErowcheck-agent-record.pyexit 0, fullagent-preflight.shexit 0## Nowsection (5,686 chars)check-doc-checkpoint.pyexit 0 on the committed mutationENGINE_ROWS 153 → 152Two distinct gaps:
ACTIVEis not inEVIDENCED_STATES.check-agent-record.py:1088gatesanchor validation on
EVIDENCED_STATES(:430-437), which excludesACTIVE.So an
ACTIVErow's anchors are unchecked even for range.`server_main.cpp:289`, `:312`, `:505`, `:560`exposes only the first as acandidate;
:312/:505/:560are not anchors to any checker. And even in anevidenced state, the check is that some anchor is in range — never that it
resolves to the named symbol.
Why it matters now
PR #624 shipped three anchors that had drifted by 4 lines, because a later commit
on the same branch inserted a comment above them. A fresh reviewer found them by
hand; no gate did, and no gate could have. They were then repaired by hand and
re-derived by hand a second time. That is three manual passes on something a
checker could assert mechanically.
The failure mode is quiet and cumulative: an anchor rots silently, and the record
keeps pointing confidently at the wrong line until someone reads it.
Scope
Two candidate fixes, either or both:
ACTIVEtoEVIDENCED_STATESso its anchors are at least range-checked.Cheap; catches the out-of-range case.
:NNNanchors against the nearest precedingpathin thesame cell, and assert the line contains the symbol named beside it rather
than merely existing. Stronger, and it is what a reader assumes the record means.
Both change a checker's semantics, so per AGENTS.md this needs its own spec plus a
red-before mutation and green-after evidence. The mutations above are the
red-before evidence and reproduce in one command each.
Related: the same PR's drift is recorded in
.agents/specs/serve-recipe-args.md.Found during the scoped re-review of #624 (#606).