backlog: file #1242 -- asvs-apply-cells.py is lossy in four ways and its guard sees one - #362
Merged
Merged
Conversation
…its guard sees one The writer re-renders every cell it touches and cannot append, so re-render is its only mode: every rescore and every anchor repair goes through it. Of the four kinds of key it can meet, it preserves one. A live top-level scalar survives. A live top-level TABLE falls through to the scalar helper, whose last branch stringifies it, so a table is rewritten as a TOML string. A top-level key supplied only by the payload is never emitted, because the carry-through loop skips on payload membership rather than on already-emitted. And any key inside a sub-table entry is dropped, since evidence and absence entries are each rebuilt from three hard-coded fields. The preservation guard compares top-level key sets and sub-table cardinality. A re-render that keeps every entry and hollows each one out passes both limbs; the mangled table is still a key, merely no longer a table; the payload-only drop is invisible by construction because the guard diffs against the live cell. The original block text is captured at the rewrite loop and then discarded, there is no hash or schema check, and no test references the script. Worse than silent: the loss removes a check instead of tripping one. The verifier documents these optional anchor fields as not-asserted when absent, so an erased pin downgrades an asserted structural claim to an unasserted one and the run reports green having checked strictly less. Filed at P1 because it is pending on the next routine operation. Until this morning every evidence entry carried exactly three keys and the sub-table limb could not fire; the D3 backfill merged today and put two structural pins on 1,710 of 1,998 anchors. The backfill is correct and does not touch the writer -- landing it is what armed a writer that was already lossy. Framing corrected by an adversarial pass before landing, and the item records it. The first draft said latent and described a clean two-way asymmetry; both were wrong. The measurement had been taken one commit before the backfill, where the counts genuinely are zero, so a stale checkout reproduces the wrong answer and reads as confirmation. A fifth limb about line-ending rewriting was investigated and rejected: autocrlf normalizes it back in the index, so the claimed review-diff consequence does not occur. No deployment axis: vault-only tooling that ships to nobody.
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.
Files one backlog item. Docs-only:
docs/BACKLOG.md, +33 lines, no other file.What it files
docs/security/asvs-apply-cells.py(vault-only tooling) re-renders any ASVS cell it touches.It cannot append -- it hard-refuses an id not already in the scorecard -- so re-render is its
only mode, and every rescore and anchor repair goes through it by design.
Of the four kinds of key it can encounter, it preserves one:
The preservation guard compares top-level key sets plus sub-table cardinality. A re-render that
keeps every entry and hollows each one out passes both limbs. The mangled table is still a key,
merely no longer a table. The payload-only drop is invisible by construction, because the guard
diffs against the live cell and that key was never there.
Why P1
The loss removes a check rather than tripping one. The verifier documents the optional anchor
fields as not asserted when absent, so an erased pin silently downgrades an asserted structural
claim to an unasserted one and the run reports green having checked strictly less. Silent in both
directions.
It is also pending, not hypothetical. Until this morning every evidence entry carried exactly three
keys and the sub-table limb could not fire. The D3 backfill merged today and put two structural
pins on 1,710 of 1,998 anchors. The backfill is correct and does not touch the writer -- landing
it is simply what armed a writer that was already lossy.
Verification, including what it corrected
The finding was put through an adversarial pass before landing (four independent lenses, then a
judge). All four refuted the draft, and the item records the corrections rather than quietly
absorbing them:
the backfill landed. That parent revision genuinely has zero of these keys, so a stale checkout
reproduces the wrong answer perfectly and reads as independent confirmation.
drop entirely; the real taxonomy is four-way.
core.autocrlf=truenormalizes it back in the index, so the blob is unchanged and the claimedreview-diff consequence does not occur. It is not in the item.
Notes
No deployment axis -- vault-only tooling that ships to nobody (CLAUDE.md section 0).
No ASVS cell ids appear in the item or in the commit body: those publish, the scorecard does not.
Banner validated with
parse_items(exactly one OPEN banner); added text carries only the OPENbanner and the amendment marker.