fix(pm): teach footerReAnchoring the second re-anchor shape — a moved newline is not a lost byte - #18758
Merged
Conversation
… newline is not a lost byte post-stamped exited 4 (EXIT_NOT_STORED) on every artefact a seat wrote with its own attribution footer. The platform stores such a body with its trailing newline moved to before the footer's own rule: equal length, one byte moved, zero lost. `footerReAnchoring` recognised only an APPENDED footer, so the first difference landed inside the sent body and `sentBodyLanded` read the move as a loss — a write that landed whole, reported as a write that did not. The predicate now answers two measured shapes, `appended` and `re-anchored`, each an exact `===` against a candidate built from the sent bytes. One spelling serves both modes: `classifyReadBack` already records `footerReAnchored` whatever the mode, so `--comment` and `--body` reach the same verdict without a mode gate of their own. The CLASS vocabulary is untouched — a moved newline added nothing, so `footer-appended` would misname it — and `--json` still reports `body_mutated: true`. The exit-4 contract does not loosen: a byte lost or changed before the rule, a chewed or rewritten footer, a truncation ending in the block, and a newline that came from nowhere all still exit 4, pinned as controls. The read-back's first line no longer prescribes "read the artefact before trusting it" for a difference this tool has already measured as benign, which retires the interim hand-reading the seat has been doing since the first shape landed. Self-test: 308 cases / 12 batteries → 347 / 13. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
The floor is a minimum, and a minimum set well below the real count lets the battery lose a third of its cases without naming itself. Probed: at 40 the floor fires and names the battery, so 39 is exact, not merely under. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
…oter-reanchor-not-a-loss
…oter-reanchor-not-a-loss
…the append Widening the predicate made one clause of `notStoredText` false: it told a caller who hit a real loss that the benign exemption "appends and takes nothing away", when the exemption now also covers the platform moving a newline around a footer block already there. A reader at exit 4 checks his bytes against the boundary this sentence draws, so a sentence describing one arm of a two-arm predicate sends him looking for the wrong shape. Pinned both ways: the report names both shapes, and still says the thing that decides it. Self-test: 347 cases / 13 batteries -> 349 / 13. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 17, 2026
os-justin
marked this pull request as ready for review
September 17, 2026 19:41
This was referenced Sep 17, 2026
This was referenced Sep 17, 2026
os-justin
pushed a commit
that referenced
this pull request
Sep 17, 2026
…ape its own clean class The header declared the issue-body footer cell UNMEASURED and held the body-mode append in `mutated` on that ground, while the governed fact table has carried the measurement since PR #17746 and the skills seat re-measures it on every seat-post refresh. Since PR #18758 `$?` already answered 0 for both footer shapes, so the tool said two things about one set of bytes: "everything sent is on the platform" in `$?` and "MUTATED" on stderr, with `--json` reporting `body_mutated: true` beside `body_landed: true`. `footerReAnchoring`'s two measured shapes are now two declared classes — `footer-appended` and the new `footer-re-anchored` — for either act, so `classifyReadBack` takes no `mode`: the comparison is exact bytes, which cannot tell one act's write from another's, and the gate existed only for the cell that is now measured. `sentBodyLanded` reads the class alone. Every exit-4 control is unchanged: a byte lost before the rule, a byte changed at equal length, a chewed footer, a rewritten link, a newline from nowhere, a truncation ending in the block. What is unmeasured is named instead: the WRITE CHANNEL. Two `--body` refreshes of the same shape on the same endpoint the same day read +58 on this seat's channel and IDENTICAL on the triage seat's, and no act here can vary that. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Sep 17, 2026
Merged
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.
Fixes #18709
Clause-②: nopost-stampedexited 4 (EXIT_NOT_STORED) on every artefact a seat wrote carrying its own attribution footer — the block this fleet's harness rule requires verbatim on every GitHub post. The platform stores such a body with its trailing newline moved to before the footer's own rule: sentX\n\n---\n_Generated by …_\n, storedX\n\n\n---\n_Generated by …_. Equal length, one byte moved, zero lost, byte-identical before the offset.footerReAnchoringrecognised only an appended footer — the stored body being the sent body, or its newline-trimmed form, followed by exactlyPLATFORM_COMMENT_FOOTER— so a body that already ended in the footer matched neither arm, the first difference landed inside the sent body, andsentBodyLandedread the move as a lost byte. A write that landed whole, reported as a write that did not: a caller obeying the new contract ("exit 4 ⇒ read the artefact, do not retry") stops on every write, and one that ignores it has learned to ignore exit 4 — the state PR #18690 existed to end. It also induces duplicate writes. This is the reverse-direction residue of the fix for #18663: a predicate tightened on one side must be re-measured on the other.The before-readings, from the live artefacts
Fetched through the REST proxy and fed to
classifyReadBack/sentBodyLandedonmain30bac2880. The sent side is the landing-record shape (the body as the seat sent it, ending in the footer block plus one newline); each row's byte counts and first-differing offset reproduce the reading recorded on the card independently.footerReAnchoredsentBodyLanded--commentmutatedfalsefalse--commentmutatedfalsefalse--bodymutatedfalsefalse--bodymutatedfalsefalseThe tail on every one of them, byte-exact:
Two measurement notes, both of which change what a reader should conclude:
trailing-newline-strippedand has always exited 0. Reproducing that shape offline proves nothing about this defect.--bodyhalf needed no mode gate of its own, and the card's evidence comment is imprecise on the mechanism. Comment 5718793488 readsclassifyReadBack's "the comment-only footer rule must be asked for by name" as "in body mode the footer rule is not consulted at all". Measured: that gate is on the class alone.classifyReadBackrecordsfooterReAnchoredwhatever the mode, and that is the field$?is decided from —mode: 'body'on the appended shape already answersfooterReAnchored: true,sentBodyLanded: true. So the two halves really are one bug, the conclusion in that comment holds, and widening the one predicate reaches both modes in one edit with no mode gate added or removed. The misreading is now said out loud in the function's own docblock, because it has been made.A fifth artefact, comment 5718451961 on #17183, shows the same shape but reads back at 5026 bytes today against the 3480 recorded — it was rewritten after that reading, so it is not pinned. Recorded here as a measurement note, not a finding.
The predicate: two arms, both exact bytes
footerReAnchoringnow answers which of two measured shapes the difference is, ornull:appended— unchanged. The sent body carried no footer of its own, and the stored body is it, or its newline-trimmed form, followed by exactlyPLATFORM_COMMENT_FOOTER.re-anchored— new. The sent body already ended in the footer block with trailing newline(s) after it, and the stored body is that same body with those newlines removed and exactly one newline inserted immediately before the block.Both arms are one
===against a candidate built from the sent bytes — never a pattern, never a length. Everything before the block and every byte of the block itself is compared literally. The re-anchor arm additionally requires the sent body to have carried trailing newline(s) of its own: the moved newline is one the act sent, and a stored body that gained a newline from nowhere is a cell nobody has measured.The class vocabulary is untouched. The re-anchored shape stays
mutatedin both modes, becausefooter-appendedsays "the stored body is that body plus exactly the platform's comment footer" and a moved newline added nothing — naming it with that word would make the vocabulary say something untrue about the bytes.--jsonstill reportsbody_mutated: true. What changed is what$?says, and one sentence of the status line.The status line. For a difference this tool has already measured as benign, the read-back's first line no longer carries the prescription "Read the artefact before trusting it: the sanitizer eats tag-shaped fragments" — it reads "the platform NORMALISED its own footer block and took nothing away. Class MUTATED, and nothing here to go read the artefact for", and the third line names which normalisation it was. That prescription is what sent the skills seat to re-read every exit-4 artefact by hand since the first shape landed; the header now records that interim reading as retired, and why nobody should make it by eye again (by eye it cannot tell a moved newline from a substitution the same length).
Not folded in: #18693. Read it. Its remedy is to move the body-mode footer append and the trailing-rule re-anchor out of
mutatedinto a benign class, and to re-pin the control at the old :1662. That is a different decision on a different surface — the class vocabulary, the--jsonfield and the header's "unmeasured cell" declaration are all untouched here, and the pinned control that the body-mode append staysmutatedstill passes. It remains the next card on this file.The pins
New battery,
the re-anchored footer: a newline the platform MOVED is not a byte lost, 39 cases, floor pinned at 39 (probed: at 40 the floor fires and names the battery, so 39 is exact and not merely under).packages/spec/src/api/batch.zod.ts:128calls the batch-size cap "DEPLOYMENT policy" — the FIFTH carrier of the claim corrected four times, in live source, inside the package whose own header states the contract it contradicts #18739/[finding] the 17.0.0 CHANGELOG entries inpackages/restandpackages/spectell deployments to "raisebatch.maxBatchSize(up to 1000)" — the falsified cap claim in its strongest form, published to npm, on the release-owned tree #18740 and 5718507419), and the offset that read-back recorded. Each asserts: both sides equal the recorded byte count; the first difference is at the recorded byte; exit 0;footerReAnchoredtrue with shapere-anchored. The shared head is filler because every byte of it is identical on both sides by construction, and the pinned offset is what provesfirstDifferingBytewalked all of it.appended, the comment-modefooter-appendedclass still answers to that arm alone, the body-mode append still exits 0 with its warning kept, and its line still says "appended", never the re-anchor's words.unreadablestays exit 0 and UNVERIFIED, as the header declares — this rule did not widen into it.The ablation
Reverting the one arm that recognises the moved-newline shape, at
9dd5db202a:Exactly the new cases go red and the old ones stay green. 14 of 347 fail, all 14 in the new battery, all of them about the re-anchored shape: for each of the four live artefacts, "it LANDED: exit 0" and "measured as the re-anchor by name"; plus "ONE predicate covers both modes", "a caller naming NO mode gets it too", the three status-line cases, and "the predicate answers the SHAPE". The other 333 pass — every one of the 308 pre-existing cases, and 25 of the 39 new ones. The 25 new survivors are the right ones: the byte-count and offset assertions are properties of the fixture, and every exit-4 control stays green with the arm deleted, which is what a control is for — a control that went red here would have been testing the arm, not the contract. 0 floor problems: the battery still registers 39, so nothing was hidden by a case that stopped running.
Restore is proven two ways, by blob hash equality against
HEADand by an emptygit diff HEAD, not by an exit code; the script carriestrap … EXIT INT TERMwith absolute paths and treats an empty hash as failure.Self-test
308 cases across 12 batteries → 347 across 13.
Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree, no hand-fed path list; change set 1 path,scripts/pm/post-stamped.mjs. All 29 run at9dd5db202a, each exit code captured with redirect-then-$?, all 0:Reconciled with
--ran: 29 derived, 29 run, 0 NOT-MEASURED, 0 UNRUN — a derived zero, since all 29 records carry an exit code. Repo-widepnpm lint(eslint . --no-inline-config): exit 0, no findings.origin/mainwas merged twice while this ran and the derived family list came back byte-identical both times (29, no additions, no drops), including across PR #18735's change todispatch-gates.mjsitself; the last derivation and every reading above are from9dd5db202awith a clean tree.origin/mainkeeps moving faster than a local sweep — CI on this PR is the authority on convergence.skip-changeset:scripts/pm/**is not shipped by any package'sfiles[]; nothing published moves.Generated by Claude Code