fix: generate the autonomy ledger skeleton instead of parsing live bytes - #124
Merged
Conversation
`autonomy_log_body()` copied lines from the live `autonomy_log.md` until one started with `|---`. That is the same "trust the live file's shape" pattern that made `empty_body()` stamp live registry entries into the public templates (#118) — it just had not fired yet. Both failure modes reproduced against the real ledger: * a task row inserted ABOVE the separator is copied verbatim; * a cosmetically reformatted separator (`| --- |`, which any markdown formatter may produce) means the break never fires — 231 live task records into a public repo. The canary scan is no backstop: a leaked row containing no dataset or person token returns zero hits, verified. The full-ledger case happens to be caught today only because some rows mention slacs1430 / B1938 / cosmos_web_ring. That is luck, and it is exactly the reasoning that made the #118 leak invisible. The header is now a constant asset and the source is never opened. It is byte-identical to what the parse produced for the current ledger, so this introduces no template drift — `autonomy_log.md` does not appear in the post-merge --check preview at all. Tests cover all five ledger shapes (well-formed, row-above-separator, reformatted separator, no separator, prose-then-table) plus a nonexistent source file, which is the strongest form of "never opens it". The end-to-end generated-tree fixture now plants live markers on BOTH sides of a reformatted separator. Control-tested: 7 tests fail against the old implementation. Closes #123 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…le 5b
Independent review (Codex) findings.
1. The tests were partly circular: `autonomy_log_body(src) == AUTONOMY_LOG_TEMPLATE`
compares the helper with what the helper returns, and the only independent
format check was `endswith("|")`. A stale or malformed constant would have
left every test AND `--check` green.
Generating instead of parsing removes the leak, but it also removes the
feedback that kept the header current — nothing else notices if the live
ledger grows a column and the template keeps shipping the old table. Adds:
* the live ledger must still START WITH the constant (the one test here
that reads the real file, skipped where no live ledger exists);
* the EMITTED template file must equal the constant, not just the helper's
return value;
* an independent shape check (H1 present, exactly a header row plus a
separator, matching column counts).
Control-tested both ways: a stale column fails the live-schema guard, and a
short separator fails both that and the shape guard.
2. Spec rule 5 was internally contradictory — it listed `autonomy_log.md` with
the EMPTY ledgers and said each title lives in `EMPTY_TITLES`, but the
ledger is SPECIAL, absent from that map, and carries prose and a table
rather than a title plus schema-pointer comment. Split into rule 5 (the six
EMPTY ledgers) and rule 5b (the autonomy ledger), each stating its own
generate-never-parse reasoning.
Refs #123
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Jammy2211
pushed a commit
that referenced
this pull request
Aug 4, 2026
This was referenced Aug 4, 2026
Jammy2211
added a commit
that referenced
this pull request
Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #123.
Overview
autonomy_log_body()copied lines from the liveautonomy_log.mduntil one started with|---. Same "trust the live file's shape" pattern that madeempty_body()stamp live registry entries into the public templates (#118) — it just had not fired yet.Pre-existing; surfaced by the independent review of #118. Sibling half of #121.
Both failure modes reproduced against the real ledger
| --- |— a cosmetic edit any markdown formatter makesThe canary scan is no backstop. A leaked row containing no dataset or person token returns zero hits — verified directly. The full-ledger case is caught today only because some rows happen to mention
slacs1430/B1938/cosmos_web_ring. That is luck, and it is exactly the reasoning that made the #118 leak invisible.The fix
Same shape as #118: the header is a constant asset and the source is never opened. Byte-identical to what the parse produced for the current ledger, so it introduces no template drift —
autonomy_log.mddoes not appear in the post-merge--checkpreview at all; only the two files changed here do.Spec rule 5 was also internally contradictory: it listed
autonomy_log.mdwith the EMPTY ledgers and said each title lives inEMPTY_TITLES, but the ledger isSPECIAL, absent from that map, and carries prose and a table rather than a title plus schema-pointer comment. Now split into rule 5 (the six EMPTY ledgers) and rule 5b (the autonomy ledger).The trade-off this creates, and how it is covered
Generating instead of parsing removes the leak — but it also removes the feedback that kept the header current. Nothing else would notice if the live ledger grew a column and the template kept shipping the old table.
So one test reads the real file and asserts the live ledger still starts with the constant. If the schema moves, that fails and tells you to update the constant — explicitly, not to re-add parsing.
Independent review (Codex)
Two findings, both fixed:
autonomy_log_body(src) == AUTONOMY_LOG_TEMPLATEcompares the helper with what the helper returns, and the only independent format check wasendswith("|")— a stale or malformed constant would have left every test and--checkgreen. Added the live-schema guard above, an assertion on the emitted template file rather than the helper's return value, and an independent shape check (H1 present, exactly a header row plus separator, matching column counts). Control-tested both ways: a stale column fails the live-schema guard; a short separator fails that and the shape guard.Codex separately confirmed what I had audited: the constant is byte-identical to the live ledger's first 11 lines (both SHA-256
6cad53f7…), the signature is safe at the single production call site, no other handler parses live bytes with shape assumptions, and there is no feedback loop — feeding the template back through spawn returns the same constant, and no shipped workflow regenerates it.Verification
--checkpreview: 2 drifts, both the files changed here. MemoryOK.API Changes
None.
spawn.pyis a repo-local generator with no importers outside this repo.autonomy_log_body(src)→autonomy_log_body(src=None);srcis accepted and ignored so the generator's dispatch stays uniform. Single production call site.Ship notes
Heart YELLOW (score 70,
red_reasons: []) on the same two reasons acknowledged earlier today — workspace validation, tenant-firewall manifest drift. Neither relates to this change.Post-merge:
/spawn --apply. Expectautonomy_log.mditself to be unchanged in the published template.🤖 Generated with Claude Code