Found by run 2 of the validation program (#16) against QuantEcon/meta on 2026-08-25. Record in #56 §5. This is invisible in the finished bundle — it was found by sampling findings.md every 15–20 seconds from a second session while the run executed.
The defect
Measured write pattern across the run: the open pass (138 items) checkpointed 15+ times, in batches of 8–9 entries every 75–120 seconds. The closed pass (179 items) checkpointed once — nothing for the entire survey, then the complete 10.8 KB section in a single write.
SKILL.md phase 2 states the guarantee this breaks: "Write each item's finding to findings.md as it is verified — the closed pass too … so that an interrupted run loses one item rather than the phase." On the closed side an interrupt loses the phase: all 179 threads re-read from scratch.
This is #21's defect 2 in a new form. Defect 2 was "the closed side is never checkpointed", and audit 0.2.0 added the ## Closed heading plus the two-partition resume rule. That fixed the format and left the granularity untouched — the closed side is still all-or-nothing, now with a heading to be all-or-nothing under.
The second-order problem: two conventions that do not compose
A fix has to address both halves, because they were written independently.
deliverables.md permits grouped entries, and run 2 used them: "entries are grouped where a whole family shares one answer; every closed issue is named exactly once" — 9 **#N headers covering all 179 closed issues. That is legitimate and produces a better-reading catalog.
But the resume rule addresses by issue number: "resume at the lowest number with no entry under the matching heading". That is not well-defined against grouped prose. So even if the closed pass were checkpointed incrementally, a resume could not address into it — it would find most closed issues lacking a **#N entry and re-verify them, which is the "re-verifying the whole set" failure the rule exists to prevent.
Suggested shape of a fix
Either checkpoint the closed pass per batch with an explicit machine-readable coverage line (for example a <!-- covered: 87,88,89,… --> marker per write, which survives grouping), or state plainly that the closed pass is atomic and have the resume rule treat a partial ## Closed section as absent and redo it. The first preserves the guarantee; the second at least makes the behaviour honest and the resume deterministic. Whichever is chosen, the guarantee sentence in phase 2 and the grouping licence in deliverables.md should end up agreeing.
Small related fix, same rule
SKILL.md's guard names two wrong ways to infer progress — "do not infer progress from the file's length or from a single block" — but not "the highest recorded number". Run 2 wrote its post-resume block out of numeric order (261, 282, 263, 264, …), which is harmless under the set-difference rule as written but would be a silent-skip hazard for any implementation that took the high-water shortcut. Adding that third item to the list closes the gap.
Found by run 2 of the validation program (#16) against
QuantEcon/metaon 2026-08-25. Record in #56 §5. This is invisible in the finished bundle — it was found by samplingfindings.mdevery 15–20 seconds from a second session while the run executed.The defect
Measured write pattern across the run: the open pass (138 items) checkpointed 15+ times, in batches of 8–9 entries every 75–120 seconds. The closed pass (179 items) checkpointed once — nothing for the entire survey, then the complete 10.8 KB section in a single write.
SKILL.mdphase 2 states the guarantee this breaks: "Write each item's finding tofindings.mdas it is verified — the closed pass too … so that an interrupted run loses one item rather than the phase." On the closed side an interrupt loses the phase: all 179 threads re-read from scratch.This is #21's defect 2 in a new form. Defect 2 was "the closed side is never checkpointed", and
audit0.2.0 added the## Closedheading plus the two-partition resume rule. That fixed the format and left the granularity untouched — the closed side is still all-or-nothing, now with a heading to be all-or-nothing under.The second-order problem: two conventions that do not compose
A fix has to address both halves, because they were written independently.
deliverables.mdpermits grouped entries, and run 2 used them: "entries are grouped where a whole family shares one answer; every closed issue is named exactly once" — 9**#Nheaders covering all 179 closed issues. That is legitimate and produces a better-reading catalog.But the resume rule addresses by issue number: "resume at the lowest number with no entry under the matching heading". That is not well-defined against grouped prose. So even if the closed pass were checkpointed incrementally, a resume could not address into it — it would find most closed issues lacking a
**#Nentry and re-verify them, which is the "re-verifying the whole set" failure the rule exists to prevent.Suggested shape of a fix
Either checkpoint the closed pass per batch with an explicit machine-readable coverage line (for example a
<!-- covered: 87,88,89,… -->marker per write, which survives grouping), or state plainly that the closed pass is atomic and have the resume rule treat a partial## Closedsection as absent and redo it. The first preserves the guarantee; the second at least makes the behaviour honest and the resume deterministic. Whichever is chosen, the guarantee sentence in phase 2 and the grouping licence indeliverables.mdshould end up agreeing.Small related fix, same rule
SKILL.md's guard names two wrong ways to infer progress — "do not infer progress from the file's length or from a single block" — but not "the highest recorded number". Run 2 wrote its post-resume block out of numeric order (261, 282, 263, 264, …), which is harmless under the set-difference rule as written but would be a silent-skip hazard for any implementation that took the high-water shortcut. Adding that third item to the list closes the gap.