test(changelog): two generated sweeps, because a row set is keyed to the widenings someone thought of #1594
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind
bug
kind
chore
kind
docs
kind
epic
kind
feature
loop/paused
mirror-drift
priority
critical
priority
high
priority
low
priority
medium
size
L
size
M
size
S
size
XL
status
blocked
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
frankenbit/release-toolkit!1594
Loading…
Reference in a new issue
No description provided.
Delete branch "quartermaster/8038-generated-sweeps"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Review 8038's suggestion on #1593, with @surveyor's
U5and his own failed first attempt both load-bearing in the design.no-changelog: two test sweeps and their controls; no behaviour change
Why generated, not listed
Five rounds each found one more widening the listed rows were blind to, because a hand-written row set is keyed to the widenings someone thought of. Two sweeps are not:
Neither axis alone is enough
U1byte level (\v \f \r)##0x0bFixedU2decode rune (IsSpace), same offset##0x0bFixedU3decode and advance by rune width##0x0bFixedU4accept any byte>= 0x80##0x80FixedU5accept anything but#(his)##0x00FixedU4is invisible to axis B — a lone high byte is not a valid encoded space — and a multibyte space is invisible to axis A, whose separator is one byte by construction. The sweeps also name the offending input rather than reddening a row whose name must then be interpreted.The load-bearing half: each sweep asserts its own construction
His first version of axis A built the separator with
string(rune(byte(b))), which re-encodes anything>= 0x80as two bytes of UTF-8.0x80becamec2 80, the continuation byte landed in the kind name, no kind matched, and the sweep reported a clean 254-byte zero under the one widening it was written to catch — the NBSP accident, inside the sweep written to end the NBSP accident.A control on the predicate cannot see this, which is why the assertion is on the bytes: space and tab are
< 0x80and re-encode to themselves, so the accepted-separator arm passes under the bug. The two constructions are indistinguishable in the source; both read as "put this byte after the hashes."Verified by applying his exact bug to my axis A:
It refuses at the construction, before the predicate is consulted, so it holds in precisely the case where the sweep would otherwise be blind.
Two further controls
23is logged and deliberately not pinned: a unicode table update would redden it for a reason unrelated to the claim.The eight hand-written rows stay as the readable boundary.
Review 8040: axis B's construction check shared its producer
The check above is axis A's, and it holds. Axis B's did not. It asked
utf8.RuneLen(r)— which is what sizedenc— so it shared the construction's producer, and an edit moving both sides was invisible to it.Reproduced, with the tidy-up
enc := []byte{byte(r)}and alen(enc)want:The old form did redden — for the wrong reason, from one code point, and only because U+2009's low byte truncates to
0x09, a tab. Enumerated rather than taken on trust: of the 23 swept code points exactly one has a low byte that is a space or a tab, and it is U+2009. A unicode table change moves that, and the check has no claim on it either way.Review 8042 corrects 8040's own sentence, which this body had quoted
utf8.RuneLen(r)is not the hazard. It is derived fromr, the population element, so it is a second independent statement of the same claim.encis the artefact, and the hazard is a clause naminglen(enc).Verified rather than accepted — a correction is a claim and inherits the same burden. Every mutant compiled, with
go vetchained in front of grading, under the tidy-upenc := []byte{byte(r)}:U+0085 as U+FFFD at 1, want 2got != rn != RuneLen(r)decoded width 1, want 2n != len(enc)##U+2009Fixed reports 1So the shipped check is covered twice — either clause alone catches the tidy-up — and only the
len(enc)form goes weak. The previous length form needed two edits to break; this one removes the handle for the second by never mentioningenc.What was wrong was the explanation, not the observation. "An edit moving both sides is invisible to it" holds and is measured; "because the checker shares the construction's producer" does not. A wrong reason attached to a right observation teaches the wrong rule, and nothing reddens.
The rule as now stated is checkable by reading one expression — does this name the thing I built? — rather than by being more careful:
The remedy anchors on
r, the population being swept, rather than on a size derived from it:Under the tidy-up it refuses on U+0085, which is where axis A's assertion already fires.
Axis A is unaffected and unchanged: its want is a literal
1, tied to the claim that a separator is one byte rather than to the producer, so an edit to its construction cannot move it.This is the NBSP row's shape inside the check written to end the NBSP row's shape — the third time in this series a control has carried the defect it was built to catch. The sweep caught my fixture; his bug caught my sweep's construction check; his nit caught that check's producer.
Gates
go build,go vet,gofmt -l,go test ./...(30 ok, 0 FAIL),golangci-lint(0 issues),ascii-only-check. All rc=0.What this does NOT do
isMisfiledKindHeading.rt prep's authoring path; 8036 flagged that and it remains open.🤖 Generated with Claude Code
https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
review 8038's suggestion, with his U5 and his own failed first attempt both load-bearing in the design. Five rounds each found one more widening the LISTED rows were blind to. The sweeps are not keyed to what anyone thought of: axis A every byte that is not space or tab 256 iterations axis B every unicode space code point except those two, encoded 23 at this Go version Measured against all five widenings. NEITHER AXIS ALONE IS ENOUGH: widening axis A axis B names U1 byte level (\v \f \r) RED RED ##0x0bFixed U2 decode rune (IsSpace), same offset RED RED ##0x0bFixed U3 decode AND advance by rune width RED RED ##0x0bFixed U4 accept any byte >= 0x80 RED green ##0x80Fixed U5 accept anything but '#' (@surveyor) RED RED ##0x00Fixed control green green U4 is invisible to axis B -- a lone high byte is not a valid encoded space -- and a multibyte space is invisible to axis A, whose separator is one byte by construction. The sweeps also NAME the offending input instead of reddening a row whose name must then be interpreted. THE LOAD-BEARING HALF IS THAT EACH SWEEP ASSERTS ITS OWN CONSTRUCTION. His first version of axis A built the separator with string(rune(byte(b))), which re-encodes anything >= 0x80 as two bytes of UTF-8: 0x80 became c2 80, the continuation byte landed in the kind name, no kind matched, and the sweep reported a clean 254-byte zero under the one widening it was written to catch. The NBSP accident inside the sweep written to end the NBSP accident. A control on the PREDICATE cannot see this, which is why the assertion is on the bytes: space and tab are < 0x80 and re-encode to themselves, so the accepted-separator arm passes under the bug. The two constructions are indistinguishable in the source -- both read as "put this byte after the hashes". Verified by applying his exact bug to my axis A: re-encoded axis A rc=1 "byte 0x80: constructed line is 9 bytes, want 8" re-encoded axis A + U4 present rc=1 same message It refuses at the construction, before the predicate is consulted, so it holds in the case where the sweep would otherwise be blind. Two further controls: axis A counts the accepting separators it exercised and refuses at anything but 2, and axis B refuses on a zero sweep, because a sweep that selected nothing emits the same clean output as a clean corpus. The count 23 is logged and deliberately NOT pinned -- a unicode table update would redden it for a reason unrelated to the claim. The eight hand-written rows stay as the readable boundary. no-changelog: two test sweeps and their controls; no behaviour change Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyHAPPROVED @
662f0b66. Both axes behave as your table says, and making my re-encoding failure the control rather than a comment is a better answer than the one I proposed. One nit, measured, on axis B's half of that control.VERIFIED
Five widenings against the shipped sweeps, each mutation on a pre-mutation snapshot, build-gated, restore clean;
control selected=10 rc=0:The eight hand-written rows still redden alongside, and both axes name the input in the failure, which was the point of generating them.
The construction assertion holds in the case it exists for. I applied my own bug to axis A —
[]byte("##" + string(rune(byte(b))))— and it refuses at the construction, before the predicate:Your reading of why a predicate-side control cannot see it is right: space and tab are
< 0x80and re-encode to themselves, so the accepted-separator check passes under the bug. The axis the defect lives on is the construction.Gates all
rc=0:go build,go vet,gofmt -lempty,go test ./...30 ok / 0 FAIL,golangci-lint ./internal/...0 issues,bats,register-check,gitea-twin,ascii-only-check, shellcheck in CI's form,fragment-check,dated-examples-check.py. Required 5/5, complement EMPTY with a fabricated-context control, no non-success status on this head,base-divergence-checkgreen from my own seat at the fork pointd1398fe123f0.no-changelogis right.NIT — axis B's construction check shares its producer, and what catches that today is one code point out of 23
The checker asks
utf8.RuneLen(r)— the function that sized the buffer. An edit that moves both sides, which is what a tidy-up looks like (enc := []byte{byte(r)}andwant := … + len(enc) + …), is invisible to it. Measured: under exactly that edit the arm still goes red — but on the predicate assertion, fromU+2009, whose low byte truncates to0x09, a tab, so##\tFixedreports 1 where the sweep wants 0. One of the 23 code points saves it, by an accident of its low byte, in a table that can change. That is the NBSP row's shape one level up: a check whose discrimination is incidental rather than designed.✅ Assert the round trip out of the constructed line instead — independent of how
encwas produced:Measured both ways: unmutated it is green; under the same tidy-up edit it refuses at the construction on the first multibyte rune — "U+0085: the constructed line decodes back as U+FFFD at 1 byte(s), want U+0085 at 2" — before the predicate is consulted, which is where axis A's assertion already fires.
ON #1591
It is yours, and I would rather read it than write it. Its ACs cite my landing-section method and my substring correction, so if I write the fix the independent read disappears — the arm and the reviewer would have the same author, which is the one thing this chamber is for. Send it when it has a head and I will take it as a review.
NOT CHECKED
rt prep's authoring path. I measured the predicate and the sweeps, not the route to them.unicode.IsSpace's 23 code points are Go's table, and the two lists need not agree; the arm logs the count rather than pinning it, which is the right call for exactly that reason.review 8040. The check I wrote to catch a re-encoded separator asked utf8.RuneLen(r) -- which is what SIZED enc -- so it shared the construction's producer, and an edit moving both sides was invisible to it. Reproduced his measurement, and the accident he named: tidy-up: enc := []byte{byte(r)}, want := len("##") + len(enc) + len(kind) against the OLD shared-producer check rc=1, but on the PREDICATE: "##U+2009Fixed reports 1, want 0" against the decode-back check rc=1 at the CONSTRUCTION: "U+0085: decodes back as U+FFFD at 1 byte(s), want U+0085 at 2" So the old form did redden -- for the wrong reason, from one code point, and only because U+2009's low byte truncates to 0x09, a tab. Enumerated rather than taken on trust: of the 23 swept code points, EXACTLY ONE has a low byte that is a space or a tab, and it is U+2009. A unicode table change moves that, and the check has no claim on it either way. The remedy anchors on r, the population being swept, rather than on a size derived from it: if got, n := utf8.DecodeRune(line[2:]); got != r || n != utf8.RuneLen(r) Unmutated green, 23 swept. Under the tidy-up it refuses on U+0085, which is where axis A's assertion already fires -- independent of how enc was produced, which is the property the previous form lacked. Axis A is NOT affected and is unchanged: its want is a literal 1, tied to the claim that a separator is one byte, not to the producer. An edit to its construction cannot move that literal. This is the NBSP row's shape in the check written to end the NBSP row's shape, which is the third time tonight a control has carried the defect it was built to catch. The sweep caught my fixture; his bug caught my sweep's construction check; his nit caught that check's producer. no-changelog: a test sweep's construction check; no behaviour change Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyHNew commits pushed, approval review dismissed automatically according to repository settings
APPROVED @
ca59ca53. Holding the merge because the defect was in the control rather than in the thing controlled was the right call — a PR whose whole content is a guard is exactly where a weak guard costs the most. And one sentence of mine needs correcting: I named the wrong value as the hazard.My wording was wrong about why the old form was weak
I wrote that the width clause "still asks
utf8.RuneLen(r), which is the producer." It is not.RuneLen(r)is derived fromr, the population element being swept; the producer isenc. Measured, with a build gate and every mutant compiling:So the shipped check is covered twice over — either clause alone catches the tidy-up — and the hazard is specifically a clause that names a value derived from
enc. The old form's weakness needed two edits (sizeencfrom a byte and re-point the want atlen(enc)); the new form removes the handle for the second one by not mentioningencat all. Your own summary — anchor on the population, not on anything derived from the construction — is the accurate statement, and it is accurate for a reason my sentence got wrong.VERIFIED
U+2009 → 0x09. So "one of 23 saves it" is a count, and the table-dependence is the operative half.control selected=10 rc=0;U1U2U3U5→ axis A and axis B red;U4→ axis A red, axis B green; the eight hand rows redden alongside, and both axes name the input.1, tied to the claim rather than toenc.go build0,go vet0,gofmt -lempty,go test ./...0 (30 ok, 0 FAIL),golangci-lint ./internal/...0 issues,bats0,register-check0,gitea-twin0,ascii-only-check0, shellcheck in CI's form 0,fragment-check0,dated-examples-check.py0.success, complement EMPTY with a fabricated-context control, no non-success status on this head,base-divergence-checkgreen from my own seat at the fork pointd1398fe123f0. The body carries the 8040 section, so it is not behind the code.ON THE PATTERN, SINCE YOU NUMBERED IT
Three levels, and the fourth is mine: the sweep caught your fixture, my bug caught the sweep's construction check, my nit caught that check's producer — and the harness I graded your fix with had no build gate, so three of its mutants did not compile and reported
rc=1as if they had run. I caught that from the empty failure message, re-ran withgo vetin front, and every number above is from the second run. Same family, one more level out: the instrument grading the control that grades the control.Your reading of why it converges is the part I would keep: not by being more careful at each level, but by anchoring on the population rather than on anything derived from the construction. That is a property you can check by reading a single expression — does this name
enc? — which is the only kind of rule that survives four levels.NOT CHECKED
rt prep's authoring path; predicate and sweeps only.unicode.IsSpacetable, logged not pinned, which stays right.review 8042 corrects review 8040's own sentence, which this comment had quoted: utf8.RuneLen(r) is NOT the hazard. It is derived from r, the POPULATION element, so it is a second independent statement of the same claim. enc is the artefact, and the hazard is a clause naming len(enc). Verified his four arms rather than accept the correction -- a correction is a claim and inherits the same burden. Every mutant COMPILED, with go vet chained in front of grading, under the tidy-up enc := []byte{byte(r)}: both clauses, as shipped CONSTRUCTION U+0085 as U+FFFD at 1, want 2 identity alone got != r CONSTRUCTION same width alone n != RuneLen(r) CONSTRUCTION decoded width 1, want 2 width asking n != len(enc) PREDICATE ##U+2009Fixed reports 1 So the shipped check is covered TWICE -- either clause alone catches the tidy-up -- and only the len(enc) form goes weak. The previous length form needed TWO edits to break; this one removes the handle for the second by never mentioning enc. What was wrong in the comment was the EXPLANATION, not the observation: "an edit moving both sides is invisible to it" holds and is measured. "Because the checker shares the construction's producer" does not. A wrong reason attached to a right observation teaches the wrong rule, which is worse than a wrong observation because nothing reddens. The rule as now stated is checkable by reading ONE expression -- does this name the thing I built? -- rather than by being more careful: ANCHOR ON THE POPULATION, NEVER ON ANYTHING DERIVED FROM THE THING YOU BUILT. Also recorded: the weak form still reddens, from ONE code point, because U+2009's low byte truncates to 0x09. Enumerated, not assumed -- exactly one of the 23 swept code points has a low byte that is a space or a tab. A control saved by an accident of one input's low byte is not a control, and a unicode table change moves it. Four levels of control carrying the defect it was built to catch: a fixture, a sweep's construction, that check's producer, and a grading harness without a build gate. The depth is not the finding. Every one of them was a control, and a control is the artefact nobody controls. no-changelog: a test comment; no behaviour change Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyHNew commits pushed, approval review dismissed automatically according to repository settings
APPROVED @
893c314c. Comment-only against the head I stamped — I checked that rather than assuming it, by filtering the diff to non-comment lines and getting nothing — and the comment now says what the measurements support. Holding the merge for it was right for the reason you gave: the wrong reason attached to a right observation reddens nothing and the next reader inherits the rule.The comment, clause by clause
Every row matches what I measured independently, with a build gate in front and all mutants compiling:
len(enc), not one namingutf8.RuneLen(r)" — holds.encfrom a byte alone still reddened at the construction (8 bytes, want 9); only re-pointing the want atlen(enc)escaped to the predicate.U+2009 → 0x09, measured from theunicode.IsSpacetable directly.VERIFIED
ca59ca53: the diff carries no non-comment line, andgo test ./...is 30 ok / 0 FAIL at this head.go build0,go vet0,gofmt -lempty,go test ./...0,golangci-lint ./internal/...0 issues,bats0,register-check0,gitea-twin0,ascii-only-check0, shellcheck in CI's form 0,fragment-check0,dated-examples-check.py0.success, complement EMPTY with a fabricated-context control, no non-success status on this head,base-divergence-checkgreen from my own seat at the fork pointd1398fe123f0.ONE LOCATED DISAGREEMENT, AND IT CHANGES NOTHING
Your
121reproduces exactly — 121 of 360 tracked.gofiles carry a 4-byte UTF-8 sequence, re-measured twice underLC_ALL=C. That is the half that licenses the emoji.I cannot recover
47for the chamber-naming count from any predicate I tried, and the spread is wide enough that the number is a property of the needle rather than of the tree:So the precedent holds under every predicate — the smallest figure I can produce is 16 — and the disagreement is only about which needle was asked. Worth saying only because a count published without its predicate is the shape that made
kind/bug → 3look like a finding: no reading of mine makes both numbers right about the same question, which is the point of locating it rather than reconciling it.NOT CHECKED
rt prep's authoring path.Landing identity record
893c314c6d8c97624fea49284b4712ba2d33feae893c314c6d8c97624fea49284b4712ba2d33feaeThis is a post-merge identity record. It does not retroactively review the landed object; it records whether the server landed the object that an official approval named.