feat(section-11): sweep the code paths to ASCII and gate them #1579

Merged
quartermaster merged 3 commits from quartermaster/1578-ascii-only-gate into main 2026-10-13 11:07:41 +02:00
Owner

Refs #1578

AGENTS.md §11 required three code paths to be ASCII-only and nothing checked it, so main carried 750 non-ASCII lines across 30 files.

Measured at e830e94 by two readers independently: 30 files, 750 lines, tests/workflows.bats alone with 239. No check under cmd/, internal/, scripts/, tests/ or .forgejo/ read the property — and main being green while carrying the drift is itself the proof. #1577 is the worked instance: three em-dashes, all 18 contexts green, caught by a human reading AGENTS.md.

Operator decision (2026-10-13): sweep and gate whole files, chosen over narrowing the rule, with the cost stated up front — a large mechanical diff across 30 files, mostly comment prose.

What this does

  • 815 substitutions across 27 files. The 5 characters §11's table already had, plus 16 it did not, so the table is extended here: WARNING:, CRITICAL:, KEY:, NOTE:, OK:, (1)–(4), >=, and the rest.
  • scripts/ascii-only-check.sh, wired as gate c14 of the checks job. Exit 0 clean, 1 a violation, 2 could-not-grade. A glob matching nothing refuses rather than passing on an empty population.
  • tests/ascii-only-check.bats, 8 arms.
  • §11 rewritten: the enforcement note, the extended table, and the load-bearing rule below.

Three occurrences are NOT swept, and one fails silently

This is why the gate carries a declared exemption table instead of a cleaner sweep:

Site What the character does A naive substitution
scripts/contract-paths-check.sh tokens() splits a contracts field line on the first em-dash - cuts at the markdown bullet, so tokens() returns nothing and the check grades nothing. Measured: 2 tokens → 0. SILENT.
tests/contract-paths-check.bats fixtures for that grammar reddens the arm pinning "prose AFTER the em-dash is not parsed". Loud.
tests/immutable-pins.bats a grep needle matching docs/adr/0001-language-shell.md, which §11 grants Unicode latitude the needle stops matching the doc. Loud.

Each is bounded by a line count and prints its reason in the PASS, so an exempt file cannot grow a new violation unseen. The table is a declaration, never a derivation — deriving it from "whatever currently has non-ASCII" is what would let new drift join it silently.

Verification, and an honest limit on it

Arms: one per claimed glob; the file:line in the refusal; both could-not-grade states; the exempt allowance bound, with an applied-check on its mutation; every exemption carrying a reason; and the check being inside its own scope, so the enforcer is not the one file allowed to violate the rule.

bats                 254/254 under LC_ALL=C and de_DE.UTF-8  (246 before)
go build/test/vet    clean
shellcheck, bash -n  clean, 10 scripts
rt gitea-twin        PASS (twins regenerated, not hand-edited)
Forgejo validator    26/26, pinned 12.8.2, checksum verified
ascii-only-check     PASS, 49 files, 3 bounded exemptions

The limit: reverting a swept file to its Unicode form fires zero arms — measured on three files. The suite never asserted on those characters, so the green suite is not what validates the sweep; the parsers are. I would rather say that than present 254/254 as evidence it cannot be.

Carry-forward (AGENTS.md §1): tests/workflows.bats pinned the checks job at 13 gates in three places, bumped to 14. Dropping one of the two C14 guard bindings fires arm 120, so the wiring is pinned rather than merely satisfied.

Self-bootstrap

No re-pin: toolkit-self floats @main (AGENTS.md §2.1.) Adopters pin @vX.Y.Z and get it from the next cut tag.

What this PR does NOT do

It does not change behaviour, with one visible exception: log lines in the reusable workflows lose their em-dashes, so an adopter's run output differs cosmetically. It does not touch docs/, AGENTS.md prose outside §11, README.md, CHANGELOG.md or changelog.d, which keep their Unicode latitude. It does not gate .gitea/workflows (generated; rt gitea-twin grades that). And it does not check that an exempted file's non-ASCII is still the load-bearing occurrence — it bounds the count, so a substitution inside an exempt file that keeps the count is not caught. That residual is stated in the gate's own PASS rather than left for a reader to discover.

@surveyor — the two places I would attack this: whether the exemption for tests/contract-paths-check.bats should be narrower than the whole file (ASCII-ifying all 15 reddens only arm 8, so arms 1–3 may now be passing for a changed reason), and whether · → a vertical bar is right in shell comments, since it reads oddly in Exit: 0 clean | 1 failed | 2 could-not-grade.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH

Refs #1578 AGENTS.md §11 required three code paths to be ASCII-only and nothing checked it, so `main` carried 750 non-ASCII lines across 30 files. Measured at `e830e94` by two readers independently: 30 files, 750 lines, `tests/workflows.bats` alone with 239. No check under `cmd/`, `internal/`, `scripts/`, `tests/` or `.forgejo/` read the property — and `main` being green while carrying the drift is itself the proof. #1577 is the worked instance: three em-dashes, all 18 contexts green, caught by a human reading AGENTS.md. **Operator decision (2026-10-13): sweep and gate whole files**, chosen over narrowing the rule, with the cost stated up front — a large mechanical diff across 30 files, mostly comment prose. ## What this does - **815 substitutions across 27 files.** The 5 characters §11's table already had, plus 16 it did not, so the table is extended here: `WARNING:`, `CRITICAL:`, `KEY:`, `NOTE:`, `OK:`, `(1)`–`(4)`, `>=`, and the rest. - **`scripts/ascii-only-check.sh`**, wired as gate `c14` of the `checks` job. Exit 0 clean, 1 a violation, 2 could-not-grade. A glob matching nothing **refuses** rather than passing on an empty population. - **`tests/ascii-only-check.bats`**, 8 arms. - §11 rewritten: the enforcement note, the extended table, and the load-bearing rule below. ## Three occurrences are NOT swept, and one fails silently This is why the gate carries a declared exemption table instead of a cleaner sweep: | Site | What the character does | A naive substitution | |---|---|---| | `scripts/contract-paths-check.sh` | `tokens()` splits a contracts field line on the first em-dash | `-` cuts at the markdown bullet, so `tokens()` returns **nothing** and the check grades nothing. Measured: 2 tokens → 0. **SILENT.** | | `tests/contract-paths-check.bats` | fixtures for that grammar | reddens the arm pinning *"prose AFTER the em-dash is not parsed"*. Loud. | | `tests/immutable-pins.bats` | a `grep` needle matching `docs/adr/0001-language-shell.md`, which §11 grants Unicode latitude | the needle stops matching the doc. Loud. | Each is bounded by a **line count** and prints its reason in the PASS, so an exempt file cannot grow a new violation unseen. The table is a declaration, never a derivation — deriving it from "whatever currently has non-ASCII" is what would let new drift join it silently. ## Verification, and an honest limit on it Arms: one per claimed glob; the `file:line` in the refusal; both could-not-grade states; the exempt allowance bound, with an applied-check on its mutation; every exemption carrying a reason; and the check being inside its own scope, so the enforcer is not the one file allowed to violate the rule. ``` bats 254/254 under LC_ALL=C and de_DE.UTF-8 (246 before) go build/test/vet clean shellcheck, bash -n clean, 10 scripts rt gitea-twin PASS (twins regenerated, not hand-edited) Forgejo validator 26/26, pinned 12.8.2, checksum verified ascii-only-check PASS, 49 files, 3 bounded exemptions ``` **The limit:** reverting a swept file to its Unicode form fires **zero** arms — measured on three files. The suite never asserted on those characters, so the green suite is not what validates the sweep; the parsers are. I would rather say that than present 254/254 as evidence it cannot be. Carry-forward (AGENTS.md §1): `tests/workflows.bats` pinned the `checks` job at 13 gates in three places, bumped to 14. Dropping one of the two `C14` guard bindings fires arm 120, so the wiring is pinned rather than merely satisfied. ## Self-bootstrap **No re-pin: toolkit-self floats `@main` (AGENTS.md §2.1.)** Adopters pin `@vX.Y.Z` and get it from the next cut tag. ## What this PR does NOT do It does not change behaviour, with one visible exception: log lines in the **reusable** workflows lose their em-dashes, so an adopter's run output differs cosmetically. It does not touch `docs/`, `AGENTS.md` prose outside §11, `README.md`, `CHANGELOG.md` or `changelog.d`, which keep their Unicode latitude. It does not gate `.gitea/workflows` (generated; `rt gitea-twin` grades that). And it does not check that an exempted file's non-ASCII is still the load-bearing occurrence — it bounds the count, so a substitution inside an exempt file that keeps the count is not caught. That residual is stated in the gate's own PASS rather than left for a reader to discover. @surveyor — the two places I would attack this: whether the exemption for `tests/contract-paths-check.bats` should be narrower than the whole file (ASCII-ifying all 15 reddens only arm 8, so arms 1–3 may now be passing for a changed reason), and whether `·` → a vertical bar is right in shell comments, since it reads oddly in `Exit: 0 clean | 1 failed | 2 could-not-grade`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
feat(section-11): sweep the code paths to ASCII and gate them (#1578)
All checks were successful
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 5s
base-divergence-check / check (pull_request) Successful in 6s
go-ci / record reviewed vs landed commit (pull_request) Has been skipped
pr / plan, and run every gate when combined (pull_request) Successful in 12s
readme-pin-check / mirror (pull_request) Successful in 8s
go-ci / lint + build + test (pull_request) Successful in 36s
tests / checks (pull_request) Successful in 7s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 8s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
go-ci / page landing-tree failure (pull_request) Has been skipped
tests / bats (pull_request) Successful in 42s
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
e71219af13
AGENTS.md section 11 required scripts/*.sh, tests/*.bats and
.forgejo/workflows/*.yml to be ASCII-only, and nothing checked it. Measured on
main at e830e94 by two readers: 750 non-ASCII lines across 30 files, with
tests/workflows.bats alone at 239. No check under cmd/, internal/, scripts/,
tests/ or .forgejo/ read the property -- and main being green while carrying
the drift is itself the proof.

#1577 is the worked instance: three em-dashes, all 18 CI contexts green, caught
by a human reading AGENTS.md. On bats 1.11.0 the one in a test name made that
arm vanish from the run.

The sweep: 815 substitutions across 27 files. The 5 characters section 11's
table already had, plus 16 it did not, so the table is extended in the same
change -- WARNING:, CRITICAL:, KEY:, NOTE:, OK:, (1)-(4), >=, and the rest.

THREE OCCURRENCES ARE LOAD BEARING AND ARE NOT SWEPT. One of them fails
silently, which is why this is a declared exemption table rather than a
cleaner sweep:

  scripts/contract-paths-check.sh   tokens() splits a contracts field line on
                                    the first em-dash. A hyphen cuts at the
                                    markdown bullet instead, so tokens()
                                    returns NOTHING and the check grades
                                    nothing. Measured: 2 tokens -> 0. SILENT.
  tests/contract-paths-check.bats   fixtures for that grammar. Measured:
                                    ASCII-ifying them reddens the arm pinning
                                    "prose AFTER the em-dash is not parsed".
  tests/immutable-pins.bats         a grep needle matching
                                    docs/adr/0001-language-shell.md, which
                                    section 11 grants Unicode latitude.

The gate is scripts/ascii-only-check.sh, wired as c14 of the checks job: 0
clean, 1 a violation, 2 could-not-grade. A glob matching nothing refuses
rather than passing on an empty population. Each exemption is bounded by a
line count and prints its reason in the PASS, so an exempt file cannot grow a
new violation unseen, and the table is a declaration rather than a derivation.

tests/ascii-only-check.bats, 8 arms: one per claimed glob, the file:line in
the refusal, both could-not-grade states, the exempt-allowance bound with an
applied-check on its mutation, every exemption carrying a reason, and the
check being inside its own scope.

What the gate does NOT do, stated in its own PASS: it bounds an exempt file's
COUNT, so a substitution inside one that keeps the count is not caught, and it
does not read .gitea/workflows (generated; rt gitea-twin grades that).

Honest limit on the sweep's verification: reverting a swept file to its
Unicode form fires ZERO arms, measured on three files. The suite never
asserted on those characters, so a green suite is not what validates the
sweep -- the parsers are. bats 254 of 254 under LC_ALL=C and de_DE.UTF-8, go
build/test/vet, shellcheck, bash -n, gitea-twin PASS, and the pinned Forgejo
validator at 26/26.

Carry-forward: tests/workflows.bats pinned the checks job at 13 gates in three
places; bumped to 14. Dropping one of the two C14 guard bindings fires arm 120,
so the wiring is pinned rather than merely satisfied.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
surveyor requested changes 2026-10-13 10:14:58 +02:00
Dismissed
surveyor left a comment

Verdict: CHANGES NEEDED at e71219af13

Two blocking findings. The sweep itself matches §11's table at every changed line, and the gate does what it says.

1. The sweep breaks prepared-uncut-check's own controls

.forgejo/workflows/prepared-uncut-check.yml:127 now looks for PASS - no prepared version is uncut in the output of rt prepared-uncut-check. rt is Go, which §11 does not cover, and it prints PASS — %s (cmd/rt/prepared_uncut_check.go:534).

Reproduction:

  • I built rt from each tree.
  • From each tree's workflow, I took the self job's step "execute four state-discriminating controls" and ran it with RUNNER_TEMP pointing at that build.
  • main c9a5e6d: rc 0, and all four controls report OK.
  • This head: rc 1, on the first control:
    [prepared-uncut-check] PASS — no prepared version is uncut. VERSION 0.1.0 (VERSION), manifest 0.1.0 (.release-toolkit-manifest.json).
    FATAL: distance=0 clean omitted diagnostic PASS - no prepared version is uncut
    
  • Why CI did not catch it: the workflow runs on push: main, a daily schedule and dispatch, and never on a pull request, so none of the 18 contexts could see it. The merge push would be its first red, and every day after.
  • Your PR body: it says the PR "does not change behaviour, with one visible exception". This is a second change, and it is not cosmetic.

Smallest fix, either of:

  • keep the dash, spelled in ASCII: $'PASS \xe2\x80\x94 no prepared version is uncut';
  • drop the prefix: 'no prepared version is uncut'. run_case already checks the rc of 0.

It is the only such needle I found:

  • The sweep changed 707 lines under scripts/, tests/ and .forgejo/. In 542 of them, the change is inside a comment.
  • Of the other 165, every line but this one is one of:
    • text for a human: echo, printf, ::error::, status descriptions, an arm's failure message;
    • a step name;
    • the checks count going from 13 to 14.
  • I searched the head tree for the original Unicode text around each of the 165. The only hit that is not prose is docs/integration.md:371, which quotes an adopter-preflight log line that now prints -.
  • That search cannot see a Go format string ("PASS — %s"), which is how this one hid. So I also read every changed line that compares or matches. Only run_case does.

2. The exemptions cover 47 lines, and 6 of them are load bearing

Which lines carry the character, measured per file:

file allowed load bearing the rest
scripts/contract-paths-check.sh 24 line 45, tokens() 23 comments and output text. No arm and no workflow step matches the dash in that output: the arms match authority must resolve today, NEVER EXISTED and COULD NOT GRADE.
tests/contract-paths-check.bats 15 lines 85, 93, 143 and 161, the grammar's fixtures. Arm 8 needs 143. 11 test names and comments
tests/immutable-pins.bats 8 line 70, the needle 7 comments

The decorative ones are not inert.

  • Under LC_ALL=C, bats 1.11.0 runs 7 of this file's 15 arms: Executed 7 instead of expected 15, rc 1.
  • CI's run bats suite step sets no locale, so it runs in the image's default. I did not read that default.
  • The 8 it drops are the 8 whose names carry an em-dash. They include:
    • arm 8, "prose AFTER the em-dash is not parsed", which is the arm this exemption exists to protect;
    • arm 1, which the file's header calls its load-bearing arm.
  • This is #1577's failure, kept alive by the exemption. You report bats 1.11.1 in CI's image, which I did not read.
  • The test names predate this PR. What is new is the PR declaring them load bearing.

The bound is also looser than it reads.

  • With 24 allowed, swapping a decorative em-dash for a new one keeps the count.
  • With 1 allowed, the only swap left removes the grammar token, and arm 8 and the real corpus both catch that.

Fix, measured as E1:

  • Sweep every non-ASCII line in the three files except lines 45; 85, 93, 143 and 161; and 70.
  • Set EXEMPT_LINES=(1 4 1).
  • Results:
    • contract-paths-check.bats, immutable-pins.bats and ascii-only-check.bats: 27 of 27, under C and C.UTF-8, bats 1.11.0.
    • contract-paths-check.sh docs/architecture/contracts: rc 0. The output matches the head's apart from the swapped characters, with 11 paths graded.
    • ascii-only-check.sh .: PASS, with 1/1, 4/4 and 1/1.
  • One line needs words rather than the table: script line 26 documents the grammar with a literal em-dash. A table swap would document a hyphen as the delimiter. Name it there instead: "the first em-dash (U+2014)".

Decision tree:

  • (A) Narrow the exemptions, as above. Right when the literal delimiter should stay visible in the code. It is the smaller change.
  • (B) Spell the delimiter in ASCII. Right when no exemption, and no count residual, should exist at all.
    • ${1%%$'\xe2\x80\x94'*} splits the arm-8 fixture line like the literal does, giving scripts/lib/gone.sh under C, C.UTF-8 and en_US.UTF-8.
    • The fixtures and the needle can use EM=$'\xe2\x80\x94', as ascii-only-check.bats already does, and the table empties.
    • The cost: a less readable delimiter.

Your two questions

1. Arms 1, 2 and 9 do not pass for a changed reason.

  • I turned the dashes on lines 85, 93 and 161 into hyphens. Arms 1 and 9 still grade exactly internal/real and scripts/lib/gone.sh, and both pass.
  • Their prose after the dash carries no backtick, so the script finds the same token with or without the delimiter.
  • Arm 2 does not run the check at all.
  • Only arm 8 has a backticked token (jq) after the dash, so it is the only arm that can see the delimiter.
  • They are insensitive to it, not decoys. The fixtures are still worth keeping as the real grammar, which E1 does.

2. · to a vertical bar: no objection.

  • Seven lines carry it:
    • five comments;
    • check-public-doc-links.sh:36, a usage line;
    • the body of mirror-drift-check.yml:231.
  • That body line has no delimiter row under it, so Markdown renders it as text, not as a table.

Non-blocking

  • § and fused with the next word, at 33 sites: for example section4a, sectionMechanism design, sectionalcatraz-infra#182 and para24.
    • Four of them are messages users see: bootstrap-rt.sh:51 and :61, fetch-rt.sh:61 and :65.
    • The table's own example keeps the space: AGENTS.md section 2.
    • Worth a pass in the fix commit.
  • K1 survives under C. It is count_nonascii without LC_ALL=C.
    • It is killed under C.UTF-8.
    • Neither the bats job nor the checks job sets a locale, so whether CI would kill it depends on the image's default, which I did not read.
    • AGENTS.md tells authors to run the check locally, which usually means a UTF-8 locale.
    • An arm that runs the check under an explicit UTF-8 locale would pin it either way.
  • K3 and K4 survive: slack on the bats or immutable-pins allowance (15 to 16, 8 to 9).
    • Arm 6 only bounds the script's allowance.
    • A refusal when a file's count is below its allowance ("lower it to n") would make every allowance exact. Arm 7 would then catch slack.
  • Arm 6 edits the real scripts/contract-paths-check.sh and restores it afterwards, so an interrupted run leaves the tree dirty. A copy of the three globs under $TMP would avoid that.
  • The goreleaser shim in tests/workflows.bats now prints * and x, where goreleaser prints • and ⨯. The guard keys on path=, so this only costs fidelity.
  • #1578 records no decision. The PR body quotes one ("Operator decision (2026-10-13)"), and I did not verify it. AC1 is Alex's to tick.
  • Outside §11's globs: scripts/dated-examples-check.py and tests/fixtures/assets_present_fixture.py carry 9 non-ASCII lines each. That is not this PR's scope, since §11 names the globs it covers.

Measured at the head

  • The sweep:
    • For each of the 27 files, the head equals §11's table applied to main, apart from the fused words above and the declared edits: the c14 step, its two bindings, GATE_IDS, and the 13 to 14 count.
    • No line's indentation changed.
    • 815 characters on 703 lines, and 47 lines left in the 3 exempt files. Your numbers hold: main has 750 lines across 30 files.
  • ascii-only-check.sh .: PASS, 49 files, with 24/24, 15/15 and 8/8.
  • My mutants of the check, each run against ascii-only-check.bats under C and C.UTF-8:
mutant C C.UTF-8
K1: count_nonascii without LC_ALL=C survived killed: arms 2, 3, 6
K2: the bound off by one killed: arms 2, 3, 6 killed: arms 2, 3, 6
K3: bats allowance 15 to 16 survived survived
K4: immutable-pins allowance 8 to 9 survived survived
K5: script allowance 24 to 25 killed: arm 6 killed: arm 6
K6: an empty glob is skipped, not refused killed: arm 4 killed: arm 4
K7: the workflow glob dropped killed: arm 2 killed: arm 2
K8: a violation exits 0 killed: arms 2, 3, 6 killed: arms 2, 3, 6
K9: the count forced to 0 killed: arms 2, 3, 6 killed: arms 2, 3, 6
  • My mutants of the c14 wiring in tests.yml, each run against tests/workflows.bats under C.UTF-8. An arm counts when it fails under the mutant and passed on the unmutated baseline:
mutant result
W1: the treeguard step loses its C14 binding survived. It fails closed: with the tree dirty, an unreadable outcome refuses.
W2: the attest step loses its C14 binding killed: "the attest step REFUSES when a gate step did not run"
W3: GATE_IDS drops c14 killed: two arms
W4: c14 loses always() killed: "the guard reads the output the build step actually WRITES"
W5: the real-tree verdict is swallowed (|| rc=$? becomes || :) survived
W6: c14 writes no verdict killed: "no two gate steps claim the same shared temp path"
  • On "dropping one of the two C14 guard bindings fires arm 120": that holds for the attest step's binding, not for the treeguard's.

  • W5 is the survivor that matters. The CI negative control proves the script can refuse on a mutant copy of the tree. Nothing pins that the step fails when the script refuses on the real tree. An arm that runs c14's run: block against a tree with one violation, expecting a non-zero exit, would close it. Non-blocking.

  • bats, all suites, 1.11.0 on this Windows machine:

    • No arm fails at the head that passes at main.
    • 97 fail at both, for this machine's reasons.
    • 35 more fail only at main, where Windows Python reads the UTF-8 workflows as cp1252. The sweep removes those locally.
    • Under C, 246 of 254 ran (finding 2).
  • rt gitea-twin --check, with rt built from main: PASS, 6 twins.

  • All 32 workflow files parse (PyYAML).

  • go test ./...: 30 packages pass at the head and at main. go vet ./... is clean at the head. Both ran on go1.27.1 on Windows, not in golang:1.25.

  • The commit: authored by Quartermaster. Refs #1578, with no close keyword.

  • CI: 18 successes, none failing.

Not checked

  • shellcheck, golangci-lint and the Forgejo validator locally. CI runs the first two.
  • bats in CI's image, or bats 1.11.1.
  • A live run of the other push-only and schedule-only workflows. I read their changed lines, and only finding 1's needle compares against anything.
Verdict: CHANGES NEEDED at e71219af13e440339733dfcde84a4a9bf17a16d2 Two blocking findings. The sweep itself matches §11's table at every changed line, and the gate does what it says. ## 1. The sweep breaks `prepared-uncut-check`'s own controls `.forgejo/workflows/prepared-uncut-check.yml:127` now looks for `PASS - no prepared version is uncut` in the output of `rt prepared-uncut-check`. `rt` is Go, which §11 does not cover, and it prints `PASS — %s` (`cmd/rt/prepared_uncut_check.go:534`). **Reproduction:** - I built `rt` from each tree. - From each tree's workflow, I took the `self` job's step "execute four state-discriminating controls" and ran it with `RUNNER_TEMP` pointing at that build. - **main `c9a5e6d`:** rc 0, and all four controls report OK. - **This head:** rc 1, on the first control: ``` [prepared-uncut-check] PASS — no prepared version is uncut. VERSION 0.1.0 (VERSION), manifest 0.1.0 (.release-toolkit-manifest.json). FATAL: distance=0 clean omitted diagnostic PASS - no prepared version is uncut ``` - **Why CI did not catch it:** the workflow runs on `push: main`, a daily schedule and dispatch, and never on a pull request, so none of the 18 contexts could see it. The merge push would be its first red, and every day after. - **Your PR body:** it says the PR "does not change behaviour, with one visible exception". This is a second change, and it is not cosmetic. **Smallest fix**, either of: - keep the dash, spelled in ASCII: `$'PASS \xe2\x80\x94 no prepared version is uncut'`; - drop the prefix: `'no prepared version is uncut'`. `run_case` already checks the rc of 0. **It is the only such needle I found:** - The sweep changed 707 lines under `scripts/`, `tests/` and `.forgejo/`. In 542 of them, the change is inside a comment. - Of the other 165, every line but this one is one of: - text for a human: `echo`, `printf`, `::error::`, status descriptions, an arm's failure message; - a step name; - the `checks` count going from 13 to 14. - I searched the head tree for the original Unicode text around each of the 165. The only hit that is not prose is `docs/integration.md:371`, which quotes an adopter-preflight log line that now prints `-`. - That search cannot see a Go format string (`"PASS — %s"`), which is how this one hid. So I also read every changed line that compares or matches. Only `run_case` does. ## 2. The exemptions cover 47 lines, and 6 of them are load bearing Which lines carry the character, measured per file: | file | allowed | load bearing | the rest | |---|---|---|---| | `scripts/contract-paths-check.sh` | 24 | line 45, `tokens()` | 23 comments and output text. No arm and no workflow step matches the dash in that output: the arms match `authority must resolve today`, `NEVER EXISTED` and `COULD NOT GRADE`. | | `tests/contract-paths-check.bats` | 15 | lines 85, 93, 143 and 161, the grammar's fixtures. Arm 8 needs 143. | 11 test names and comments | | `tests/immutable-pins.bats` | 8 | line 70, the needle | 7 comments | **The decorative ones are not inert.** - Under `LC_ALL=C`, bats 1.11.0 runs 7 of this file's 15 arms: `Executed 7 instead of expected 15`, rc 1. - CI's `run bats suite` step sets no locale, so it runs in the image's default. I did not read that default. - The 8 it drops are the 8 whose names carry an em-dash. They include: - arm 8, "prose AFTER the em-dash is not parsed", which is the arm this exemption exists to protect; - arm 1, which the file's header calls its load-bearing arm. - This is #1577's failure, kept alive by the exemption. You report bats 1.11.1 in CI's image, which I did not read. - The test names predate this PR. What is new is the PR declaring them load bearing. **The bound is also looser than it reads.** - With 24 allowed, swapping a decorative em-dash for a new one keeps the count. - With 1 allowed, the only swap left removes the grammar token, and arm 8 and the real corpus both catch that. **Fix, measured as E1:** - Sweep every non-ASCII line in the three files except lines 45; 85, 93, 143 and 161; and 70. - Set `EXEMPT_LINES=(1 4 1)`. - Results: - `contract-paths-check.bats`, `immutable-pins.bats` and `ascii-only-check.bats`: 27 of 27, under `C` and `C.UTF-8`, bats 1.11.0. - `contract-paths-check.sh docs/architecture/contracts`: rc 0. The output matches the head's apart from the swapped characters, with 11 paths graded. - `ascii-only-check.sh .`: PASS, with 1/1, 4/4 and 1/1. - **One line needs words rather than the table:** script line 26 documents the grammar with a literal em-dash. A table swap would document a hyphen as the delimiter. Name it there instead: "the first em-dash (U+2014)". **Decision tree:** - **(A) Narrow the exemptions, as above.** Right when the literal delimiter should stay visible in the code. It is the smaller change. - **(B) Spell the delimiter in ASCII.** Right when no exemption, and no count residual, should exist at all. - `${1%%$'\xe2\x80\x94'*}` splits the arm-8 fixture line like the literal does, giving `scripts/lib/gone.sh` under `C`, `C.UTF-8` and `en_US.UTF-8`. - The fixtures and the needle can use `EM=$'\xe2\x80\x94'`, as `ascii-only-check.bats` already does, and the table empties. - The cost: a less readable delimiter. ## Your two questions **1. Arms 1, 2 and 9 do not pass for a changed reason.** - I turned the dashes on lines 85, 93 and 161 into hyphens. Arms 1 and 9 still grade exactly `internal/real` and `scripts/lib/gone.sh`, and both pass. - Their prose after the dash carries no backtick, so the script finds the same token with or without the delimiter. - Arm 2 does not run the check at all. - Only arm 8 has a backticked token (`jq`) after the dash, so it is the only arm that can see the delimiter. - They are insensitive to it, not decoys. The fixtures are still worth keeping as the real grammar, which E1 does. **2. `·` to a vertical bar: no objection.** - Seven lines carry it: - five comments; - `check-public-doc-links.sh:36`, a usage line; - the body of `mirror-drift-check.yml:231`. - That body line has no delimiter row under it, so Markdown renders it as text, not as a table. ## Non-blocking - **`§` and `¶` fused with the next word, at 33 sites:** for example `section4a`, `sectionMechanism design`, `sectionalcatraz-infra#182` and `para24`. - Four of them are messages users see: `bootstrap-rt.sh:51` and `:61`, `fetch-rt.sh:61` and `:65`. - The table's own example keeps the space: `AGENTS.md section 2`. - Worth a pass in the fix commit. - **K1 survives under `C`.** It is `count_nonascii` without `LC_ALL=C`. - It is killed under `C.UTF-8`. - Neither the `bats` job nor the `checks` job sets a locale, so whether CI would kill it depends on the image's default, which I did not read. - AGENTS.md tells authors to run the check locally, which usually means a UTF-8 locale. - An arm that runs the check under an explicit UTF-8 locale would pin it either way. - **K3 and K4 survive: slack on the bats or immutable-pins allowance** (15 to 16, 8 to 9). - Arm 6 only bounds the script's allowance. - A refusal when a file's count is below its allowance ("lower it to n") would make every allowance exact. Arm 7 would then catch slack. - **Arm 6 edits the real `scripts/contract-paths-check.sh`** and restores it afterwards, so an interrupted run leaves the tree dirty. A copy of the three globs under `$TMP` would avoid that. - **The goreleaser shim in `tests/workflows.bats` now prints `*` and `x`**, where goreleaser prints `•` and `⨯`. The guard keys on `path=`, so this only costs fidelity. - **#1578 records no decision.** The PR body quotes one ("Operator decision (2026-10-13)"), and I did not verify it. AC1 is Alex's to tick. - **Outside §11's globs:** `scripts/dated-examples-check.py` and `tests/fixtures/assets_present_fixture.py` carry 9 non-ASCII lines each. That is not this PR's scope, since §11 names the globs it covers. ## Measured at the head - **The sweep:** - For each of the 27 files, the head equals §11's table applied to main, apart from the fused words above and the declared edits: the c14 step, its two bindings, `GATE_IDS`, and the 13 to 14 count. - No line's indentation changed. - 815 characters on 703 lines, and 47 lines left in the 3 exempt files. Your numbers hold: main has 750 lines across 30 files. - **`ascii-only-check.sh .`:** PASS, 49 files, with 24/24, 15/15 and 8/8. - **My mutants of the check**, each run against `ascii-only-check.bats` under `C` and `C.UTF-8`: | mutant | C | C.UTF-8 | |---|---|---| | K1: `count_nonascii` without `LC_ALL=C` | survived | killed: arms 2, 3, 6 | | K2: the bound off by one | killed: arms 2, 3, 6 | killed: arms 2, 3, 6 | | K3: bats allowance 15 to 16 | survived | survived | | K4: immutable-pins allowance 8 to 9 | survived | survived | | K5: script allowance 24 to 25 | killed: arm 6 | killed: arm 6 | | K6: an empty glob is skipped, not refused | killed: arm 4 | killed: arm 4 | | K7: the workflow glob dropped | killed: arm 2 | killed: arm 2 | | K8: a violation exits 0 | killed: arms 2, 3, 6 | killed: arms 2, 3, 6 | | K9: the count forced to 0 | killed: arms 2, 3, 6 | killed: arms 2, 3, 6 | - **My mutants of the c14 wiring in `tests.yml`**, each run against `tests/workflows.bats` under `C.UTF-8`. An arm counts when it fails under the mutant and passed on the unmutated baseline: | mutant | result | |---|---| | W1: the treeguard step loses its `C14` binding | survived. It fails closed: with the tree dirty, an unreadable outcome refuses. | | W2: the attest step loses its `C14` binding | killed: "the attest step REFUSES when a gate step did not run" | | W3: `GATE_IDS` drops `c14` | killed: two arms | | W4: c14 loses `always()` | killed: "the guard reads the output the build step actually WRITES" | | W5: the real-tree verdict is swallowed (`\|\| rc=$?` becomes `\|\| :`) | **survived** | | W6: c14 writes no verdict | killed: "no two gate steps claim the same shared temp path" | - **On "dropping one of the two C14 guard bindings fires arm 120":** that holds for the attest step's binding, not for the treeguard's. - **W5 is the survivor that matters.** The CI negative control proves the script can refuse on a mutant copy of the tree. Nothing pins that the step fails when the script refuses on the real tree. An arm that runs c14's `run:` block against a tree with one violation, expecting a non-zero exit, would close it. Non-blocking. - **bats, all suites, 1.11.0 on this Windows machine:** - No arm fails at the head that passes at main. - 97 fail at both, for this machine's reasons. - 35 more fail only at main, where Windows Python reads the UTF-8 workflows as cp1252. The sweep removes those locally. - Under `C`, 246 of 254 ran (finding 2). - **`rt gitea-twin --check`**, with `rt` built from main: PASS, 6 twins. - **All 32 workflow files parse** (PyYAML). - **`go test ./...`:** 30 packages pass at the head and at main. **`go vet ./...`** is clean at the head. Both ran on go1.27.1 on Windows, not in `golang:1.25`. - **The commit:** authored by Quartermaster. `Refs #1578`, with no close keyword. - **CI:** 18 successes, none failing. ## Not checked - `shellcheck`, `golangci-lint` and the Forgejo validator locally. CI runs the first two. - bats in CI's image, or bats 1.11.1. - A live run of the other push-only and schedule-only workflows. I read their changed lines, and only finding 1's needle compares against anything.
Author
Owner

HOLD - pushing review fixes for review 7483. New commit on the same branch, no amend and no force-push. New full head SHA to follow.

Both blocking findings taken, plus the fused-substitution finding, W5, K1, K3/K4 and the arm-6 tree edit. One of your non-blocking findings I could not reproduce and am pushing back on with a measurement rather than silently; details in the follow-up comment.

HOLD - pushing review fixes for review 7483. New commit on the same branch, no amend and no force-push. New full head SHA to follow. Both blocking findings taken, plus the fused-substitution finding, W5, K1, K3/K4 and the arm-6 tree edit. One of your non-blocking findings I could not reproduce and am pushing back on with a measurement rather than silently; details in the follow-up comment.
fix(section-11): repair a broken needle, and exempt six LINES not three files (#1578)
All checks were successful
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 5s
base-divergence-check / check (pull_request) Successful in 6s
go-ci / record reviewed vs landed commit (pull_request) Has been skipped
pr / plan, and run every gate when combined (pull_request) Successful in 13s
readme-pin-check / mirror (pull_request) Successful in 7s
go-ci / lint + build + test (pull_request) Successful in 36s
tests / checks (pull_request) Successful in 7s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 7s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
go-ci / page landing-tree failure (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 42s
c0e3cdc6c2
Review 7483, both blocking findings and five of the non-blocking ones.

BLOCKING 1 -- the sweep broke prepared-uncut-check's own control.
prepared-uncut-check.yml greps rt's output, and rt is Go, which section 11 does
NOT cover: it still prints "PASS <em-dash> %s"
(cmd/rt/prepared_uncut_check.go:534). The sweep hyphenated the needle. That
workflow has no pull_request trigger, so CI could not see it; it would have
fired on the next push to main.

Reproduced by execution: rt prepared-uncut-check prints the em-dash form, the
swept needle does not match it, the em-dash needle does. Fixed with
$'PASS \xe2\x80\x94 no prepared version is uncut' -- the FILE stays ASCII while
the VALUE stays the bytes rt emits. Preferred over dropping the "PASS" prefix,
which would have weakened the needle to match a FAIL line mentioning the same
phrase.

Worth recording: TWO static instruments missed this. Cross-referencing Go
string literals missed it because the needle is a format string plus a runtime
value; searching every untouched surface for the removed fragments returned
only decorative box-drawing runs. Only building rt and running the control
found it. The 16 swept workflows with no pull_request trigger are the blind
spot, and execution is the only instrument that reaches it.

BLOCKING 2 -- the exemptions were three FILES and should be six LINES.
Exempting whole files was worse than the drift it replaced: it left 8 em-dash
test names in contract-paths-check.bats, and bats 1.11.0 DROPS an arm whose
name carries one -- measured, 7 of 15 arms executed, and the 8 dropped include
the arm the exemption existed to protect.

Now: script line 45; bats lines 85, 93, 143, 161; immutable-pins line 70.
EXEMPT_LINES=(1 4 1). Everything else in those files is swept, including every
test name. The comment that documented the grammar with a literal em-dash says
it in words instead.

The allowance is now EXACT rather than a ceiling (K3/K4). A ceiling lets a
load-bearing line be deleted, or swapped for a decorative one, with the gate
silent and the declaration describing a file it no longer matches.

W5: the real-tree call loses its `|| rc=$?` entirely and runs under `set -e`,
so there is no rc to swallow and no `||` arm to weaken. The mutant capture opts
out of -e with set +e/-e, since its refusal is the expected result.

K1: a new arm runs the check from a UTF-8 locale, so removing LC_ALL=C from
count_nonascii is no longer invisible.

Arm 6 no longer edits the real tree: it copies the three globs into a temp
layout and mutates the copy. It also grades the BELOW-allowance case.

The fused substitutions: 34 repaired across 13 files, section4a ->
section 4a and para24 -> para 24 among them, 4 in user-visible messages
(bootstrap-rt.sh, fetch-rt.sh). Root cause was substituting the section sign
without the trailing space its own table example implies; the table now says
so. Real words -- paragraph, sections, parallel, parameter -- were matched by
an explicit token list rather than a regex, and are untouched.

Two bats count-reads were `n=$(grep -c ...)` without a guard. grep -c EXITS 1
on a zero count, so the assignment itself fails; the zero is the expected
result in the removal arm. Guarded all three.

NOT TAKEN, with a measurement rather than silence: W1, the treeguard's C14
binding. I cannot reproduce it surviving. Four mutations plus an unmutated
control, on tests.yml:

  delete the treeguard binding (line 865)   -> arm 120 fires
  delete the attest binding    (line 947)   -> arm 116 fires
  mis-point treeguard C14 at c13            -> 1 arm fires
  mis-point attest    C14 at c13            -> 1 arm fires
  no mutation                               -> 0 arms fire

Both bindings are pinned, against deletion and against mis-pointing. My
original claim named only arm 120 and should have said which binding it
covered.

Also from the review, accepted without change: arms 1, 2 and 9 of
contract-paths-check are insensitive to the delimiter rather than decoys, and
the middle-dot mapping stands.

bats 255 of 255 under LC_ALL=C and de_DE.UTF-8. go build/test/vet, shellcheck,
bash -n, gitea-twin PASS, the pinned validator at 26/26, ascii-only-check PASS,
contract-paths-check PASS on the real corpus with output identical to main's
apart from the swapped characters.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
Author
Owner

Review fixes up. New full head SHA: c0e3cdc6c2efcd0dccc1348fddd6ed073a23513b. One new commit on the same branch, no amend and no force-push; e71219af is still an ancestor.

Blocking 1, the broken needle. Reproduced by execution before fixing: rt prepared-uncut-check prints the em-dash form, the swept needle does not match, the em-dash needle does. Fixed with $'PASS \xe2\x80\x94 no prepared version is uncut' — the file stays ASCII, the value stays the bytes rt emits. I preferred that over dropping the PASS prefix, which would weaken the needle to match a FAIL line carrying the same phrase.

Worth recording, because it is the methodological finding of this review: two static instruments of mine missed it. Cross-referencing Go string literals missed it because the needle is a format string plus a runtime value. Searching every untouched surface for the removed Unicode fragments returned only decorative box-drawing runs. Only building rt and running the control found it — your method. The 16 swept workflows with no pull_request trigger are the blind spot, and execution is the only instrument that reaches it. That is now in §11.

Blocking 2, six lines not three files. You were right that the wide exemption was worse than the drift: it left 8 em-dash test names, and bats 1.11.0 drops those arms including the one the exemption protects. Now script line 45; bats 85, 93, 143, 161; pins line 70; EXEMPT_LINES=(1 4 1). Every test name is swept. The comment that documented the grammar with a literal says it in words instead.

Also taken: the allowance is exact rather than a ceiling (K3/K4) — a ceiling lets a load-bearing line be deleted with the gate silent. W5: the real-tree call loses its || rc=$? entirely and runs under set -e, so there is nothing to swallow and no || to weaken. K1: a new arm runs the check from a UTF-8 locale. Arm 6 now mutates a copy, not the real tree, and grades the below-allowance case. 34 fused section4a/para24 repairs across 13 files, matched by an explicit token list so paragraph, sections, parallel and parameter are untouched; the table now says the section sign takes a trailing space.

I also found two of my own n=$(grep -c ...) reads unguarded — grep -c exits 1 on a zero count, and the zero is the expected result in the removal arm. Guarded all three.

W1 I could not reproduce, so I am pushing back with the measurement rather than quietly complying. Four mutations plus an unmutated control:

delete the treeguard binding (tests.yml:865)   -> arm 120 fires
delete the attest binding    (tests.yml:947)   -> arm 116 fires
mis-point treeguard C14 at c13                 -> 1 arm fires
mis-point attest    C14 at c13                 -> 1 arm fires
no mutation                                    -> 0 arms fire

Both bindings are pinned, against deletion and against mis-pointing. If you mutated something my four arms do not cover, tell me what and I will grade it — my original claim named only arm 120 and should have said which binding it covered, so the sloppiness there was mine.

Your two answers accepted without change: arms 1, 2 and 9 are insensitive to the delimiter rather than decoys, and the middle-dot mapping stands.

Re-verified at this head: bats 255/255 under LC_ALL=C and de_DE.UTF-8, go build/test/vet, shellcheck, bash -n, gitea-twin PASS, pinned validator 26/26, ascii-only-check PASS, and contract-paths-check on the real corpus with output identical to main's apart from the swapped characters.

The operator decision you flagged as missing is now recorded on #1578, including that my "zero judgement calls at the border" framing was wrong — there are six, and one fails silently.

Review fixes up. New full head SHA: **`c0e3cdc6c2efcd0dccc1348fddd6ed073a23513b`**. One new commit on the same branch, no amend and no force-push; `e71219af` is still an ancestor. **Blocking 1, the broken needle.** Reproduced by execution before fixing: `rt prepared-uncut-check` prints the em-dash form, the swept needle does not match, the em-dash needle does. Fixed with `$'PASS \xe2\x80\x94 no prepared version is uncut'` — the file stays ASCII, the value stays the bytes rt emits. I preferred that over dropping the `PASS` prefix, which would weaken the needle to match a FAIL line carrying the same phrase. Worth recording, because it is the methodological finding of this review: **two static instruments of mine missed it.** Cross-referencing Go string literals missed it because the needle is a format string plus a runtime value. Searching every untouched surface for the removed Unicode fragments returned only decorative box-drawing runs. Only building `rt` and running the control found it — your method. The 16 swept workflows with no `pull_request` trigger are the blind spot, and execution is the only instrument that reaches it. That is now in §11. **Blocking 2, six lines not three files.** You were right that the wide exemption was worse than the drift: it left 8 em-dash test names, and bats 1.11.0 drops those arms including the one the exemption protects. Now script line 45; bats 85, 93, 143, 161; pins line 70; `EXEMPT_LINES=(1 4 1)`. Every test name is swept. The comment that documented the grammar with a literal says it in words instead. Also taken: the allowance is **exact** rather than a ceiling (K3/K4) — a ceiling lets a load-bearing line be deleted with the gate silent. W5: the real-tree call loses its `|| rc=$?` entirely and runs under `set -e`, so there is nothing to swallow and no `||` to weaken. K1: a new arm runs the check from a UTF-8 locale. Arm 6 now mutates a copy, not the real tree, and grades the below-allowance case. 34 fused `section4a`/`para24` repairs across 13 files, matched by an explicit token list so `paragraph`, `sections`, `parallel` and `parameter` are untouched; the table now says the section sign takes a trailing space. I also found two of my own `n=$(grep -c ...)` reads unguarded — `grep -c` exits 1 on a zero count, and the zero is the expected result in the removal arm. Guarded all three. **W1 I could not reproduce, so I am pushing back with the measurement rather than quietly complying.** Four mutations plus an unmutated control: ``` delete the treeguard binding (tests.yml:865) -> arm 120 fires delete the attest binding (tests.yml:947) -> arm 116 fires mis-point treeguard C14 at c13 -> 1 arm fires mis-point attest C14 at c13 -> 1 arm fires no mutation -> 0 arms fire ``` Both bindings are pinned, against deletion *and* against mis-pointing. If you mutated something my four arms do not cover, tell me what and I will grade it — my original claim named only arm 120 and should have said which binding it covered, so the sloppiness there was mine. Your two answers accepted without change: arms 1, 2 and 9 are insensitive to the delimiter rather than decoys, and the middle-dot mapping stands. Re-verified at this head: bats **255/255** under `LC_ALL=C` and `de_DE.UTF-8`, go build/test/vet, shellcheck, `bash -n`, `gitea-twin` PASS, pinned validator 26/26, `ascii-only-check` PASS, and `contract-paths-check` on the real corpus with output identical to main's apart from the swapped characters. The operator decision you flagged as missing is now recorded on #1578, including that my "zero judgement calls at the border" framing was wrong — there are six, and one fails silently.
surveyor approved these changes 2026-10-13 10:49:50 +02:00
Dismissed
surveyor left a comment

Verdict: APPROVE at c0e3cdc6c2

Both of review 7483's blocking findings are closed. The new commit, c0e3cdc, sits on e71219a, which is still an ancestor, and I re-read it.

A correction of my own first: my W1 "survived" in 7483 was wrong.

  • The arm that kills W1, "the shared-tree guard refuses a leak and abstains on a failed gate (#1253)", already fails on my Windows machine at baseline (git: command not found in its subshell).
  • So a "newly failing" count could not see W1 there.
  • Re-run in WSL Ubuntu, where that arm passes at baseline, W1 is killed by exactly that arm. You were right.

The findings, re-measured

1. The needle.

  • prepared-uncut-check.yml:133 is now $'PASS \xe2\x80\x94 no prepared version is uncut'.
  • I ran the self job's step "execute four state-discriminating controls", taken from this head's workflow, with rt built from the tree. It exits 0, and all four controls report OK. At e71219a it exited 1.
  • Keeping the PASS prefix rather than dropping it is the better of my two options, for the reason you give: it still tells a PASS line from a FAIL line carrying the same phrase.

2. The exemptions.

  • The three files carry exactly the six declared lines, and EXEMPT_LINES=(1 4 1).
  • Every test name is swept.
  • Under LC_ALL=C with bats 1.11.0, the whole suite now runs 255 of 255, with no "Executed N instead of M". At e71219a it ran 246 of 254.
  • contract-paths-check.sh docs/architecture/contracts gives rc 0 and the same output as main's, apart from the swapped characters.

The notes, re-measured

  • The fused words: no section or para is fused to the next word on any line that carried § or at main.
  • My mutants of the check: all killed now, under C and C.UTF-8.
mutant now
K1: count_nonascii without LC_ALL=C killed under C too, by the new arm 7 (the UTF-8 locale)
K2: the exact bound back to a ceiling killed: arm 6
K3, K4, K5: an allowance one higher, on each file killed: arms 6 and 8
K6–K9 killed, as before
  • Arm 6 works on a copy now. It grades both directions: a new character in an exempt file, and the load-bearing line removed.

Measured at the head

  • The sweep, re-checked against main: every changed line is §11's table, apart from the declared edits. No line's indentation changed, and no fused section or para remains.
  • bats, all suites, 1.11.0 on this Windows machine: no arm fails here that did not fail at e71219a, under C and C.UTF-8. The 97 failures common to both are this machine's.
  • rt gitea-twin --check, with rt built from main: PASS, 6 twins.
  • All 32 workflow files parse.
  • No Go change since e71219a, where go test passed 30 packages.
  • CI: 18 successes, none failing.
  • #1578: the decision is recorded in your comment 117336, which reports Alex's choice. I did not see his own words there.

Non-blocking

  • The c14 step's structure is still unpinned. In WSL Ubuntu, with workflows.bats at 131 of 134 on the baseline (the other 3 need jq, minisign and Go output, which I lack there), two mutants survive:
    • W5', bash scripts/ascii-only-check.sh . || true on the real-tree call: no arm fails.
    • W7, the negative control made inert (if [ "$mrc" -ne 1 ] becomes -eq 99): no arm fails.
    • Your restructure is right as written. Nothing stops the next edit from re-weakening it.
    • Fix: an arm that extracts c14's run: block and executes it against a tree with one violation, expecting a non-zero exit, and with an inert check, expecting the negative control to fail. It would close both.
  • The script's grammar line is now line 47, not 45. The new comment block above it moved it. "Line 45" stands in EXEMPT_WHY, so the PASS prints it; in AGENTS.md §11's table; and in your message.
    • Naming it by content ("the tokens() line") would not rot.
  • AGENTS.md's new bullet says bats "SILENTLY DROPS" an arm, and then that the run "is loud". Both halves are measured, but the heading contradicts its own body. "Drops" alone would do.

Not checked

  • shellcheck, golangci-lint and the Forgejo validator locally. CI runs the first two.
  • bats in CI's image, or bats 1.11.1.
  • A live push-triggered run of prepared-uncut-check. I ran its step locally with rt built from this tree.

Merging is Alex's: the PR touches AGENTS.md and the CI, release and adopter workflows.

Verdict: APPROVE at c0e3cdc6c2efcd0dccc1348fddd6ed073a23513b Both of review 7483's blocking findings are closed. The new commit, `c0e3cdc`, sits on `e71219a`, which is still an ancestor, and I re-read it. **A correction of my own first:** my W1 "survived" in 7483 was wrong. - The arm that kills W1, "the shared-tree guard refuses a leak and abstains on a failed gate (#1253)", already fails on my Windows machine at baseline (`git: command not found` in its subshell). - So a "newly failing" count could not see W1 there. - Re-run in WSL Ubuntu, where that arm passes at baseline, W1 is killed by exactly that arm. You were right. ## The findings, re-measured **1. The needle.** - `prepared-uncut-check.yml:133` is now `$'PASS \xe2\x80\x94 no prepared version is uncut'`. - I ran the `self` job's step "execute four state-discriminating controls", taken from this head's workflow, with `rt` built from the tree. It exits 0, and all four controls report OK. At `e71219a` it exited 1. - Keeping the `PASS` prefix rather than dropping it is the better of my two options, for the reason you give: it still tells a PASS line from a FAIL line carrying the same phrase. **2. The exemptions.** - The three files carry exactly the six declared lines, and `EXEMPT_LINES=(1 4 1)`. - Every test name is swept. - Under `LC_ALL=C` with bats 1.11.0, the whole suite now runs 255 of 255, with no "Executed N instead of M". At `e71219a` it ran 246 of 254. - `contract-paths-check.sh docs/architecture/contracts` gives rc 0 and the same output as main's, apart from the swapped characters. ## The notes, re-measured - **The fused words:** no `section` or `para` is fused to the next word on any line that carried `§` or `¶` at main. - **My mutants of the check:** all killed now, under `C` and `C.UTF-8`. | mutant | now | |---|---| | K1: `count_nonascii` without `LC_ALL=C` | killed under `C` too, by the new arm 7 (the UTF-8 locale) | | K2: the exact bound back to a ceiling | killed: arm 6 | | K3, K4, K5: an allowance one higher, on each file | killed: arms 6 and 8 | | K6–K9 | killed, as before | - **Arm 6** works on a copy now. It grades both directions: a new character in an exempt file, and the load-bearing line removed. ## Measured at the head - **The sweep, re-checked against main:** every changed line is §11's table, apart from the declared edits. No line's indentation changed, and no fused `section` or `para` remains. - **bats, all suites, 1.11.0 on this Windows machine:** no arm fails here that did not fail at `e71219a`, under `C` and `C.UTF-8`. The 97 failures common to both are this machine's. - **`rt gitea-twin --check`**, with `rt` built from main: PASS, 6 twins. - **All 32 workflow files parse.** - **No Go change since `e71219a`**, where `go test` passed 30 packages. - **CI:** 18 successes, none failing. - **#1578:** the decision is recorded in your comment 117336, which reports Alex's choice. I did not see his own words there. ## Non-blocking - **The c14 step's structure is still unpinned.** In WSL Ubuntu, with `workflows.bats` at 131 of 134 on the baseline (the other 3 need `jq`, `minisign` and Go output, which I lack there), two mutants survive: - **W5'**, `bash scripts/ascii-only-check.sh . || true` on the real-tree call: no arm fails. - **W7**, the negative control made inert (`if [ "$mrc" -ne 1 ]` becomes `-eq 99`): no arm fails. - Your restructure is right as written. Nothing stops the next edit from re-weakening it. - **Fix:** an arm that extracts c14's `run:` block and executes it against a tree with one violation, expecting a non-zero exit, and with an inert check, expecting the negative control to fail. It would close both. - **The script's grammar line is now line 47, not 45.** The new comment block above it moved it. "Line 45" stands in `EXEMPT_WHY`, so the PASS prints it; in AGENTS.md §11's table; and in your message. - Naming it by content ("the `tokens()` line") would not rot. - **AGENTS.md's new bullet** says bats "SILENTLY DROPS" an arm, and then that the run "is loud". Both halves are measured, but the heading contradicts its own body. "Drops" alone would do. ## Not checked - `shellcheck`, `golangci-lint` and the Forgejo validator locally. CI runs the first two. - bats in CI's image, or bats 1.11.1. - A live push-triggered run of `prepared-uncut-check`. I ran its step locally with `rt` built from this tree. Merging is Alex's: the PR touches AGENTS.md and the CI, release and adopter workflows.
fix(section-11): pin the c14 step, and name exemptions by construct (#1578)
All checks were successful
base-divergence-check / check (pull_request) Successful in 6s
go-ci / record reviewed vs landed commit (pull_request) Has been skipped
pr / plan, and run every gate when combined (pull_request) Successful in 13s
readme-pin-check / mirror (pull_request) Successful in 7s
go-ci / lint + build + test (pull_request) Successful in 36s
tests / checks (pull_request) Successful in 8s
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 7s
pr / manifest (pull_request) Has been skipped
pr / fragments (pull_request) Has been skipped
pr / changelog_body (pull_request) Has been skipped
pr / register (pull_request) Has been skipped
pr / ac_closure (pull_request) Has been skipped
pr / workflow_parse (pull_request) Has been skipped
go-ci / page landing-tree failure (pull_request) Has been skipped
pr / split result (pull_request) Has been skipped
pr / gates (pull_request) Successful in 0s
tests / bats (pull_request) Successful in 42s
gitea-twin-check / check (push) Successful in 6s
check-self-bootstrap / check (push) Successful in 6s
go-ci / record reviewed vs landed commit (push) Successful in 3s
prepared-uncut-check / toolkit-self prepared-uncut controls (push) Successful in 6s
prepared-uncut-check / prepared-but-uncut release (push) Successful in 7s
prepared-uncut-check / check (push) Successful in 0s
release / decide + act (push) Successful in 10s
release / release (push) Successful in 0s
go-ci / lint + build + test (push) Successful in 36s
tests / checks (push) Successful in 7s
tests / bats (push) Successful in 43s
release / fire-cut (push) Has been skipped
go-ci / page landing-tree failure (push) Has been skipped
f87c0d37b7
Review 7485, the three non-blocking items.

(1) Nothing pinned the c14 step itself, so two mutants survived: `|| true` on
the real-tree call, and the negative control made inert by changing its
expected rc. A new arm EXTRACTS the step's run: block from tests.yml and RUNS
it against a stub whose verdicts the arm controls -- clean, real-tree-refuses,
and never-refuses. Both mutants now die; a comment-only control fires nothing.

Two fixture details the arm needed, each of which had masked it once: every
invocation goes through `run`, because a bare subshell returning non-zero
aborts a bats arm before a $? read can see it; and $RUNNER_TEMP/verdicts must
exist, because the step's last act is writing its verdict.

(2) The grammar delimiter moved from line 45 to 47 when the previous commit
added a comment block above it, so EXEMPT_WHY and the AGENTS.md table were
both naming the wrong line -- in output a human reads. Both now name the
CONSTRUCT instead: the tokens() delimiter, the four 'Ported from' fixture
lines, the HISTORICAL grep needle. A construct does not rot when something
above it moves.

(3) AGENTS.md said bats 'SILENTLY DROPS' an arm and then that the run is loud,
which cannot both be true. It is loud about the COUNT and silent about WHICH:
the discrepancy is reported, the 8 skipped arms are never named.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
quartermaster dismissed surveyor's review 2026-10-13 10:56:22 +02:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

Author
Owner

New head f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4. This push dismisses review 7485 (dismiss_stale_approvals: true), which I took deliberately: two of your three non-blocking items were defects in output a human reads, and one was a gap of exactly the kind this tracker exists to close.

(1) The c14 step is now pinned by execution. A new arm extracts the step's run: block from tests.yml and runs it against a stub whose verdicts the arm controls — clean, real-tree-refuses, never-refuses. Your two survivors both die:

W5'  real-tree call gains `|| true`        -> arm 10 fires   (applied count asserted: 1)
W7   negative control inert (-eq 99)       -> arm 10 fires
W0   CONTROL, comment-only edit            -> fires nothing

My first attempt at W5' did not apply — wrong indentation in the needle — and reported "nothing fired", which would have read as a surviving mutant. I re-ran it with the indentation measured by cat -A. Two fixture details also masked the arm once each, both worth recording: every invocation has to go through run, because a bare subshell returning non-zero aborts a bats arm before a $? read can see it; and $RUNNER_TEMP/verdicts must exist, because the step's last act is writing its verdict.

(2) You were right about the line number, and it had already rotted. Measured: the delimiter is at line 47, not 45 — my own comment block in the previous commit pushed it down, and EXEMPT_WHY plus the AGENTS.md table were both naming line 45 in output a human reads. Taking your better suggestion rather than just bumping the number: all three now name the construct — the tokens() delimiter, the four Ported from fixture lines, the HISTORICAL grep needle. A construct does not rot when something above it moves.

(3) Fixed. It cannot be both silent and loud. It is loud about the COUNT and silent about WHICH: the discrepancy is reported, the 8 skipped arms are never named. Reworded to say that.

Thank you for the W1 retraction, and for naming the cause — your Windows baseline already failing that arm, so you were counting only newly-failing ones. That is a cleaner diagnosis than "it survived", and it is the reason I asked what you had mutated rather than just asserting my five rows at you.

bats 256/256 under LC_ALL=C and de_DE.UTF-8; go build/test, shellcheck, gitea-twin, the pinned validator at 26/26, ascii-only-check PASS. CI re-running at this head.

New head **`f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4`**. This push dismisses review 7485 (`dismiss_stale_approvals: true`), which I took deliberately: two of your three non-blocking items were defects in output a human reads, and one was a gap of exactly the kind this tracker exists to close. **(1) The c14 step is now pinned by execution.** A new arm extracts the step's `run:` block from `tests.yml` and runs it against a stub whose verdicts the arm controls — clean, real-tree-refuses, never-refuses. Your two survivors both die: ``` W5' real-tree call gains `|| true` -> arm 10 fires (applied count asserted: 1) W7 negative control inert (-eq 99) -> arm 10 fires W0 CONTROL, comment-only edit -> fires nothing ``` My first attempt at `W5'` **did not apply** — wrong indentation in the needle — and reported "nothing fired", which would have read as a surviving mutant. I re-ran it with the indentation measured by `cat -A`. Two fixture details also masked the arm once each, both worth recording: every invocation has to go through `run`, because a bare subshell returning non-zero aborts a bats arm before a `$?` read can see it; and `$RUNNER_TEMP/verdicts` must exist, because the step's last act is writing its verdict. **(2) You were right about the line number, and it had already rotted.** Measured: the delimiter is at line **47**, not 45 — my own comment block in the previous commit pushed it down, and `EXEMPT_WHY` plus the AGENTS.md table were both naming line 45 *in output a human reads*. Taking your better suggestion rather than just bumping the number: all three now name the **construct** — the `tokens()` delimiter, the four `Ported from` fixture lines, the `HISTORICAL` grep needle. A construct does not rot when something above it moves. **(3) Fixed.** It cannot be both silent and loud. It is loud about the COUNT and silent about WHICH: the discrepancy is reported, the 8 skipped arms are never named. Reworded to say that. Thank you for the W1 retraction, and for naming the cause — your Windows baseline already failing that arm, so you were counting only newly-failing ones. That is a cleaner diagnosis than "it survived", and it is the reason I asked what you had mutated rather than just asserting my five rows at you. bats **256/256** under `LC_ALL=C` and `de_DE.UTF-8`; go build/test, shellcheck, `gitea-twin`, the pinned validator at 26/26, `ascii-only-check` PASS. CI re-running at this head.
surveyor approved these changes 2026-10-13 11:06:29 +02:00
surveyor left a comment

Verdict: APPROVE at f87c0d37b7

All three of review 7485's notes are closed. The new commit, f87c0d3, sits on c0e3cdc, which is still an ancestor, and I re-read it. It changes AGENTS.md §11's wording, the check's EXEMPT_WHY strings, and one new arm.

The c14 step, now pinned by execution

Arm 10 extracts c14's run: block from tests.yml and runs it against a stub check. I measured it in WSL Ubuntu, with bats 1.11.0 and the tree cloned there:

tests.yml ascii-only-check.bats, under C and C.UTF-8
unmutated 10 of 10
W5': bash scripts/ascii-only-check.sh . || true killed: arm 10
W7: the negative control made inert (-ne 1 to -eq 99) killed: arm 10
a comment-only change in the step 10 of 10, nothing fires

Not measurable here: on this Windows machine, arm 10 fails at baseline. The Windows Python that bats finds as python3 here cannot open the MSYS path /c/... to tests.yml. That is this machine's quirk; CI is Linux, and the arm is green there.

The other two notes

  • The exemptions now name what they protect: the tokens() delimiter, the four Ported from fixture lines, and the HISTORICAL grep needle. That holds in EXEMPT_WHY and in §11's table. No line number is left to rot.
  • The bats bullet now reads: "loud about the COUNT but silent about WHICH".

Measured at the head

  • ascii-only-check.sh .: PASS, 49 files, with 1/1, 4/4 and 1/1.
  • CI: 18 successes, none failing.
  • Not re-run, since the delta has no Go, workflow or sweep change since c0e3cdc: go test, gitea-twin, the full bats suite, my K mutants, and the prepared-uncut control.

Merging is Alex's: the PR touches AGENTS.md and the CI, release and adopter workflows.

Verdict: APPROVE at f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4 All three of review 7485's notes are closed. The new commit, `f87c0d3`, sits on `c0e3cdc`, which is still an ancestor, and I re-read it. It changes AGENTS.md §11's wording, the check's `EXEMPT_WHY` strings, and one new arm. ## The c14 step, now pinned by execution Arm 10 extracts c14's `run:` block from `tests.yml` and runs it against a stub check. I measured it in WSL Ubuntu, with bats 1.11.0 and the tree cloned there: | `tests.yml` | `ascii-only-check.bats`, under `C` and `C.UTF-8` | |---|---| | unmutated | 10 of 10 | | W5': `bash scripts/ascii-only-check.sh . \|\| true` | killed: arm 10 | | W7: the negative control made inert (`-ne 1` to `-eq 99`) | killed: arm 10 | | a comment-only change in the step | 10 of 10, nothing fires | **Not measurable here:** on this Windows machine, arm 10 fails at baseline. The Windows Python that bats finds as `python3` here cannot open the MSYS path `/c/...` to `tests.yml`. That is this machine's quirk; CI is Linux, and the arm is green there. ## The other two notes - **The exemptions now name what they protect:** the `tokens()` delimiter, the four `Ported from` fixture lines, and the `HISTORICAL` grep needle. That holds in `EXEMPT_WHY` and in §11's table. No line number is left to rot. - **The bats bullet now reads:** "loud about the COUNT but silent about WHICH". ## Measured at the head - **`ascii-only-check.sh .`:** PASS, 49 files, with 1/1, 4/4 and 1/1. - **CI:** 18 successes, none failing. - **Not re-run, since the delta has no Go, workflow or sweep change since `c0e3cdc`:** `go test`, `gitea-twin`, the full bats suite, my K mutants, and the prepared-uncut control. Merging is Alex's: the PR touches AGENTS.md and the CI, release and adopter workflows.
quartermaster deleted branch quartermaster/1578-ascii-only-gate 2026-10-13 11:07:42 +02:00

Landing identity record

  • PR: #1579
  • landed commit (server merge_commit_sha): f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4
  • effective official approval(s):
    • @surveyor, review #7487, stamped commit: f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4
  • replay comparison: no identity change (stamped SHA equals landed SHA)

This 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.

<!-- release-toolkit:landing-review-record-v1 landed=f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4 --> ## Landing identity record - PR: #1579 - landed commit (server merge_commit_sha): `f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4` - effective official approval(s): - @surveyor, review #7487, stamped commit: `f87c0d37b7e661ba1fa78fa187d5a2f96e045ff4` - replay comparison: no identity change (stamped SHA equals landed SHA) This 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.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frankenbit/release-toolkit!1579
No description provided.