Gladex Agent Logs
Agent run logs & app logs · env: prod · LAN-only investor surface
Overview
| Run logs | 607 files, 23.3 MB |
| Latest run log | run-20260927-070048-205.log |
| Log directory | /data/agent-logs |
| App log directory | /opt/startup/prod/logs |
Run logs (newest first, last 50)
| File | Size | Modified (UTC) |
|---|---|---|
| run-20260927-070048-205.log | 341 KB | 2026-09-27 05:20:01 |
| run-20260927-060824-204.log | 396 KB | 2026-09-27 04:50:48 |
| run-20260927-051844-203.log | 421 KB | 2026-09-27 03:58:24 |
| run-20260927-040036-202.log | 687 KB | 2026-09-27 03:08:44 |
| run-20260927-031532-201.log | 117 KB | 2026-09-27 01:50:36 |
| run-20260927-020118-200.log | 492 KB | 2026-09-27 01:05:32 |
| run-20260927-015118-199.log | 153 B | 2026-09-26 23:51:18 |
| run-20260927-014117-198.log | 153 B | 2026-09-26 23:41:18 |
| run-20260927-013116-197.log | 153 B | 2026-09-26 23:31:17 |
| run-20260927-012116-196.log | 153 B | 2026-09-26 23:21:16 |
| run-20260927-011115-195.log | 153 B | 2026-09-26 23:11:16 |
| run-20260927-010114-194.log | 153 B | 2026-09-26 23:01:15 |
| run-20260927-005114-193.log | 153 B | 2026-09-26 22:51:14 |
| run-20260927-004113-192.log | 153 B | 2026-09-26 22:41:14 |
| run-20260927-003112-191.log | 153 B | 2026-09-26 22:31:13 |
| run-20260927-002111-190.log | 153 B | 2026-09-26 22:21:12 |
| run-20260927-001111-189.log | 153 B | 2026-09-26 22:11:11 |
| run-20260927-000110-188.log | 153 B | 2026-09-26 22:01:11 |
| run-20260926-235109-187.log | 153 B | 2026-09-26 21:51:10 |
| run-20260926-234108-186.log | 153 B | 2026-09-26 21:41:09 |
| run-20260926-233108-185.log | 153 B | 2026-09-26 21:31:08 |
| run-20260926-232107-184.log | 153 B | 2026-09-26 21:21:08 |
| run-20260926-231106-183.log | 153 B | 2026-09-26 21:11:07 |
| run-20260926-230105-182.log | 190 B | 2026-09-26 21:01:06 |
| run-20260926-225105-181.log | 153 B | 2026-09-26 20:51:05 |
| run-20260926-224104-180.log | 153 B | 2026-09-26 20:41:05 |
| run-20260926-223103-179.log | 153 B | 2026-09-26 20:31:04 |
| run-20260926-222103-178.log | 190 B | 2026-09-26 20:21:03 |
| run-20260926-221102-177.log | 153 B | 2026-09-26 20:11:03 |
| run-20260926-220101-176.log | 190 B | 2026-09-26 20:01:02 |
| run-20260926-215100-175.log | 153 B | 2026-09-26 19:51:01 |
| run-20260926-214100-174.log | 153 B | 2026-09-26 19:41:00 |
| run-20260926-213059-173.log | 153 B | 2026-09-26 19:31:00 |
| run-20260926-212058-172.log | 153 B | 2026-09-26 19:20:59 |
| run-20260926-205455-171.log | 133 KB | 2026-09-26 19:10:58 |
| run-20260926-202137-170.log | 215 KB | 2026-09-26 18:44:55 |
| run-20260926-194055-169.log | 257 KB | 2026-09-26 18:11:37 |
| run-20260926-191403-168.log | 160 KB | 2026-09-26 17:30:55 |
| run-20260926-180537-167.log | 281 KB | 2026-09-26 17:04:03 |
| run-20260926-170523-166.log | 164 KB | 2026-09-26 15:55:37 |
| run-20260926-162230-165.log | 178 KB | 2026-09-26 14:55:23 |
| run-20260926-154050-164.log | 198 KB | 2026-09-26 14:12:30 |
| run-20260926-153049-163.log | 153 B | 2026-09-26 13:30:50 |
| run-20260926-152049-162.log | 153 B | 2026-09-26 13:20:49 |
| run-20260926-151048-161.log | 153 B | 2026-09-26 13:10:49 |
| run-20260926-150047-160.log | 153 B | 2026-09-26 13:00:48 |
| run-20260926-145046-159.log | 153 B | 2026-09-26 12:50:47 |
| run-20260926-144046-158.log | 153 B | 2026-09-26 12:40:46 |
| run-20260926-143045-157.log | 153 B | 2026-09-26 12:30:46 |
| run-20260926-142044-156.log | 153 B | 2026-09-26 12:20:45 |
Tail — run-20260927-070048-205.log (last 200 lines)
**Safety**: read-only by construction — `git ls-tree` / `git show <sha>:<path>` / `git cat-file -e <sha>:<path>` object reads only, no index/lock use, so it never mutates git state and is safe to run while other shifts commit; the Go materialization lives in a `mkdtemp()` dir removed in a `finally`. The suite asserts `git status --porcelain` byte-identical across a live run, on both the sandbox
**Dependencies**: python3 (stdlib only: argparse, contextlib, io, json, os, re, shutil, subprocess, sys, tempfile, time, datetime), git; php/bash/gofmt for their respective languages, `go` for the compile gate (any missing binary → exit 3, fail closed — never a silent pass).
**Tests**:
- `bash tests/test_repo_lint.sh` → **366 assertions**, hermetic (throwaway git repos under `${TMPDIR:-/tmp}/opencode`, trap-cleaned): clean→0 with exact per-language/skip counts (`files_total = linted + skipped`), all five languages caught with path+line, the 219fd8f incident replayed **both directions** (bad worktree/clean commit → 0; clean worktree/bad commit → 1), arg/env exit contracts
- **Section N — the compile gate** (its own stdlib-only module in a separate throwaway repo; `$SB/repo`'s `main.go`-without-`go.mod` is case N10): clean module → 0 with `go_compile.ok`; **the 395b9b5 shape verbatim → 1** naming `pkg/a_test.go:4 [go-compile]` *and* asserting `all(f['lang'] != 'go')` + `linted == {'go': 2}` — the per-file gate passed, proving the parse gate is blind rather t
- **Section O — the CHANGELOG version-identity gate** (`$SB/repo`'s own changelog): no `CHANGELOG.md` → `attempted false / no_changelog / ok null`, exit 0 and **no** failure or error from the absent file, human line `changelog-version: no CHANGELOG.md`; duplicate-free → exit 0 with `entries == unique`, `path == CHANGELOG.md`, human verdict `changelog-version: 2 changelog version heading(s),
- **Section T — the citation rule** (`[0.4.82]`, queue item (26); 24 assertions): a citation of an **existing** heading → exit 0 with `citations_seen`/`citations_in_series` counted, `citations_missing == []`, `series == ['7.1']`; **the defect** → exit 1 with `FAIL PLAN.md:2 [changelog]`, the message `cites [7.1.5] but CHANGELOG.md has no such heading`, `citations_missing == [{'path','line','
- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 16 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `fail to parse` anywhere in the output, `json_exit_code` mirroring the process and the failure's `lang` shown to be the field the line is derived from; **U2** a broken PHP file → `result: 1 file(s) fail to
- **Section V — the NUMBER in the closing line counts files** (`[0.4.84]`, queue item (30); 14 assertions): U's two branches are both **one-failure** fixtures, so every assertion in U is satisfied by a counter that never counted files at all — V supplies the case where the two counts disagree. **V1** three `## [7.1.1]` headings → **two `FAIL CHANGELOG.md:` lines** with `result: 1 file(s) fai
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && awk 'NR==2347||NR==2350||NR==2361' tools/REGISTRY.md | fold -w 200 | sed -n '1,200p'
- `bash tests/test_repo_lint.sh` → **366 assertions**, hermetic (throwaway git repos under `${TMPDIR:-/tmp}/opencode`, trap-cleaned): clean→0 with exact per-language/skip counts (`files_total = li
nted + skipped`), all five languages caught with path+line, the 219fd8f incident replayed **both directions** (bad worktree/clean commit → 0; clean worktree/bad commit → 1), arg/env exit contracts
, exact JSON key set (now including `changelog_version`), symlink invocation (sandbox + real `/data/tools`), missing-binary→3 and hung-linter→3, read-only status proof on the live repo — plus **
section R**, the epilog refusal and its machine-readable form, **section S**, the usage error's, **section T**, the citation rule, **section U**, the human closing line, and **section V**, the number
inside it.
- **Section T — the citation rule** (`[0.4.82]`, queue item (26); 24 assertions): a citation of an **existing** heading → exit 0 with `citations_seen`/`citations_in_series` counted, `citations_mis
sing == []`, `series == ['7.1']`; **the defect** → exit 1 with `FAIL PLAN.md:2 [changelog]`, the message `cites [7.1.5] but CHANGELOG.md has no such heading`, `citations_missing == [{'path','line','
version'}]`, `lang: changelog` (so `promote`'s `_lint_failure_verdict` keeps rendering it as *a rule, not a parse*), `ok`/`exit_code` flipped, and a human summary ending `citation(s) checked, 1 missin
g`; **blob basis** (claim committed, worktree fixed → still 1; after the fix commit → 0); **the fence** → a `[9.9.4]` token is *counted* (`seen 4`) but *not judged* (`in_series 3`, `missing []`,
exit 0) with the human line `… 4 citation(s) checked, 0 missing`; **no `CHANGELOG.md`** → `seen 2, in_series 0, missing [], series []`, exit 0, no failure and no error (tokens read, nothing judge
d); **the contract** → the rule appears in the docstring block *and* in what `--help` renders (derived, byte-for-byte) together with the `SCOPE` sentence; **cleanup** → the section leaves the sand
box green so a later mutant's clean-run assertion cannot fail for its own reason. Fixtures use series **`7.1`** and write the missing token into a *fixture file*, never into this suite — a literal i
n-series version committed here would be a citation in the REAL tree and the rule would fail the repo that hosts its own test (that constraint is documented in the tool's `SCOPE` paragraph too).
- **Mutation**: 22, each precondition-asserted to occur exactly once, caught by a divergence assertion, and surgically checked — M1 exit gate defeated (`(1 if failures else 0)` → 0); M2 `--sha` ig
nored (always lints HEAD); M3 `.php` dropped from `EXT_LANG` (mutant still catches broken sh); **M4** `failures.extend(gentries)` → `extend([])` (the 395b9b5 defect returns: a build-breaking commit
reports 0; mutant still 0 on a compiling commit); **M5** `3 if errors` → `1 if errors` (an environment failure reads as "broken file": real=3/mutant=1; mutant still 1 on broken php); **M6** the gate
's blob read → `open(<worktree path>)` (the 219fd8f class applied to Go: a fixed worktree hides a broken commit; mutant still 1 when the worktree is broken too); **M7** `failures.extend(cl_failures)
` → `extend([])` (the hand-off dies while the JSON still names the twin — `ok false`, `duplicates == ['1.0.0']`, `exit_code 0`; mutant still exits 1 on broken php); **M8** `if ver in first_seen:`
→ `if False:` (the test itself dies: `duplicates == []` and `ok true` where the real tool reports a twin; mutant still green on a clean changelog); **M9** the changelog blob read pinned to `HEAD` in
stead of `--sha` while the existence probe still uses `--sha` (an ancestor's twin vanishes — real=1/mutant=0; mutant still 0 on a clean HEAD); **M10** the CHANGELOG rule dropped from the tool's one
contract (the `[0.4.56]` defect itself planted) — caught by P2/P5 while **P1 and P4 stay green**: the docstring and `--help` still agree because they are one copy, so they lost the rule *together*;
surgical checks are the agreement holding, the parse rule surviving, and `--help` still exiting 0; **M11** a second copy of the contract planted as a source comment `--help` never renders — caught b
y **P1 alone**, with P4 deliberately asserted **green** (what `--help` prints is still byte-identical to the docstring), proving the source-level count is not redundant with the render-level check; **
M12** the same shape for a *derived* section (a source-comment second copy of the go-gate text) — caught by **Q-source**, with **Q-render asserted green** on the mutant (`--help` still equals the do
cstring, so the byte comparison provably cannot see it) and `--help` still exiting 0; **M13** the inverse — `("env:", "Environment:")` repointed to the languages heading, so `env:` renders a differe
nt docstring block — caught by **Q-render**, with **Q-source asserted green** (the Environment text still occurs exactly once, so the count cannot see a misattribution) and the `exit codes:` pair st
ill agreeing (one pair misattributed, not the whole epilog). M12/M13 are complementary by construction, exactly as M10/M11 are: each one's green assertions are what prove the other's necessity; **M14*
* the pre-`[0.4.60]` state reproduced — R's trigger (the docstring heading renamed to `Environment (renamed):` while the tuple still says `Environment:`) **in the same copy as** the refusal's condit
ion defeated (`if missing:` → `if False:`). Two edits deliberately: defeating the guard **alone** changes nothing, because a healthy docstring still yields seven full sections — I built it that wa
y first and the mutant came out **green**, which is the finding rather than a flaw in the mutation: the guard is not the defect, it is what makes an always-available trigger loud. With both halves pre
sent `--help` exits 0 over a label printed on nothing, stderr silent — caught by R's refusal assertions and by `r_labels` (R3's own check, run against the mutant) going red at **exactly** `env:` —
while an unrelated section still byte-equals its docstring (surgical: one condition defeated, not the derivation); **M15** the machine channel dropped (`[0.4.61]`): R's trigger **in the same copy as*
* the fix reverted (`raise SystemExit(die(None, default_repo(), message, sha, fmt))` → the bare `sys.stderr.write(message)` + `SystemExit(EXIT_CANNOT)`), i.e. the refusal output as it stood before t
his step. Two edits for the same reason M14 needs two — with a healthy docstring nothing refuses, so the dropped channel is unobservable (I planted the revert alone first and the mutant came out gre
en, **exit 0**: the second time this mutation taught its own lesson) — and the catch is the point: **every human assertion stays GREEN** (exit still 3, pair still named, `--help` still refusing with
an empty stdout) while **R9b** sees the empty stdout. The old suite asserted the *absence* of JSON, so the defect passed it. **M16** the usage-error channel dropped (`[0.4.62]`): `if fmt == "json":`
→ `if False:` in `_Parser.error`, i.e. the pre-step state exactly — argparse always prints usage to stderr and exits 2, so `--format json --timeout abc` gives a jq pipeline empty stdin again. **On
e edit where M14 and M15 each needed two, and the difference is the finding**: those needed a *trigger* because a healthy docstring never refuses, whereas here the argv that says json is supplied **by
the test**, so the trigger and the defect are the same line. Caught by **S3** (stdout empty again) with **every human assertion staying GREEN** — exit still 2, usage still on stderr, `--help` still
0, the healthy json run still 0 — because the human path never had the check; that asymmetry is the argument for having written S1/S13/S14/S15 as guards. **M17–M19 (the citation rule, `[0.4.82]`)
** — three ways to lint green over a version nobody wrote, each with a surgical value that says *which* one: **M17** the existence test → `if False` → the token is still **counted and classified
in series** but never judged (`seen ≥ 3, in_series ≥ 3, missing [], exit 0`), caught `real=1 mutant=0`; **M18** the **series fence** dropped (`in_series = list(citations)`) → the one excluded t
oken becomes the defect (`in_series 4`, `missing ['9.9.4']`), caught `real=0 mutant=1`, i.e. red on a fixture the real rule calls clean — and its replace runs through python with `t.count(old) == 1`
asserted **inside** the script, because a sed pattern of brackets and quotes that matches the wrong line edits a path no fixture exercises and comes back green; **M19** the **collection** dropped (`c
itations.extend([])`) → `citations_seen == 0`, nothing was scanned at all, caught `real=1 mutant=0`. M17 vs M19 is the pair that matters: both exit 0 over the defect, and only `citations_seen` (coun
ted-but-unjudged vs never-scanned) tells them apart. Every mutant file is `[ -f ]`-checked before it is run, so a build that produced nothing cannot be reported as a catch. **M20/M21 (`[0.4.83]`, the
closing line)** — the two halves of one judgement call, both planted in `_result_line`'s syntax-set test by exact-string replace with `t.count(old) == 1` asserted inside the script: **M20** `if all(
…)` → `if True:` (every failure called a parse/compile failure — the pre-step constant with the count still derived) is caught by **U1** while the exit code stays **1 on both sides**, and its su
rgical check is a *real* syntax failure where mutant and tool say exactly the same sentence; **M21** `if all(…)` → `if False:` (a rule failure never reported as a rule) is caught by **U2** with a
*syntax* fixture, and its surgical check is a rule fixture where the inverted mutant is **indistinguishable** from the real tool — which is precisely why only a wording pin on the other branch can c
atch it. Neither mutant changes any verdict, so no exit-code assertion sees either: the section U pins are the only thing that does. **M22 (`[0.4.84]`, the count)** — the pre-step defect planted in
the one expression that decides the number: `n_files = len({f.get("path") for f in failures})` → `n_files = len(failures)`, planted by the same exact-string replace with `t.count(old) == 1` asserted
inside the script. Exit code, `kinds` and `failures[]` all stay put, so **every verdict assertion in the suite is green over it**; caught by **V1** with `real_rc == mut_rc == 1` and only the digits t
elling them apart (`real: 1 file(s)`, `mutant: 2 file(s)`), and its surgical check is V3's fixture — one failure per file, where failures and files are equal and the mutant is **indistinguishable**
from the real tool, which is precisely why V1's fixture has to separate them.
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && awk 'NR==2350' tools/REGISTRY.md | fold -w 200
- **Section T — the citation rule** (`[0.4.82]`, queue item (26); 24 assertions): a citation of an **existing** heading → exit 0 with `citations_seen`/`citations_in_series` counted, `citations_mis
sing == []`, `series == ['7.1']`; **the defect** → exit 1 with `FAIL PLAN.md:2 [changelog]`, the message `cites [7.1.5] but CHANGELOG.md has no such heading`, `citations_missing == [{'path','line','
version'}]`, `lang: changelog` (so `promote`'s `_lint_failure_verdict` keeps rendering it as *a rule, not a parse*), `ok`/`exit_code` flipped, and a human summary ending `citation(s) checked, 1 missin
g`; **blob basis** (claim committed, worktree fixed → still 1; after the fix commit → 0); **the fence** → a `[9.9.4]` token is *counted* (`seen 4`) but *not judged* (`in_series 3`, `missing []`,
exit 0) with the human line `… 4 citation(s) checked, 0 missing`; **no `CHANGELOG.md`** → `seen 2, in_series 0, missing [], series []`, exit 0, no failure and no error (tokens read, nothing judge
d); **the contract** → the rule appears in the docstring block *and* in what `--help` renders (derived, byte-for-byte) together with the `SCOPE` sentence; **cleanup** → the section leaves the sand
box green so a later mutant's clean-run assertion cannot fail for its own reason. Fixtures use series **`7.1`** and write the missing token into a *fixture file*, never into this suite — a literal i
n-series version committed here would be a citation in the REAL tree and the rule would fail the repo that hosts its own test (that constraint is documented in the tool's `SCOPE` paragraph too).
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && grep -n "^- \*\*Section [UV]" tools/REGISTRY.md | cut -c1-160
2351:- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 16 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail
2352:- **Section V — the NUMBER in the closing line counts files** (`[0.4.84]`, queue item (30); 14 assertions): U's two branches are both **one-failure** fix
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && awk 'NR==2351' tools/REGISTRY.md | fold -w 200
- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 16 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `fail t
o parse` anywhere in the output, `json_exit_code` mirroring the process and the failure's `lang` shown to be the field the line is derived from; **U2** a broken PHP file → `result: 1 file(s) fail to
parse or compile (exit 1)` with **no** `fail lint (`, i.e. the specific diagnosis does not regress to vagueness; **U3** both at once → `result: 2 file(s) fail lint (changelog, php) (exit 1)` (sorte
d, de-duplicated, both kinds named); **U4** `_SYNTAX_LANGS` in `tools/repo-lint` and in `tools/promote-dev-to-prod` are **the same set**, extracted by regex from both files rather than imported (a chi
ld must not import its parent, and prose agreement is what drifted in `[0.4.53]`); **U5** the function is defined exactly once and `main()` prints it exactly once (no hand-rolled second literal — P/
Q's shape applied to a runtime line); **U6** the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason.
> build · mimo-v2.6-flash-free
[0m← [0mEdit repo/tools/REGISTRY.md
Index: repo/tools/REGISTRY.md
===================================================================
--- repo/tools/REGISTRY.md
+++ repo/tools/REGISTRY.md
@@ -2343,9 +2343,9 @@
**Dependencies**: python3 (stdlib only: argparse, contextlib, io, json, os, re, shutil, subprocess, sys, tempfile, time, datetime), git; php/bash/gofmt for their respective languages, `go` for the compile gate (any missing binary → exit 3, fail closed — never a silent pass).
**Tests**:
-- `bash tests/test_repo_lint.sh` → **366 assertions**, hermetic (throwaway git repos under `${TMPDIR:-/tmp}/opencode`, trap-cleaned): clean→0 with exact per-language/skip counts (`files_total = linted + skipped`), all five languages caught with path+line, the 219fd8f incident replayed **both directions** (bad worktree/clean commit → 0; clean worktree/bad commit → 1), arg/env exit contracts, exact JSON key set (now including `changelog_version`), symlink invocation (sandbox + real `/data/tools`), missing-binary→3 and hung-linter→3, read-only status proof on the live repo — plus **section R**, the epilog refusal and its machine-readable form, **section S**, the usage error's, **section T**, the citation rule, **section U**, the human closing line, and **section V**, the number inside it.
+- `bash tests/test_repo_lint.sh` → **374 assertions**, hermetic (throwaway git repos under `${TMPDIR:-/tmp}/opencode`, trap-cleaned): clean→0 with exact per-language/skip counts (`files_total = linted + skipped`), all five languages caught with path+line, the 219fd8f incident replayed **both directions** (bad worktree/clean commit → 0; clean worktree/bad commit → 1), arg/env exit contracts, exact JSON key set (now including `changelog_version`), symlink invocation (sandbox + real `/data/tools`), missing-binary→3 and hung-linter→3, read-only status proof on the live repo — plus **section R**, the epilog refusal and its machine-readable form, **section S**, the usage error's, **section T**, the citation rule, **section U**, the human closing line (its **U7** + M23 also prove every lang the tool can *emit* is classified), and **section V**, the number inside it.
- **Section N — the compile gate** (its own stdlib-only module in a separate throwaway repo; `$SB/repo`'s `main.go`-without-`go.mod` is case N10): clean module → 0 with `go_compile.ok`; **the 395b9b5 shape verbatim → 1** naming `pkg/a_test.go:4 [go-compile]` *and* asserting `all(f['lang'] != 'go')` + `linted == {'go': 2}` — the per-file gate passed, proving the parse gate is blind rather than merely not reached; blob basis (worktree fix invisible → 1; committed fix → 0); broken *ancestor* `--sha` → 1 while HEAD is clean; `GLADEX_GO_GOCACHE=/dev/null/x` → **3 with `failures == []`** (cannot verify ≠ broken ≠ pass); missing `go` → 3 naming it; `--go-timeout 0.001` → 3 and `--go-timeout 0` → 2; `--help` documents the gate. Live, **content-addressed so it can never flake**: `--sha 395b9b5` must exit 1 blaming `app/src/go/cmd/gladex/commands/status_test.go:5` as `go-compile` and nothing else; `--sha 219fd8f` still exactly one failure (the PHP parse error) **with a passing Go gate**; HEAD `go_compile.go_mod == app/src/go/go.mod`, `files > 40`.
- **Section O — the CHANGELOG version-identity gate** (`$SB/repo`'s own changelog): no `CHANGELOG.md` → `attempted false / no_changelog / ok null`, exit 0 and **no** failure or error from the absent file, human line `changelog-version: no CHANGELOG.md`; duplicate-free → exit 0 with `entries == unique`, `path == CHANGELOG.md`, human verdict `changelog-version: 2 changelog version heading(s), 2 unique`; **the defect shape → exit 1 with the twin deliberately three entries away from its twin** (a consecutive-line comparison would find only adjacent repeats), `duplicates == ['1.0.0']`, `entries 4 / unique 3`, the failure blaming `CHANGELOG.md:9 [changelog]` with `first at line 3`, and `ok false / exit_code 1`; **blob basis** (twin committed, worktree fixed → still 1; after the fix commit → 0); **`--sha` basis** (a duplicated *ancestor* → 1 while HEAD is clean, `requested_sha` echoed, clean HEAD → 0); a non-version `## Random section` heading → `unparseable 1`, `entries 2`, exit 0 and `failures == []` (counted, never a verdict); `--help` documents the gate by name and by rule.
- **Section T — the citation rule** (`[0.4.82]`, queue item (26); 24 assertions): a citation of an **existing** heading → exit 0 with `citations_seen`/`citations_in_series` counted, `citations_missing == []`, `series == ['7.1']`; **the defect** → exit 1 with `FAIL PLAN.md:2 [changelog]`, the message `cites [7.1.5] but CHANGELOG.md has no such heading`, `citations_missing == [{'path','line','version'}]`, `lang: changelog` (so `promote`'s `_lint_failure_verdict` keeps rendering it as *a rule, not a parse*), `ok`/`exit_code` flipped, and a human summary ending `citation(s) checked, 1 missing`; **blob basis** (claim committed, worktree fixed → still 1; after the fix commit → 0); **the fence** → a `[9.9.4]` token is *counted* (`seen 4`) but *not judged* (`in_series 3`, `missing []`, exit 0) with the human line `… 4 citation(s) checked, 0 missing`; **no `CHANGELOG.md`** → `seen 2, in_series 0, missing [], series []`, exit 0, no failure and no error (tokens read, nothing judged); **the contract** → the rule appears in the docstring block *and* in what `--help` renders (derived, byte-for-byte) together with the `SCOPE` sentence; **cleanup** → the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason. Fixtures use series **`7.1`** and write the missing token into a *fixture file*, never into this suite — a literal in-series version committed here would be a citation in the REAL tree and the rule would fail the repo that hosts its own test (that constraint is documented in the tool's `SCOPE` paragraph too).
- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 16 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `fail to parse` anywhere in the output, `json_exit_code` mirroring the process and the failure's `lang` shown to be the field the line is derived from; **U2** a broken PHP file → `result: 1 file(s) fail to parse or compile (exit 1)` with **no** `fail lint (`, i.e. the specific diagnosis does not regress to vagueness; **U3** both at once → `result: 2 file(s) fail lint (changelog, php) (exit 1)` (sorted, de-duplicated, both kinds named); **U4** `_SYNTAX_LANGS` in `tools/repo-lint` and in `tools/promote-dev-to-prod` are **the same set**, extracted by regex from both files rather than imported (a child must not import its parent, and prose agreement is what drifted in `[0.4.53]`); **U5** the function is defined exactly once and `main()` prints it exactly once (no hand-rolled second literal — P/Q's shape applied to a runtime line); **U6** the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason.
> build · mimo-v2.6-flash-free
[0m← [0mEdit repo/tools/REGISTRY.md
Index: repo/tools/REGISTRY.md
===================================================================
--- repo/tools/REGISTRY.md
+++ repo/tools/REGISTRY.md
@@ -2347,9 +2347,9 @@
- `bash tests/test_repo_lint.sh` → **374 assertions**, hermetic (throwaway git repos under `${TMPDIR:-/tmp}/opencode`, trap-cleaned): clean→0 with exact per-language/skip counts (`files_total = linted + skipped`), all five languages caught with path+line, the 219fd8f incident replayed **both directions** (bad worktree/clean commit → 0; clean worktree/bad commit → 1), arg/env exit contracts, exact JSON key set (now including `changelog_version`), symlink invocation (sandbox + real `/data/tools`), missing-binary→3 and hung-linter→3, read-only status proof on the live repo — plus **section R**, the epilog refusal and its machine-readable form, **section S**, the usage error's, **section T**, the citation rule, **section U**, the human closing line (its **U7** + M23 also prove every lang the tool can *emit* is classified), and **section V**, the number inside it.
- **Section N — the compile gate** (its own stdlib-only module in a separate throwaway repo; `$SB/repo`'s `main.go`-without-`go.mod` is case N10): clean module → 0 with `go_compile.ok`; **the 395b9b5 shape verbatim → 1** naming `pkg/a_test.go:4 [go-compile]` *and* asserting `all(f['lang'] != 'go')` + `linted == {'go': 2}` — the per-file gate passed, proving the parse gate is blind rather than merely not reached; blob basis (worktree fix invisible → 1; committed fix → 0); broken *ancestor* `--sha` → 1 while HEAD is clean; `GLADEX_GO_GOCACHE=/dev/null/x` → **3 with `failures == []`** (cannot verify ≠ broken ≠ pass); missing `go` → 3 naming it; `--go-timeout 0.001` → 3 and `--go-timeout 0` → 2; `--help` documents the gate. Live, **content-addressed so it can never flake**: `--sha 395b9b5` must exit 1 blaming `app/src/go/cmd/gladex/commands/status_test.go:5` as `go-compile` and nothing else; `--sha 219fd8f` still exactly one failure (the PHP parse error) **with a passing Go gate**; HEAD `go_compile.go_mod == app/src/go/go.mod`, `files > 40`.
- **Section O — the CHANGELOG version-identity gate** (`$SB/repo`'s own changelog): no `CHANGELOG.md` → `attempted false / no_changelog / ok null`, exit 0 and **no** failure or error from the absent file, human line `changelog-version: no CHANGELOG.md`; duplicate-free → exit 0 with `entries == unique`, `path == CHANGELOG.md`, human verdict `changelog-version: 2 changelog version heading(s), 2 unique`; **the defect shape → exit 1 with the twin deliberately three entries away from its twin** (a consecutive-line comparison would find only adjacent repeats), `duplicates == ['1.0.0']`, `entries 4 / unique 3`, the failure blaming `CHANGELOG.md:9 [changelog]` with `first at line 3`, and `ok false / exit_code 1`; **blob basis** (twin committed, worktree fixed → still 1; after the fix commit → 0); **`--sha` basis** (a duplicated *ancestor* → 1 while HEAD is clean, `requested_sha` echoed, clean HEAD → 0); a non-version `## Random section` heading → `unparseable 1`, `entries 2`, exit 0 and `failures == []` (counted, never a verdict); `--help` documents the gate by name and by rule.
- **Section T — the citation rule** (`[0.4.82]`, queue item (26); 24 assertions): a citation of an **existing** heading → exit 0 with `citations_seen`/`citations_in_series` counted, `citations_missing == []`, `series == ['7.1']`; **the defect** → exit 1 with `FAIL PLAN.md:2 [changelog]`, the message `cites [7.1.5] but CHANGELOG.md has no such heading`, `citations_missing == [{'path','line','version'}]`, `lang: changelog` (so `promote`'s `_lint_failure_verdict` keeps rendering it as *a rule, not a parse*), `ok`/`exit_code` flipped, and a human summary ending `citation(s) checked, 1 missing`; **blob basis** (claim committed, worktree fixed → still 1; after the fix commit → 0); **the fence** → a `[9.9.4]` token is *counted* (`seen 4`) but *not judged* (`in_series 3`, `missing []`, exit 0) with the human line `… 4 citation(s) checked, 0 missing`; **no `CHANGELOG.md`** → `seen 2, in_series 0, missing [], series []`, exit 0, no failure and no error (tokens read, nothing judged); **the contract** → the rule appears in the docstring block *and* in what `--help` renders (derived, byte-for-byte) together with the `SCOPE` sentence; **cleanup** → the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason. Fixtures use series **`7.1`** and write the missing token into a *fixture file*, never into this suite — a literal in-series version committed here would be a citation in the REAL tree and the rule would fail the repo that hosts its own test (that constraint is documented in the tool's `SCOPE` paragraph too).
-- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 16 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `fail to parse` anywhere in the output, `json_exit_code` mirroring the process and the failure's `lang` shown to be the field the line is derived from; **U2** a broken PHP file → `result: 1 file(s) fail to parse or compile (exit 1)` with **no** `fail lint (`, i.e. the specific diagnosis does not regress to vagueness; **U3** both at once → `result: 2 file(s) fail lint (changelog, php) (exit 1)` (sorted, de-duplicated, both kinds named); **U4** `_SYNTAX_LANGS` in `tools/repo-lint` and in `tools/promote-dev-to-prod` are **the same set**, extracted by regex from both files rather than imported (a child must not import its parent, and prose agreement is what drifted in `[0.4.53]`); **U5** the function is defined exactly once and `main()` prints it exactly once (no hand-rolled second literal — P/Q's shape applied to a runtime line); **U6** the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason.
+- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 20 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `fail to parse` anywhere in the output, `json_exit_code` mirroring the process and the failure's `lang` shown to be the field the line is derived from; **U2** a broken PHP file → `result: 1 file(s) fail to parse or compile (exit 1)` with **no** `fail lint (`, i.e. the specific diagnosis does not regress to vagueness; **U3** both at once → `result: 2 file(s) fail lint (changelog, php) (exit 1)` (sorted, de-duplicated, both kinds named); **U4** `_SYNTAX_LANGS` in `tools/repo-lint` and in `tools/promote-dev-to-prod` are **the same set**, extracted by regex from both files rather than imported (a child must not import its parent, and prose agreement is what drifted in `[0.4.53]`); **U5** the function is defined exactly once and `main()` prints it exactly once (no hand-rolled second literal — P/Q's shape applied to a runtime line); **U6** the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason; **U7** (`[0.4.85]`, queue item (31)) — U4 compares two *declarations* to each other and never asks whether either covers what the tool **emits**, so `u7_classify <path>` derives four sets from that file's own source (the `EXT_LANG` and `SHEBANG_LANG` dict values, the `_SYNTAX_LANGS` frozenset, every literal `"lang": "…"` the gates hand to `failures[]`) and asserts three things: **U7-1** it read four non-empty sets (an extraction that reads nothing would pass every subtraction below vacuously — the same "cannot verify is not a pass" discipline the tool itself has), **U7-2** every dispatch lang is classified as syntax, **U7-3** every emittable lang is syntax **or one of a DECLARED rule set** (`RULE_LANGS = {"changelog"}` — declared rather than derived as `gate − syntax`, which would absorb a new rule automatically and make the check tautological), **U7-4** `rules_match=YES`, that declaration compared back against the gate in **both** directions so it may not drift either. The same function runs against `$TOOL` and, in M23, against a copy carrying one extra `EXT_LANG` entry.
- **Section V — the NUMBER in the closing line counts files** (`[0.4.84]`, queue item (30); 14 assertions): U's two branches are both **one-failure** fixtures, so every assertion in U is satisfied by a counter that never counted files at all — V supplies the case where the two counts disagree. **V1** three `## [7.1.1]` headings → **two `FAIL CHANGELOG.md:` lines** with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `result: 2 file(s)` anywhere (the defect, reproduced in the harness rather than quoted from a run); **V2** the same run in JSON, `len(failures) == 2` and `len({f['path'] …}) == 1`, both paths `CHANGELOG.md` — the two figures the sentence must *choose* between, asserted to differ so the fix cannot be "right" by coincidence; **V3** the opposite direction, two distinct broken PHP files → still `result: 2 file(s) fail to parse or compile (exit 1)`, so a fix that collapsed the number to 1 is caught too; **V4** the source shape, three counts (the derivation occurs once, both branch strings are fed `{n_files}`, `{len(failures)} file(s) fail` occurs zero times) — a later edit cannot silently hand the label a failure count again; **V5** the sandbox left green. `kinds` is deliberately **not** de-duplicated per file: one file tripping two rules must still be told both, so the noun decides the number while the list stays per failure.
- **Pre-fix replay for `[0.4.84]`**: the new suite against `HEAD`'s tool blob swapped **in place** (old md5 `16d7a0cc073ab416ff0d685ae666c481` → new `0df9317ebe19afafeafb4766e3f8c405`, restored and re-verified byte-identical; log `/tmp/opencode/pre-fix-replay-84.log`) → **357 passed / 6 failed**, every red a section-V finding or an unplantable precondition: **V1 ×2** (the `result: 1 file(s)` pin and its `result: 2 file(s)` twin), **V4 ×3** (the distinct-path derivation absent, both `{n_files}` branch strings absent, `{len(failures)} file(s) fail` present twice), **M22's precondition** (the needle does not exist — its other three assertions could not run, hence **357 counted pre-fix against 366 post-fix**: 366 − 6 − 3). Guards that passed pre-fix and thereby identify themselves: **V1's exit code and FAIL-line count**, **V2** (the JSON figures the line must choose between were already right — only the printed number was wrong), **V3** (the over-correction direction was already true before the fix, which is exactly why it is a guard and not a finding), **V5** and all of sections A–U unchanged. Captured **in place**, the way `[0.4.83]` learned to: a copy outside `tools/` makes section L report `repo_root: /tmp/…` and exit 3.
- **Pre-fix replay for `[0.4.83]`**: the new suite against `HEAD`'s tool blob swapped **in place** (new md5 `16d7a0cc073ab416ff0d685ae666c481`; old `0a5ccfcbbc9093212cce0c4d54d4d28c`, restored and re-verified byte-identical) → **333 passed / 9 failed**, every red a section-U finding or an unplantable precondition: **U1 ×2** (the rule line and its `fail to parse` twin), **U2**, **U3**, **U4** (no `_SYNTAX_LANGS` exists yet, so the set is unmatched), **U5 ×2** (0 definitions, 0 prints), **M20/M21 preconditions ×2** (the `if all(k in _SYNTAX_LANGS …)` needle does not exist — their other six assertions could not run, hence **342 counted pre-fix against 348 post-fix**). Guards that passed pre-fix and thereby identify themselves: **U1's exit codes**, **U2's exit code**, **U3's exit code** and all of sections A–T unchanged. Captured **in place**, not via `REPO_LINT_BIN` pointing outside `tools/`: the first attempt did exactly that and returned 11 extra reds in section L, because `default_repo()` resolves relative to the script — a harness artifact (`repo_root: /tmp/…`, exit 3) that cost one capture to read correctly, the same trap `[0.4.60]`'s replay documented.
- **Pre-fix replay for `[0.4.82]`**: the new suite against `HEAD`'s tool blob swapped **in place** (so section L's `repo_root == '/data/repo'` still holds; old md5 `fb0d6c5d1ec55d91a0cd075dfee9e2ee` → new `0a5ccfcbbc9093212cce0c4d54d4d28c`, restored and re-verified) → **297 passed / 21 failed**: 18 section-T findings plus M17/M18/M19's three **unplantable preconditions** (their other six assertions could not run — 318 counted pre-fix against 324 post-fix). Guards passing pre-fix and thereby identifying themselves: the exit-0 halves of T1/T3/T4/T5/T6/T7, and all of A–S. **Re-taken against the final bytes**: the first capture's md5 (`f6764ec8…`, an intermediate version superseded by the `Exit codes:` 1-line wording edit) described a file that no longer existed by the time this entry was written, so the swap was re-run with the final suite — identical 297 / 21 and the identical 18 + 3 breakdown (`/tmp/opencode/pre-fix-replay-82-final.log`).
> build · mimo-v2.6-flash-free
[0m← [0mEdit repo/tools/REGISTRY.md
Index: repo/tools/REGISTRY.md
===================================================================
--- repo/tools/REGISTRY.md
+++ repo/tools/REGISTRY.md
@@ -2357,9 +2357,9 @@
- **Section Q — EVERY epilog section derived, not copied** (`[0.4.59]`): Q applies P's two checks to the six remaining docstring/epilog pairs (`languages`, `go compile gate`, `changelog version gate`, `reads GIT BLOBS`, `env`, `examples`). **Q-render** (Q1–Q6) runs `--help` and compares each labelled section to its docstring block **byte for byte**, requiring the docstring side to be non-empty (a heading that no longer exists in the docstring cannot pass by rendering nothing); **Q-source** (Q7–Q12) counts each section's distinctive text in the tool source and requires **exactly one** — the check that sees a copy `--help` never renders. **Q13** requires the hand-written `Usage:` synopsis to be *gone* (needle `[--sha SHA] [--format human|json]`, count 0): argparse generates the synopsis from the argument definitions, and the docstring's copy had already drifted from it (no `-h`, `human|json` vs `{human,json}`), so the fifth pair the queue named was closed by deletion rather than by keeping two things in step. Guards: `--help` exits 0 and its `usage:` line is argparse's own.
- **Section R — the epilog REFUSES to build a label over nothing** (`[0.4.60]`, widened by `[0.4.61]`): derivation made the epilog correct, but `docstring_section` still returned `""` for a heading it could not find and `"\n\n".join` does not complain about `""`, so a renamed or deleted docstring heading produced `env:` printed above a blank line with `--help` exiting **0** — and only Q-render's non-empty requirement stood in the way, i.e. a defect that was *tested* rather than *prevented*, covering only the heading someone named. **R1–R3** are guards on the healthy tool (exit 0, no refusal on stderr, all seven labels rendering a non-empty body); **R4–R9** cover a heading **renamed away** while the tuple still names it (refuse with exit 3; name the pair `'env:' -> 'Environment:'`; nothing on stdout; name **only** the broken pair), and R9 points `GLADEX_REPO_DIR` at the real sandbox repo for the same reason it always did — run from `$SB` the mutant's default repo is not a git repo and it exited 3 for *that* reason, a false pass the red had to be read to catch. **R10–R12b** cover a heading that **exists but whose block is empty** — `docstring_section` stops at the first blank line, so "found" must not mean "fine". **R9's original assertion was written inverted and is corrected in `[0.4.61]`**: it required *no* parseable JSON from the refusing tool — which is exactly the defect (`| jq` meeting empty stdin), so it passed for it. It now asserts the contract, and the block grew accordingly: **R9b** one object on stdout with `ok false`/`exit 3`; **R9c** it names the broken pair; **R9d** it is an ERROR not a verdict (`failures`/`errors` empty, `sha_resolved` null); **R9e** `go_compile`/`changelog_version` null (die()'s shape); **R9f** stderr clean in json mode; **R9g** its **key set is byte-equal to a normal run's** — the shape-level proof that the refusal is the contract and not an exception to it.
- **Section R, argv parity — the refusal's reading of argv must BE argparse's** (`[0.4.61]`): it fires before argparse exists, so it reads argv with a throwaway parser built from the **same `_add_flags`** definitions; each assertion below is the first place a hand-rolled `sys.argv` scan would diverge. **R13** one definition, two call sites (source count); **R14/R14b** the `--format=json` equals form; **R15/R15b** argparse's unique-prefix rule (`--form json`) with **R15c** as the guard that argparse really does accept it; **R16/R16b** `--sha probe-r9` echoed by the refusal with **R16c/R16d** as the parity reference — the *healthy* tool must report the same `requested_sha`, one expectation read by two code paths; **R17/R17b/R17c** `--` termination (the scan stops there and emits no JSON, while argparse itself rejects the same argv with exit 2); **R18/R18b/R18c/R18d** an argv argparse rejects (refusal still fires, still names the pair, no `usage:` noise leaked, stdout still empty in human mode) with **R19** as the guard that argparse keeps ownership of validation (invalid choice alone → exit 2). **R17b, R18c and R18d are vacuously green before the fix** — with no scan in existence nothing could print or leak — and they only begin testing something once it exists; disclosed as guards, not findings. **Guards that passed against the pre-fix tool and thereby identify themselves**: R1–R8, R10–R12b, the exit-3 half of R9/R14/R15/R16, R15c, R16c/R16d, R17, R17c, R18, R18b, R19.
- **Section S — a usage error under `--format json` is still ONE JSON object** (`[0.4.62]`): `repo-lint --format json --timeout abc` used to exit 2 with usage prose on stderr and an **empty stdout**, so a `| jq` consumer got jq's own parse error and could not tell a mistyped flag from a crash — the last path with no object after `[0.4.61]`, and reachable on a perfectly healthy tool. **S1 is the human guard** (usage on stderr, empty stdout, exit 2 — passes before *and* after, which is what makes it a guard rather than a finding, and what M16 leaves green while S3 goes red); **S2–S8** the defect itself (exit 2 preserved; stdout non-empty; one object with `ok false`/`exit_code 2`; `error` names the bad argument; **key set byte-equal to a normal run's** — the shape-level proof that the usage object *is* the contract; not a verdict — `failures[]`/`errors[]` empty, `sha_resolved` null; stderr clean); **S9–S11** argv forms a hand-rolled scan gets wrong — the failing token **before** `--format` (a full pre-parse aborts first and would answer `human`), `--format=json`, `--form json`; **S12** the tool's own `p.error()` checks take the same route as argparse's rejections (both are inside one `try`); **S13–S15** the three argv shapes where **no** format can be read (`--format yaml`, a bare `--format`, anything after `--`) → human, asserted not assumed; **S16/S16b** exactly one `add_argument("--format", …)` and two readers of it (`_add_format_flag` feeds `_add_flags` and `_format_of` — splitting the flag out must not become a second choices list); **S17/S18** guards that a healthy json run still exits 0 and `--help` still exits 0. The section captures **stdout and stderr separately** throughout (`run_tool` merges them) because *which stream* is half of what it asserts, which is why it also needed `assert_empty`/`assert_nonempty`: `assert_not_contains` takes its needle as argument 2, so an empty needle matches every haystack and "this stream is empty" could not be expressed without failing by construction.
-- **Mutation**: 22, each precondition-asserted to occur exactly once, caught by a divergence assertion, and surgically checked — M1 exit gate defeated (`(1 if failures else 0)` → 0); M2 `--sha` ignored (always lints HEAD); M3 `.php` dropped from `EXT_LANG` (mutant still catches broken sh); **M4** `failures.extend(gentries)` → `extend([])` (the 395b9b5 defect returns: a build-breaking commit reports 0; mutant still 0 on a compiling commit); **M5** `3 if errors` → `1 if errors` (an environment failure reads as "broken file": real=3/mutant=1; mutant still 1 on broken php); **M6** the gate's blob read → `open(<worktree path>)` (the 219fd8f class applied to Go: a fixed worktree hides a broken commit; mutant still 1 when the worktree is broken too); **M7** `failures.extend(cl_failures)` → `extend([])` (the hand-off dies while the JSON still names the twin — `ok false`, `duplicates == ['1.0.0']`, `exit_code 0`; mutant still exits 1 on broken php); **M8** `if ver in first_seen:` → `if False:` (the test itself dies: `duplicates == []` and `ok true` where the real tool reports a twin; mutant still green on a clean changelog); **M9** the changelog blob read pinned to `HEAD` instead of `--sha` while the existence probe still uses `--sha` (an ancestor's twin vanishes — real=1/mutant=0; mutant still 0 on a clean HEAD); **M10** the CHANGELOG rule dropped from the tool's one contract (the `[0.4.56]` defect itself planted) — caught by P2/P5 while **P1 and P4 stay green**: the docstring and `--help` still agree because they are one copy, so they lost the rule *together*; surgical checks are the agreement holding, the parse rule surviving, and `--help` still exiting 0; **M11** a second copy of the contract planted as a source comment `--help` never renders — caught by **P1 alone**, with P4 deliberately asserted **green** (what `--help` prints is still byte-identical to the docstring), proving the source-level count is not redundant with the render-level check; **M12** the same shape for a *derived* section (a source-comment second copy of the go-gate text) — caught by **Q-source**, with **Q-render asserted green** on the mutant (`--help` still equals the docstring, so the byte comparison provably cannot see it) and `--help` still exiting 0; **M13** the inverse — `("env:", "Environment:")` repointed to the languages heading, so `env:` renders a different docstring block — caught by **Q-render**, with **Q-source asserted green** (the Environment text still occurs exactly once, so the count cannot see a misattribution) and the `exit codes:` pair still agreeing (one pair misattributed, not the whole epilog). M12/M13 are complementary by construction, exactly as M10/M11 are: each one's green assertions are what prove the other's necessity; **M14** the pre-`[0.4.60]` state reproduced — R's trigger (the docstring heading renamed to `Environment (renamed):` while the tuple still says `Environment:`) **in the same copy as** the refusal's condition defeated (`if missing:` → `if False:`). Two edits deliberately: defeating the guard **alone** changes nothing, because a healthy docstring still yields seven full sections — I built it that way first and the mutant came out **green**, which is the finding rather than a flaw in the mutation: the guard is not the defect, it is what makes an always-available trigger loud. With both halves present `--help` exits 0 over a label printed on nothing, stderr silent — caught by R's refusal assertions and by `r_labels` (R3's own check, run against the mutant) going red at **exactly** `env:` — while an unrelated section still byte-equals its docstring (surgical: one condition defeated, not the derivation); **M15** the machine channel dropped (`[0.4.61]`): R's trigger **in the same copy as** the fix reverted (`raise SystemExit(die(None, default_repo(), message, sha, fmt))` → the bare `sys.stderr.write(message)` + `SystemExit(EXIT_CANNOT)`), i.e. the refusal output as it stood before this step. Two edits for the same reason M14 needs two — with a healthy docstring nothing refuses, so the dropped channel is unobservable (I planted the revert alone first and the mutant came out green, **exit 0**: the second time this mutation taught its own lesson) — and the catch is the point: **every human assertion stays GREEN** (exit still 3, pair still named, `--help` still refusing with an empty stdout) while **R9b** sees the empty stdout. The old suite asserted the *absence* of JSON, so the defect passed it. **M16** the usage-error channel dropped (`[0.4.62]`): `if fmt == "json":` → `if False:` in `_Parser.error`, i.e. the pre-step state exactly — argparse always prints usage to stderr and exits 2, so `--format json --timeout abc` gives a jq pipeline empty stdin again. **One edit where M14 and M15 each needed two, and the difference is the finding**: those needed a *trigger* because a healthy docstring never refuses, whereas here the argv that says json is supplied **by the test**, so the trigger and the defect are the same line. Caught by **S3** (stdout empty again) with **every human assertion staying GREEN** — exit still 2, usage still on stderr, `--help` still 0, the healthy json run still 0 — because the human path never had the check; that asymmetry is the argument for having written S1/S13/S14/S15 as guards. **M17–M19 (the citation rule, `[0.4.82]`)** — three ways to lint green over a version nobody wrote, each with a surgical value that says *which* one: **M17** the existence test → `if False` → the token is still **counted and classified in series** but never judged (`seen ≥ 3, in_series ≥ 3, missing [], exit 0`), caught `real=1 mutant=0`; **M18** the **series fence** dropped (`in_series = list(citations)`) → the one excluded token becomes the defect (`in_series 4`, `missing ['9.9.4']`), caught `real=0 mutant=1`, i.e. red on a fixture the real rule calls clean — and its replace runs through python with `t.count(old) == 1` asserted **inside** the script, because a sed pattern of brackets and quotes that matches the wrong line edits a path no fixture exercises and comes back green; **M19** the **collection** dropped (`citations.extend([])`) → `citations_seen == 0`, nothing was scanned at all, caught `real=1 mutant=0`. M17 vs M19 is the pair that matters: both exit 0 over the defect, and only `citations_seen` (counted-but-unjudged vs never-scanned) tells them apart. Every mutant file is `[ -f ]`-checked before it is run, so a build that produced nothing cannot be reported as a catch. **M20/M21 (`[0.4.83]`, the closing line)** — the two halves of one judgement call, both planted in `_result_line`'s syntax-set test by exact-string replace with `t.count(old) == 1` asserted inside the script: **M20** `if all(…)` → `if True:` (every failure called a parse/compile failure — the pre-step constant with the count still derived) is caught by **U1** while the exit code stays **1 on both sides**, and its surgical check is a *real* syntax failure where mutant and tool say exactly the same sentence; **M21** `if all(…)` → `if False:` (a rule failure never reported as a rule) is caught by **U2** with a *syntax* fixture, and its surgical check is a rule fixture where the inverted mutant is **indistinguishable** from the real tool — which is precisely why only a wording pin on the other branch can catch it. Neither mutant changes any verdict, so no exit-code assertion sees either: the section U pins are the only thing that does. **M22 (`[0.4.84]`, the count)** — the pre-step defect planted in the one expression that decides the number: `n_files = len({f.get("path") for f in failures})` → `n_files = len(failures)`, planted by the same exact-string replace with `t.count(old) == 1` asserted inside the script. Exit code, `kinds` and `failures[]` all stay put, so **every verdict assertion in the suite is green over it**; caught by **V1** with `real_rc == mut_rc == 1` and only the digits telling them apart (`real: 1 file(s)`, `mutant: 2 file(s)`), and its surgical check is V3's fixture — one failure per file, where failures and files are equal and the mutant is **indistinguishable** from the real tool, which is precisely why V1's fixture has to separate them.
+- **Mutation**: 23, each precondition-asserted to occur exactly once, caught by a divergence assertion, and surgically checked — M1 exit gate defeated (`(1 if failures else 0)` → 0); M2 `--sha` ignored (always lints HEAD); M3 `.php` dropped from `EXT_LANG` (mutant still catches broken sh); **M4** `failures.extend(gentries)` → `extend([])` (the 395b9b5 defect returns: a build-breaking commit reports 0; mutant still 0 on a compiling commit); **M5** `3 if errors` → `1 if errors` (an environment failure reads as "broken file": real=3/mutant=1; mutant still 1 on broken php); **M6** the gate's blob read → `open(<worktree path>)` (the 219fd8f class applied to Go: a fixed worktree hides a broken commit; mutant still 1 when the worktree is broken too); **M7** `failures.extend(cl_failures)` → `extend([])` (the hand-off dies while the JSON still names the twin — `ok false`, `duplicates == ['1.0.0']`, `exit_code 0`; mutant still exits 1 on broken php); **M8** `if ver in first_seen:` → `if False:` (the test itself dies: `duplicates == []` and `ok true` where the real tool reports a twin; mutant still green on a clean changelog); **M9** the changelog blob read pinned to `HEAD` instead of `--sha` while the existence probe still uses `--sha` (an ancestor's twin vanishes — real=1/mutant=0; mutant still 0 on a clean HEAD); **M10** the CHANGELOG rule dropped from the tool's one contract (the `[0.4.56]` defect itself planted) — caught by P2/P5 while **P1 and P4 stay green**: the docstring and `--help` still agree because they are one copy, so they lost the rule *together*; surgical checks are the agreement holding, the parse rule surviving, and `--help` still exiting 0; **M11** a second copy of the contract planted as a source comment `--help` never renders — caught by **P1 alone**, with P4 deliberately asserted **green** (what `--help` prints is still byte-identical to the docstring), proving the source-level count is not redundant with the render-level check; **M12** the same shape for a *derived* section (a source-comment second copy of the go-gate text) — caught by **Q-source**, with **Q-render asserted green** on the mutant (`--help` still equals the docstring, so the byte comparison provably cannot see it) and `--help` still exiting 0; **M13** the inverse — `("env:", "Environment:")` repointed to the languages heading, so `env:` renders a different docstring block — caught by **Q-render**, with **Q-source asserted green** (the Environment text still occurs exactly once, so the count cannot see a misattribution) and the `exit codes:` pair still agreeing (one pair misattributed, not the whole epilog). M12/M13 are complementary by construction, exactly as M10/M11 are: each one's green assertions are what prove the other's necessity; **M14** the pre-`[0.4.60]` state reproduced — R's trigger (the docstring heading renamed to `Environment (renamed):` while the tuple still says `Environment:`) **in the same copy as** the refusal's condition defeated (`if missing:` → `if False:`). Two edits deliberately: defeating the guard **alone** changes nothing, because a healthy docstring still yields seven full sections — I built it that way first and the mutant came out **green**, which is the finding rather than a flaw in the mutation: the guard is not the defect, it is what makes an always-available trigger loud. With both halves present `--help` exits 0 over a label printed on nothing, stderr silent — caught by R's refusal assertions and by `r_labels` (R3's own check, run against the mutant) going red at **exactly** `env:` — while an unrelated section still byte-equals its docstring (surgical: one condition defeated, not the derivation); **M15** the machine channel dropped (`[0.4.61]`): R's trigger **in the same copy as** the fix reverted (`raise SystemExit(die(None, default_repo(), message, sha, fmt))` → the bare `sys.stderr.write(message)` + `SystemExit(EXIT_CANNOT)`), i.e. the refusal output as it stood before this step. Two edits for the same reason M14 needs two — with a healthy docstring nothing refuses, so the dropped channel is unobservable (I planted the revert alone first and the mutant came out green, **exit 0**: the second time this mutation taught its own lesson) — and the catch is the point: **every human assertion stays GREEN** (exit still 3, pair still named, `--help` still refusing with an empty stdout) while **R9b** sees the empty stdout. The old suite asserted the *absence* of JSON, so the defect passed it. **M16** the usage-error channel dropped (`[0.4.62]`): `if fmt == "json":` → `if False:` in `_Parser.error`, i.e. the pre-step state exactly — argparse always prints usage to stderr and exits 2, so `--format json --timeout abc` gives a jq pipeline empty stdin again. **One edit where M14 and M15 each needed two, and the difference is the finding**: those needed a *trigger* because a healthy docstring never refuses, whereas here the argv that says json is supplied **by the test**, so the trigger and the defect are the same line. Caught by **S3** (stdout empty again) with **every human assertion staying GREEN** — exit still 2, usage still on stderr, `--help` still 0, the healthy json run still 0 — because the human path never had the check; that asymmetry is the argument for having written S1/S13/S14/S15 as guards. **M17–M19 (the citation rule, `[0.4.82]`)** — three ways to lint green over a version nobody wrote, each with a surgical value that says *which* one: **M17** the existence test → `if False` → the token is still **counted and classified in series** but never judged (`seen ≥ 3, in_series ≥ 3, missing [], exit 0`), caught `real=1 mutant=0`; **M18** the **series fence** dropped (`in_series = list(citations)`) → the one excluded token becomes the defect (`in_series 4`, `missing ['9.9.4']`), caught `real=0 mutant=1`, i.e. red on a fixture the real rule calls clean — and its replace runs through python with `t.count(old) == 1` asserted **inside** the script, because a sed pattern of brackets and quotes that matches the wrong line edits a path no fixture exercises and comes back green; **M19** the **collection** dropped (`citations.extend([])`) → `citations_seen == 0`, nothing was scanned at all, caught `real=1 mutant=0`. M17 vs M19 is the pair that matters: both exit 0 over the defect, and only `citations_seen` (counted-but-unjudged vs never-scanned) tells them apart. Every mutant file is `[ -f ]`-checked before it is run, so a build that produced nothing cannot be reported as a catch. **M20/M21 (`[0.4.83]`, the closing line)** — the two halves of one judgement call, both planted in `_result_line`'s syntax-set test by exact-string replace with `t.count(old) == 1` asserted inside the script: **M20** `if all(…)` → `if True:` (every failure called a parse/compile failure — the pre-step constant with the count still derived) is caught by **U1** while the exit code stays **1 on both sides**, and its surgical check is a *real* syntax failure where mutant and tool say exactly the same sentence; **M21** `if all(…)` → `if False:` (a rule failure never reported as a rule) is caught by **U2** with a *syntax* fixture, and its surgical check is a rule fixture where the inverted mutant is **indistinguishable** from the real tool — which is precisely why only a wording pin on the other branch can catch it. Neither mutant changes any verdict, so no exit-code assertion sees either: the section U pins are the only thing that does. **M22 (`[0.4.84]`, the count)** — the pre-step defect planted in the one expression that decides the number: `n_files = len({f.get("path") for f in failures})` → `n_files = len(failures)`, planted by the same exact-string replace with `t.count(old) == 1` asserted inside the script. Exit code, `kinds` and `failures[]` all stay put, so **every verdict assertion in the suite is green over it**; caught by **V1** with `real_rc == mut_rc == 1` and only the digits telling them apart (`real: 1 file(s)`, `mutant: 2 file(s)`), and its surgical check is V3's fixture — one failure per file, where failures and files are equal and the mutant is **indistinguishable** from the real tool, which is precisely why V1's fixture has to separate them.
- Live: HEAD → exit 0 (176 files — **174 → 176 with `[0.4.65]`**, its own `tools/regression-run` + `tests/test_regression_run.sh` going from untracked to tracked (`linted.bash` 24 → 25, `linted.python` 11 → 12), following **173 → 174 with `[0.4.64]`**; the pre-commit run reads **174** with `bash 24` / `python 11` because those blobs are not there yet — the stale-live-number class, re-read after the commit below — 45 module files compile clean in ~1.6s. **`[0.4.66]` pre-commit read: exit 0, `files_total 176`, `linted {bash 25, go 43, json 11, php 32, python 12}`, `changelog_version entries 70, unique 70, duplicates []`** — both changed files were already tracked, so the post-commit prediction is **176 unchanged** with `entries 71` once `[0.4.66]` lands, re-read after the commit rather than carried. **`[0.4.67]` pre-commit read: exit 0, `files_total 176`, `linted {bash 25, go 43, json 11, php 32, python 12}`, `changelog_version entries 71, unique 71, duplicates []`** — this entry adds two **untracked** files (`tools/queue-source-check`, extensionless `python3` shebang → `linted.python`; `tests/test_queue_source.sh`, `.sh` → `linted.bash`) plus its own heading, so the post-commit prediction is **178** with `bash 26`, `python 13` and `entries 72`, re-read after the commit rather than carried) with `changelog_version` = `attempted true, entries 70, unique 70, unparseable 0, duplicates [], ok true` (**69 → 70 with `[0.4.65]`**, following **68 → 69 with `[0.4.64]`**: the count is read from the COMMITTED blob, so it is re-read after the append commits rather than carried over — it read 68 while `[0.4.64]` was still uncommitted, which is the whole point of re-reading; the working-tree count was verified the anchored way, `grep -c '^## \['` → 69 with `uniq -d` empty, because the greedy `sed 's/.*\[\([^]]*\)\].*/\1/'` form reports **5 phantom duplicates** on this tree — 0.4.31/0.4.40/0.4.44/0.4.49/0.4.62 — by taking the last bracket in a heading that cites other versions. The **file** count is 173, not the 171 drafted mid-run: `[0.4.63]`'s own two mailbox files were untracked when that number was written and tracked once it committed, so 171 → 173 is this entry's own movement rather than a count carried); `--sha 219fd8f` → exit 1 naming `tests/test_mailbox_a11y.php:208 [php]`; `--sha 395b9b5` → exit 1 naming `.../status_test.go:5 [go-compile]`; unknown rev / non-repo → exit 3; `--sha probe-r9` → exit 3 with `requested_sha: probe-r9` (the R16 parity reference, live); `--format yaml` → exit 2 with **usage on stderr and an empty stdout** (no format could be read, so none is invented — `[0.4.62]`); **`--format json` + a bad argv → exit 2 with a 384-byte 15-key object on stdout and 0 bytes on stderr** (`--timeout abc`, `--nonsense`, `--timeout 0`, empty `--sha`, and the failing token placed *before* `--format`), while the same argv in human mode still gives argparse's `usage:`+`error:` with **stdout 0 bytes**; `--help` (**106 lines**, was 57 before the epilog stopped carrying its own prose, 102 before the exit-3 clause widened, 103 through `[0.4.61]`, **+3 for `[0.4.62]`'s widened exit-2 clause**) renders all seven docstring blocks verbatim under their labels; a copy with a heading renamed → `repo-lint: ERROR refusing to run - docstring section missing or empty …` + ` 'env:' -> 'Environment:'` → **exit 3**, stderr only, and under `--format json` the **same refusal as an object** — `ok false`, `exit_code 3`, `error` naming the pair, **stderr 0 bytes** — which is the `| jq` consumer `[0.4.60]`'s queue described, now parsing (`--format=json` → 3; `--form json` → 3; `-- --format json` → no JSON on stdout; `--format yaml` on the broken copy → refusal only, no `usage:` leak) — **and on that same broken copy `--format json --timeout abc` now yields the 458-byte refusal object with `exit_code 3` instead of falling back to `human`**, which is `[0.4.61]`'s own queue item struck as actioned. **`[0.4.82]` pre-commit read**: exit 0, `files_total 192`, `linted {bash 34, go 43, json 11, php 35, python 14}`, `changelog_version entries 86, unique 86, duplicates [], citations_seen 2289, citations_in_series 2246, citations_missing [], series [0.1, 0.2, 0.3, 0.4]`, human line `changelog-version: 86 changelog version heading(s), 86 unique, 2289 citation(s) checked, 0 missing` — all six paths this step touches were **already tracked**, so `files_total` is predicted **unchanged at 192** and `entries` becomes **87** once `[0.4.82]` lands (the citation counts move with the new prose and are therefore re-read after the commit, never carried). **Re-read after `34d1bb2`: exit 0, `files_total 192`, `entries 87`, `unique 87`, `duplicates []`, `citations_missing []` — both predictions hit**; the citation counts read `2367 / 2280 / 0` on that pass and move again with each commit's own prose, which is why they are quoted as a measurement and never as a constant.
- Pre-fix replay: the **then-`HEAD` suite against the then-`HEAD` tool** → **88 passed / 28 failed** (including `L: 395b9b5 … (want rc=1 got=0)`) for the Go gate of `[0.4.3x]`; for the changelog gate the *new* suite against the pre-fix tool (md5 `3a4e09176e24ca3414366952467d4944`, log `/tmp/opencode/changelog-gate/pre-fix.log`, suite md5 `9e352394d02096183adef92d55fc5a73`) → **125 passed / 22 failed**: the exact key-set pin plus every O1–O7 finding red, and M7/M8/M9 unplantable (0 matching lines) — while the six guard-style assertions inside O (absent file adds no failure; fixed commit → 0) already passed, which is what identifies them as guards rather than findings. For `[0.4.56]` the new section P against the pre-fix tool (tool md5 `3ebcf0b4ae7e290796fbed12c57e422b`, suite md5 `a50e16d7a5643bdfd18b667752e50d2c`, log `/tmp/opencode/exitcodes/pre-fix.log`) → **166 passed / 6 failed**: P1 (the contract text occurs **twice**), P2 ×2 (Go rule and CHANGELOG rule both absent from the docstring), P4 (the docstring block and `--help`'s section differ), M10's agreement surgical check (pre-fix both copies still exist, so the mutant's docstring and `--help` disagree), and M11's precondition (already 2 occurrences → unplantable, so its other three assertions could not run pre-fix — hence 172 counted pre-fix against 175 post-fix). Guards that passed pre-fix and thereby identify themselves: P2's parse rule, P3 (all four codes), P4's `--help exits 0`, and all three P5 rules — the epilog was the copy that was right. Baseline re-verified on a checkout of the same commit before the fix: **155/156 then 156/156 twice**, the single red being `L: real repo status changed during a run` (a concurrent identity committed mid-run), not this change. For `[0.4.59]` the new section Q against the pre-fix tool (tool md5 `f17563d67064a79f313ef2bab376cd66`, suite md5 `9217e2653fbed256afb704d0a01fd359`, log `/tmp/opencode/epilogderive/pre-fix.log`; baseline of the *old* suite against the old tool was **175/0** first) → **186 passed / 9 failed**: the seven findings are Q1–Q6 (every pair renders different bytes) and Q13 (the drifted synopsis still present), plus **M12's surgical render check** — which fails pre-fix only because the two renderings differ by definition, i.e. it restates Q2 — and **M13's precondition unplantable** (the derivation tuple does not exist yet, so its other three assertions could not run: hence 186 counted pre-fix against 198 post-fix). **Guards passed pre-fix and thereby identify themselves**: all six Q-source counts (each section's text already occurred exactly once — the copies differed, they were not duplicated line-for-line), `--help exits 0`, the generated-usage line, and M12's precondition plus its "caught" assertion. For `[0.4.60]` the new section R against the pre-fix tool (old tool md5 `4e6c58ffc86441a5745054a4ea45d084`, final suite md5 `e126f791dbcd4b1d9ae0bd0626022d82`, log `/tmp/opencode/epilogrefuse/pre-fix.log`; baseline of the old suite against the old tool was **198/0** first) → **203 passed / 10 failed**, captured **inside a clone of the repo** rather than from `/tmp`: pointing `REPO_LINT_BIN` at a copy outside `tools/` makes section L's live checks fail for *path* reasons, because `default_repo()` resolves relative to the script, so the tool reported `repo_root: /tmp/...` and exited 3 — a harness artifact that cost a second capture to get a red meaning what it says. **Nine of the ten are real**: **R5, R6, R7, R9 ×2, R11, R12, R12b** plus **M14's precondition unplantable** (the refusal does not exist yet, so its other five assertions could not run — hence 213 counted pre-fix against 218 post-fix); the tenth is `L: live json structurally sound`, whose `d['repo_root'] == '/data/repo'` is true in the real repo and false in a clone — disclosed as an artifact of my cloning rather than counted as a finding. **Guards passed pre-fix and thereby identify themselves**: R1 (healthy tool exits 0), R2 (no refusal on stderr), R3 (all seven labels non-empty), R4 and R10 (both mutant preconditions), R8 (the refusal names only the broken pair — pre-fix stderr is empty, so it passes vacuously, which is what makes it a guard rather than a finding). For `[0.4.61]` the widened section R against the pre-fix tool (old tool md5 `d6b50e6dcf68df6dccb5a46dfe06e5a0`, **final** suite md5 `b71b64db24d64fa65263e3867e45ba97`, log `/tmp/opencode/jsonrefuse/pre-fix.log`; baseline of the committed suite against the committed tool was **218/218** first) → **230 passed / 12 failed**, again **inside a clone** for the same path reason. **Eleven are real**: **R9b, R9c, R9d, R9e, R9f, R9g** (one cause — stdout empty, refusal on stderr), **R13** (`_add_flags` does not exist yet), **R14b, R15b, R16b** (same empty-stdout cause) and **M15's precondition unplantable** (the die()-routing line does not exist, so its five other assertions could not run — hence **242 counted pre-fix against 247 post-fix**). The twelfth is again `L: live json structurally sound` (`repo_root` is the clone, not `/data/repo`) — disclosed as a cloning artifact, not counted. **Guards passed pre-fix and thereby identify themselves**: R1–R8, R10–R12b, the exit-3 half of R9/R14/R15/R16, **R15c** (argparse really accepts `--form`), **R16c/R16d** (the healthy tool already echoed `requested_sha: probe-r9` — the reference both readers must match), R17, R17c, R18, R18b, R19; and **R17b, R18c, R18d are vacuously green** (nothing could print before a scan existed) — disclosed as guards, not findings. Two first-draft defects of mine are recorded in the CHANGELOG: R9c's predicate used `->` outside a string (the *checker* raised SyntaxError — a red meaning the wrong thing), and M15 was first planted without its trigger (mutant exited **0** and was "NOT caught", because nothing refuses when the docstring is healthy). For `[0.4.62]` the new section S against the pre-fix tool (tool md5 `f42b33e34ab28588334b5f616a551798`, **final** suite md5 `4acbd04968016e319778dda544c6596e`, log `/tmp/opencode/usagejson/pre-fix.log`; baseline of the committed suite against the committed tool was **247/247** first) → **268 passed / 16 failed** of 284, captured **in place rather than in a clone** — the tool was still unmodified at its real path, so section L's `repo_root == '/data/repo'` check passed on its own; the clone was only ever needed because a copy *outside* `tools/` changes `default_repo()`. **All sixteen are real**: **S3–S8** (one cause — stdout empty, usage on stderr), **S9b, S9c, S10b, S10c, S11b** (same cause, one per argv form), **S12b, S12c, S12e, S12f** (same cause, via our own `p.error()`), **S16b** (`_add_format_flag` does not exist yet — hence 268 counted pre-fix against 291 post-fix). **Guards passed pre-fix and thereby identify themselves**: **S1** (the human channel was already exactly right — the strongest evidence this was a *channel* defect, not a validation one), S2, S9a, S10a, S11a, S12a, S12d, **S13a–S15b** (no-format-readable argv), **S16** (the `--format` definition was already single), **S17, S18**. Two first-draft defects of mine are recorded in the CHANGELOG: S17b read `$OUT` where `s_run` wrote `$S_OUT` (a **stale** object, so the assertion failed against the *old* tool for an unrelated reason — caught as the 17th red and fixed before the tool was touched, the capture then re-taken honestly at 16), and S16b's predicate `grep -c '_add_format_flag(p)'` also matched the `def` line, reporting `3` for two call sites plus a definition — the third time this suite has been wrong in the *predicate* direction.
**Status**: Green ✅ 2026-09-27 (**348/348**; full regression **52 suites / 4267 assertions / 0 failed / 0 skipped, exit 0** — 29 shell = 2892, 23 PHP = 1375. Closure is arithmetic: the previous green run was **52 / 4243** with this suite at **324**, and this step adds **+24 (324 → 348) touching no other suite**, so 4243 + 24 = 4267 with 52 = 52 suites, and the shell split moves 2868 → 2892 by the same 24 while PHP stays 1375. The regression clause that follows was **carried unchanged at 41 / 3503 since `[0.4.67]`** — the tree had already reached 52 / 4210 by `[0.4.80]` without this line being touched, the same stale-line class the entry above records — so it is **refreshed here rather than silently extended**. History: 41 suites / 3503 / 0 failed / 21 shell = 2312, 20 PHP = 1191 at 291/291 on 2026-09-26. Was 40 / 3396 / 20 shell = 2205 with `[0.4.66]`; **`[0.4.67]` adds `tests/test_queue_source.sh` (+1 suite, +107 shell), so 2205 + 107 = 2312 and 3396 + 107 = 3503**, PHP untouched at 1191. Before that, `[0.4.66]` grew `tests/test_regression_run.sh` (+0 suites, +83 shell: 110 → 193), so 2122 + 83 = 2205 and 3313 + 83 = 3396, and `[0.4.65]` added that suite (+1 suite, +110 shell) — 2012 + 110 = 2122, 3203 + 110 = 3313. This line was itself two runs stale at `[0.4.64]` — `[0.4.63]` added `test_app_contrast.php` (+1, +185) without updating it, so 958 + 185 + 48 = 1191 and 2970 + 185 + 48 = 3203 came out then)
> build · mimo-v2.6-flash-free
[0m← [0mEdit repo/tools/REGISTRY.md
Index: repo/tools/REGISTRY.md
===================================================================
--- repo/tools/REGISTRY.md
+++ repo/tools/REGISTRY.md
@@ -2357,9 +2357,9 @@
- **Section Q — EVERY epilog section derived, not copied** (`[0.4.59]`): Q applies P's two checks to the six remaining docstring/epilog pairs (`languages`, `go compile gate`, `changelog version gate`, `reads GIT BLOBS`, `env`, `examples`). **Q-render** (Q1–Q6) runs `--help` and compares each labelled section to its docstring block **byte for byte**, requiring the docstring side to be non-empty (a heading that no longer exists in the docstring cannot pass by rendering nothing); **Q-source** (Q7–Q12) counts each section's distinctive text in the tool source and requires **exactly one** — the check that sees a copy `--help` never renders. **Q13** requires the hand-written `Usage:` synopsis to be *gone* (needle `[--sha SHA] [--format human|json]`, count 0): argparse generates the synopsis from the argument definitions, and the docstring's copy had already drifted from it (no `-h`, `human|json` vs `{human,json}`), so the fifth pair the queue named was closed by deletion rather than by keeping two things in step. Guards: `--help` exits 0 and its `usage:` line is argparse's own.
- **Section R — the epilog REFUSES to build a label over nothing** (`[0.4.60]`, widened by `[0.4.61]`): derivation made the epilog correct, but `docstring_section` still returned `""` for a heading it could not find and `"\n\n".join` does not complain about `""`, so a renamed or deleted docstring heading produced `env:` printed above a blank line with `--help` exiting **0** — and only Q-render's non-empty requirement stood in the way, i.e. a defect that was *tested* rather than *prevented*, covering only the heading someone named. **R1–R3** are guards on the healthy tool (exit 0, no refusal on stderr, all seven labels rendering a non-empty body); **R4–R9** cover a heading **renamed away** while the tuple still names it (refuse with exit 3; name the pair `'env:' -> 'Environment:'`; nothing on stdout; name **only** the broken pair), and R9 points `GLADEX_REPO_DIR` at the real sandbox repo for the same reason it always did — run from `$SB` the mutant's default repo is not a git repo and it exited 3 for *that* reason, a false pass the red had to be read to catch. **R10–R12b** cover a heading that **exists but whose block is empty** — `docstring_section` stops at the first blank line, so "found" must not mean "fine". **R9's original assertion was written inverted and is corrected in `[0.4.61]`**: it required *no* parseable JSON from the refusing tool — which is exactly the defect (`| jq` meeting empty stdin), so it passed for it. It now asserts the contract, and the block grew accordingly: **R9b** one object on stdout with `ok false`/`exit 3`; **R9c** it names the broken pair; **R9d** it is an ERROR not a verdict (`failures`/`errors` empty, `sha_resolved` null); **R9e** `go_compile`/`changelog_version` null (die()'s shape); **R9f** stderr clean in json mode; **R9g** its **key set is byte-equal to a normal run's** — the shape-level proof that the refusal is the contract and not an exception to it.
- **Section R, argv parity — the refusal's reading of argv must BE argparse's** (`[0.4.61]`): it fires before argparse exists, so it reads argv with a throwaway parser built from the **same `_add_flags`** definitions; each assertion below is the first place a hand-rolled `sys.argv` scan would diverge. **R13** one definition, two call sites (source count); **R14/R14b** the `--format=json` equals form; **R15/R15b** argparse's unique-prefix rule (`--form json`) with **R15c** as the guard that argparse really does accept it; **R16/R16b** `--sha probe-r9` echoed by the refusal with **R16c/R16d** as the parity reference — the *healthy* tool must report the same `requested_sha`, one expectation read by two code paths; **R17/R17b/R17c** `--` termination (the scan stops there and emits no JSON, while argparse itself rejects the same argv with exit 2); **R18/R18b/R18c/R18d** an argv argparse rejects (refusal still fires, still names the pair, no `usage:` noise leaked, stdout still empty in human mode) with **R19** as the guard that argparse keeps ownership of validation (invalid choice alone → exit 2). **R17b, R18c and R18d are vacuously green before the fix** — with no scan in existence nothing could print or leak — and they only begin testing something once it exists; disclosed as guards, not findings. **Guards that passed against the pre-fix tool and thereby identify themselves**: R1–R8, R10–R12b, the exit-3 half of R9/R14/R15/R16, R15c, R16c/R16d, R17, R17c, R18, R18b, R19.
- **Section S — a usage error under `--format json` is still ONE JSON object** (`[0.4.62]`): `repo-lint --format json --timeout abc` used to exit 2 with usage prose on stderr and an **empty stdout**, so a `| jq` consumer got jq's own parse error and could not tell a mistyped flag from a crash — the last path with no object after `[0.4.61]`, and reachable on a perfectly healthy tool. **S1 is the human guard** (usage on stderr, empty stdout, exit 2 — passes before *and* after, which is what makes it a guard rather than a finding, and what M16 leaves green while S3 goes red); **S2–S8** the defect itself (exit 2 preserved; stdout non-empty; one object with `ok false`/`exit_code 2`; `error` names the bad argument; **key set byte-equal to a normal run's** — the shape-level proof that the usage object *is* the contract; not a verdict — `failures[]`/`errors[]` empty, `sha_resolved` null; stderr clean); **S9–S11** argv forms a hand-rolled scan gets wrong — the failing token **before** `--format` (a full pre-parse aborts first and would answer `human`), `--format=json`, `--form json`; **S12** the tool's own `p.error()` checks take the same route as argparse's rejections (both are inside one `try`); **S13–S15** the three argv shapes where **no** format can be read (`--format yaml`, a bare `--format`, anything after `--`) → human, asserted not assumed; **S16/S16b** exactly one `add_argument("--format", …)` and two readers of it (`_add_format_flag` feeds `_add_flags` and `_format_of` — splitting the flag out must not become a second choices list); **S17/S18** guards that a healthy json run still exits 0 and `--help` still exits 0. The section captures **stdout and stderr separately** throughout (`run_tool` merges them) because *which stream* is half of what it asserts, which is why it also needed `assert_empty`/`assert_nonempty`: `assert_not_contains` takes its needle as argument 2, so an empty needle matches every haystack and "this stream is empty" could not be expressed without failing by construction.
-- **Mutation**: 23, each precondition-asserted to occur exactly once, caught by a divergence assertion, and surgically checked — M1 exit gate defeated (`(1 if failures else 0)` → 0); M2 `--sha` ignored (always lints HEAD); M3 `.php` dropped from `EXT_LANG` (mutant still catches broken sh); **M4** `failures.extend(gentries)` → `extend([])` (the 395b9b5 defect returns: a build-breaking commit reports 0; mutant still 0 on a compiling commit); **M5** `3 if errors` → `1 if errors` (an environment failure reads as "broken file": real=3/mutant=1; mutant still 1 on broken php); **M6** the gate's blob read → `open(<worktree path>)` (the 219fd8f class applied to Go: a fixed worktree hides a broken commit; mutant still 1 when the worktree is broken too); **M7** `failures.extend(cl_failures)` → `extend([])` (the hand-off dies while the JSON still names the twin — `ok false`, `duplicates == ['1.0.0']`, `exit_code 0`; mutant still exits 1 on broken php); **M8** `if ver in first_seen:` → `if False:` (the test itself dies: `duplicates == []` and `ok true` where the real tool reports a twin; mutant still green on a clean changelog); **M9** the changelog blob read pinned to `HEAD` instead of `--sha` while the existence probe still uses `--sha` (an ancestor's twin vanishes — real=1/mutant=0; mutant still 0 on a clean HEAD); **M10** the CHANGELOG rule dropped from the tool's one contract (the `[0.4.56]` defect itself planted) — caught by P2/P5 while **P1 and P4 stay green**: the docstring and `--help` still agree because they are one copy, so they lost the rule *together*; surgical checks are the agreement holding, the parse rule surviving, and `--help` still exiting 0; **M11** a second copy of the contract planted as a source comment `--help` never renders — caught by **P1 alone**, with P4 deliberately asserted **green** (what `--help` prints is still byte-identical to the docstring), proving the source-level count is not redundant with the render-level check; **M12** the same shape for a *derived* section (a source-comment second copy of the go-gate text) — caught by **Q-source**, with **Q-render asserted green** on the mutant (`--help` still equals the docstring, so the byte comparison provably cannot see it) and `--help` still exiting 0; **M13** the inverse — `("env:", "Environment:")` repointed to the languages heading, so `env:` renders a different docstring block — caught by **Q-render**, with **Q-source asserted green** (the Environment text still occurs exactly once, so the count cannot see a misattribution) and the `exit codes:` pair still agreeing (one pair misattributed, not the whole epilog). M12/M13 are complementary by construction, exactly as M10/M11 are: each one's green assertions are what prove the other's necessity; **M14** the pre-`[0.4.60]` state reproduced — R's trigger (the docstring heading renamed to `Environment (renamed):` while the tuple still says `Environment:`) **in the same copy as** the refusal's condition defeated (`if missing:` → `if False:`). Two edits deliberately: defeating the guard **alone** changes nothing, because a healthy docstring still yields seven full sections — I built it that way first and the mutant came out **green**, which is the finding rather than a flaw in the mutation: the guard is not the defect, it is what makes an always-available trigger loud. With both halves present `--help` exits 0 over a label printed on nothing, stderr silent — caught by R's refusal assertions and by `r_labels` (R3's own check, run against the mutant) going red at **exactly** `env:` — while an unrelated section still byte-equals its docstring (surgical: one condition defeated, not the derivation); **M15** the machine channel dropped (`[0.4.61]`): R's trigger **in the same copy as** the fix reverted (`raise SystemExit(die(None, default_repo(), message, sha, fmt))` → the bare `sys.stderr.write(message)` + `SystemExit(EXIT_CANNOT)`), i.e. the refusal output as it stood before this step. Two edits for the same reason M14 needs two — with a healthy docstring nothing refuses, so the dropped channel is unobservable (I planted the revert alone first and the mutant came out green, **exit 0**: the second time this mutation taught its own lesson) — and the catch is the point: **every human assertion stays GREEN** (exit still 3, pair still named, `--help` still refusing with an empty stdout) while **R9b** sees the empty stdout. The old suite asserted the *absence* of JSON, so the defect passed it. **M16** the usage-error channel dropped (`[0.4.62]`): `if fmt == "json":` → `if False:` in `_Parser.error`, i.e. the pre-step state exactly — argparse always prints usage to stderr and exits 2, so `--format json --timeout abc` gives a jq pipeline empty stdin again. **One edit where M14 and M15 each needed two, and the difference is the finding**: those needed a *trigger* because a healthy docstring never refuses, whereas here the argv that says json is supplied **by the test**, so the trigger and the defect are the same line. Caught by **S3** (stdout empty again) with **every human assertion staying GREEN** — exit still 2, usage still on stderr, `--help` still 0, the healthy json run still 0 — because the human path never had the check; that asymmetry is the argument for having written S1/S13/S14/S15 as guards. **M17–M19 (the citation rule, `[0.4.82]`)** — three ways to lint green over a version nobody wrote, each with a surgical value that says *which* one: **M17** the existence test → `if False` → the token is still **counted and classified in series** but never judged (`seen ≥ 3, in_series ≥ 3, missing [], exit 0`), caught `real=1 mutant=0`; **M18** the **series fence** dropped (`in_series = list(citations)`) → the one excluded token becomes the defect (`in_series 4`, `missing ['9.9.4']`), caught `real=0 mutant=1`, i.e. red on a fixture the real rule calls clean — and its replace runs through python with `t.count(old) == 1` asserted **inside** the script, because a sed pattern of brackets and quotes that matches the wrong line edits a path no fixture exercises and comes back green; **M19** the **collection** dropped (`citations.extend([])`) → `citations_seen == 0`, nothing was scanned at all, caught `real=1 mutant=0`. M17 vs M19 is the pair that matters: both exit 0 over the defect, and only `citations_seen` (counted-but-unjudged vs never-scanned) tells them apart. Every mutant file is `[ -f ]`-checked before it is run, so a build that produced nothing cannot be reported as a catch. **M20/M21 (`[0.4.83]`, the closing line)** — the two halves of one judgement call, both planted in `_result_line`'s syntax-set test by exact-string replace with `t.count(old) == 1` asserted inside the script: **M20** `if all(…)` → `if True:` (every failure called a parse/compile failure — the pre-step constant with the count still derived) is caught by **U1** while the exit code stays **1 on both sides**, and its surgical check is a *real* syntax failure where mutant and tool say exactly the same sentence; **M21** `if all(…)` → `if False:` (a rule failure never reported as a rule) is caught by **U2** with a *syntax* fixture, and its surgical check is a rule fixture where the inverted mutant is **indistinguishable** from the real tool — which is precisely why only a wording pin on the other branch can catch it. Neither mutant changes any verdict, so no exit-code assertion sees either: the section U pins are the only thing that does. **M22 (`[0.4.84]`, the count)** — the pre-step defect planted in the one expression that decides the number: `n_files = len({f.get("path") for f in failures})` → `n_files = len(failures)`, planted by the same exact-string replace with `t.count(old) == 1` asserted inside the script. Exit code, `kinds` and `failures[]` all stay put, so **every verdict assertion in the suite is green over it**; caught by **V1** with `real_rc == mut_rc == 1` and only the digits telling them apart (`real: 1 file(s)`, `mutant: 2 file(s)`), and its surgical check is V3's fixture — one failure per file, where failures and files are equal and the mutant is **indistinguishable** from the real tool, which is precisely why V1's fixture has to separate them.
+- **Mutation**: 23, each precondition-asserted to occur exactly once, caught by a divergence assertion, and surgically checked — M1 exit gate defeated (`(1 if failures else 0)` → 0); M2 `--sha` ignored (always lints HEAD); M3 `.php` dropped from `EXT_LANG` (mutant still catches broken sh); **M4** `failures.extend(gentries)` → `extend([])` (the 395b9b5 defect returns: a build-breaking commit reports 0; mutant still 0 on a compiling commit); **M5** `3 if errors` → `1 if errors` (an environment failure reads as "broken file": real=3/mutant=1; mutant still 1 on broken php); **M6** the gate's blob read → `open(<worktree path>)` (the 219fd8f class applied to Go: a fixed worktree hides a broken commit; mutant still 1 when the worktree is broken too); **M7** `failures.extend(cl_failures)` → `extend([])` (the hand-off dies while the JSON still names the twin — `ok false`, `duplicates == ['1.0.0']`, `exit_code 0`; mutant still exits 1 on broken php); **M8** `if ver in first_seen:` → `if False:` (the test itself dies: `duplicates == []` and `ok true` where the real tool reports a twin; mutant still green on a clean changelog); **M9** the changelog blob read pinned to `HEAD` instead of `--sha` while the existence probe still uses `--sha` (an ancestor's twin vanishes — real=1/mutant=0; mutant still 0 on a clean HEAD); **M10** the CHANGELOG rule dropped from the tool's one contract (the `[0.4.56]` defect itself planted) — caught by P2/P5 while **P1 and P4 stay green**: the docstring and `--help` still agree because they are one copy, so they lost the rule *together*; surgical checks are the agreement holding, the parse rule surviving, and `--help` still exiting 0; **M11** a second copy of the contract planted as a source comment `--help` never renders — caught by **P1 alone**, with P4 deliberately asserted **green** (what `--help` prints is still byte-identical to the docstring), proving the source-level count is not redundant with the render-level check; **M12** the same shape for a *derived* section (a source-comment second copy of the go-gate text) — caught by **Q-source**, with **Q-render asserted green** on the mutant (`--help` still equals the docstring, so the byte comparison provably cannot see it) and `--help` still exiting 0; **M13** the inverse — `("env:", "Environment:")` repointed to the languages heading, so `env:` renders a different docstring block — caught by **Q-render**, with **Q-source asserted green** (the Environment text still occurs exactly once, so the count cannot see a misattribution) and the `exit codes:` pair still agreeing (one pair misattributed, not the whole epilog). M12/M13 are complementary by construction, exactly as M10/M11 are: each one's green assertions are what prove the other's necessity; **M14** the pre-`[0.4.60]` state reproduced — R's trigger (the docstring heading renamed to `Environment (renamed):` while the tuple still says `Environment:`) **in the same copy as** the refusal's condition defeated (`if missing:` → `if False:`). Two edits deliberately: defeating the guard **alone** changes nothing, because a healthy docstring still yields seven full sections — I built it that way first and the mutant came out **green**, which is the finding rather than a flaw in the mutation: the guard is not the defect, it is what makes an always-available trigger loud. With both halves present `--help` exits 0 over a label printed on nothing, stderr silent — caught by R's refusal assertions and by `r_labels` (R3's own check, run against the mutant) going red at **exactly** `env:` — while an unrelated section still byte-equals its docstring (surgical: one condition defeated, not the derivation); **M15** the machine channel dropped (`[0.4.61]`): R's trigger **in the same copy as** the fix reverted (`raise SystemExit(die(None, default_repo(), message, sha, fmt))` → the bare `sys.stderr.write(message)` + `SystemExit(EXIT_CANNOT)`), i.e. the refusal output as it stood before this step. Two edits for the same reason M14 needs two — with a healthy docstring nothing refuses, so the dropped channel is unobservable (I planted the revert alone first and the mutant came out green, **exit 0**: the second time this mutation taught its own lesson) — and the catch is the point: **every human assertion stays GREEN** (exit still 3, pair still named, `--help` still refusing with an empty stdout) while **R9b** sees the empty stdout. The old suite asserted the *absence* of JSON, so the defect passed it. **M16** the usage-error channel dropped (`[0.4.62]`): `if fmt == "json":` → `if False:` in `_Parser.error`, i.e. the pre-step state exactly — argparse always prints usage to stderr and exits 2, so `--format json --timeout abc` gives a jq pipeline empty stdin again. **One edit where M14 and M15 each needed two, and the difference is the finding**: those needed a *trigger* because a healthy docstring never refuses, whereas here the argv that says json is supplied **by the test**, so the trigger and the defect are the same line. Caught by **S3** (stdout empty again) with **every human assertion staying GREEN** — exit still 2, usage still on stderr, `--help` still 0, the healthy json run still 0 — because the human path never had the check; that asymmetry is the argument for having written S1/S13/S14/S15 as guards. **M17–M19 (the citation rule, `[0.4.82]`)** — three ways to lint green over a version nobody wrote, each with a surgical value that says *which* one: **M17** the existence test → `if False` → the token is still **counted and classified in series** but never judged (`seen ≥ 3, in_series ≥ 3, missing [], exit 0`), caught `real=1 mutant=0`; **M18** the **series fence** dropped (`in_series = list(citations)`) → the one excluded token becomes the defect (`in_series 4`, `missing ['9.9.4']`), caught `real=0 mutant=1`, i.e. red on a fixture the real rule calls clean — and its replace runs through python with `t.count(old) == 1` asserted **inside** the script, because a sed pattern of brackets and quotes that matches the wrong line edits a path no fixture exercises and comes back green; **M19** the **collection** dropped (`citations.extend([])`) → `citations_seen == 0`, nothing was scanned at all, caught `real=1 mutant=0`. M17 vs M19 is the pair that matters: both exit 0 over the defect, and only `citations_seen` (counted-but-unjudged vs never-scanned) tells them apart. Every mutant file is `[ -f ]`-checked before it is run, so a build that produced nothing cannot be reported as a catch. **M20/M21 (`[0.4.83]`, the closing line)** — the two halves of one judgement call, both planted in `_result_line`'s syntax-set test by exact-string replace with `t.count(old) == 1` asserted inside the script: **M20** `if all(…)` → `if True:` (every failure called a parse/compile failure — the pre-step constant with the count still derived) is caught by **U1** while the exit code stays **1 on both sides**, and its surgical check is a *real* syntax failure where mutant and tool say exactly the same sentence; **M21** `if all(…)` → `if False:` (a rule failure never reported as a rule) is caught by **U2** with a *syntax* fixture, and its surgical check is a rule fixture where the inverted mutant is **indistinguishable** from the real tool — which is precisely why only a wording pin on the other branch can catch it. Neither mutant changes any verdict, so no exit-code assertion sees either: the section U pins are the only thing that does. **M22 (`[0.4.84]`, the count)** — the pre-step defect planted in the one expression that decides the number: `n_files = len({f.get("path") for f in failures})` → `n_files = len(failures)`, planted by the same exact-string replace with `t.count(old) == 1` asserted inside the script. Exit code, `kinds` and `failures[]` all stay put, so **every verdict assertion in the suite is green over it**; caught by **V1** with `real_rc == mut_rc == 1` and only the digits telling them apart (`real: 1 file(s)`, `mutant: 2 file(s)`), and its surgical check is V3's fixture — one failure per file, where failures and files are equal and the mutant is **indistinguishable** from the real tool, which is precisely why V1's fixture has to separate them. **M23 (`[0.4.85]`, the coverage)** — an `EXT_LANG` entry nothing classifies (`".ts": "typescript"` planted by exact-string replace with `t.count(old) == 1` asserted inside the script). Nothing RUNS this copy, deliberately: a bare new extension lang dies in `lint()` at `cmd = {...}[lang]` with an **uncaught KeyError** (measured 2026-09-27 in a throwaway repo — traceback, exit 1, no result line; that is a separate defect class, queued as (33)), so the defect cannot be caught through an exit code at all. The catch is therefore the **analyser diverging between two sources** — the same `u7_classify` reports `dispatch_unclassified=NONE` on the tool and `dispatch_unclassified=typescript` on the mutant — which is exactly U7's shape: it reads a file, so the mutant hands it a different file. Its surgical check is that `gate=changelog,go-compile`, `rules_match=YES` and the whole `syntax=` set are byte-identical between the two sources with `emittable_unclassified=typescript` naming **one** lang, i.e. one missing classification rather than a wrecked read.
- Live: HEAD → exit 0 (176 files — **174 → 176 with `[0.4.65]`**, its own `tools/regression-run` + `tests/test_regression_run.sh` going from untracked to tracked (`linted.bash` 24 → 25, `linted.python` 11 → 12), following **173 → 174 with `[0.4.64]`**; the pre-commit run reads **174** with `bash 24` / `python 11` because those blobs are not there yet — the stale-live-number class, re-read after the commit below — 45 module files compile clean in ~1.6s. **`[0.4.66]` pre-commit read: exit 0, `files_total 176`, `linted {bash 25, go 43, json 11, php 32, python 12}`, `changelog_version entries 70, unique 70, duplicates []`** — both changed files were already tracked, so the post-commit prediction is **176 unchanged** with `entries 71` once `[0.4.66]` lands, re-read after the commit rather than carried. **`[0.4.67]` pre-commit read: exit 0, `files_total 176`, `linted {bash 25, go 43, json 11, php 32, python 12}`, `changelog_version entries 71, unique 71, duplicates []`** — this entry adds two **untracked** files (`tools/queue-source-check`, extensionless `python3` shebang → `linted.python`; `tests/test_queue_source.sh`, `.sh` → `linted.bash`) plus its own heading, so the post-commit prediction is **178** with `bash 26`, `python 13` and `entries 72`, re-read after the commit rather than carried) with `changelog_version` = `attempted true, entries 70, unique 70, unparseable 0, duplicates [], ok true` (**69 → 70 with `[0.4.65]`**, following **68 → 69 with `[0.4.64]`**: the count is read from the COMMITTED blob, so it is re-read after the append commits rather than carried over — it read 68 while `[0.4.64]` was still uncommitted, which is the whole point of re-reading; the working-tree count was verified the anchored way, `grep -c '^## \['` → 69 with `uniq -d` empty, because the greedy `sed 's/.*\[\([^]]*\)\].*/\1/'` form reports **5 phantom duplicates** on this tree — 0.4.31/0.4.40/0.4.44/0.4.49/0.4.62 — by taking the last bracket in a heading that cites other versions. The **file** count is 173, not the 171 drafted mid-run: `[0.4.63]`'s own two mailbox files were untracked when that number was written and tracked once it committed, so 171 → 173 is this entry's own movement rather than a count carried); `--sha 219fd8f` → exit 1 naming `tests/test_mailbox_a11y.php:208 [php]`; `--sha 395b9b5` → exit 1 naming `.../status_test.go:5 [go-compile]`; unknown rev / non-repo → exit 3; `--sha probe-r9` → exit 3 with `requested_sha: probe-r9` (the R16 parity reference, live); `--format yaml` → exit 2 with **usage on stderr and an empty stdout** (no format could be read, so none is invented — `[0.4.62]`); **`--format json` + a bad argv → exit 2 with a 384-byte 15-key object on stdout and 0 bytes on stderr** (`--timeout abc`, `--nonsense`, `--timeout 0`, empty `--sha`, and the failing token placed *before* `--format`), while the same argv in human mode still gives argparse's `usage:`+`error:` with **stdout 0 bytes**; `--help` (**106 lines**, was 57 before the epilog stopped carrying its own prose, 102 before the exit-3 clause widened, 103 through `[0.4.61]`, **+3 for `[0.4.62]`'s widened exit-2 clause**) renders all seven docstring blocks verbatim under their labels; a copy with a heading renamed → `repo-lint: ERROR refusing to run - docstring section missing or empty …` + ` 'env:' -> 'Environment:'` → **exit 3**, stderr only, and under `--format json` the **same refusal as an object** — `ok false`, `exit_code 3`, `error` naming the pair, **stderr 0 bytes** — which is the `| jq` consumer `[0.4.60]`'s queue described, now parsing (`--format=json` → 3; `--form json` → 3; `-- --format json` → no JSON on stdout; `--format yaml` on the broken copy → refusal only, no `usage:` leak) — **and on that same broken copy `--format json --timeout abc` now yields the 458-byte refusal object with `exit_code 3` instead of falling back to `human`**, which is `[0.4.61]`'s own queue item struck as actioned. **`[0.4.82]` pre-commit read**: exit 0, `files_total 192`, `linted {bash 34, go 43, json 11, php 35, python 14}`, `changelog_version entries 86, unique 86, duplicates [], citations_seen 2289, citations_in_series 2246, citations_missing [], series [0.1, 0.2, 0.3, 0.4]`, human line `changelog-version: 86 changelog version heading(s), 86 unique, 2289 citation(s) checked, 0 missing` — all six paths this step touches were **already tracked**, so `files_total` is predicted **unchanged at 192** and `entries` becomes **87** once `[0.4.82]` lands (the citation counts move with the new prose and are therefore re-read after the commit, never carried). **Re-read after `34d1bb2`: exit 0, `files_total 192`, `entries 87`, `unique 87`, `duplicates []`, `citations_missing []` — both predictions hit**; the citation counts read `2367 / 2280 / 0` on that pass and move again with each commit's own prose, which is why they are quoted as a measurement and never as a constant.
- Pre-fix replay: the **then-`HEAD` suite against the then-`HEAD` tool** → **88 passed / 28 failed** (including `L: 395b9b5 … (want rc=1 got=0)`) for the Go gate of `[0.4.3x]`; for the changelog gate the *new* suite against the pre-fix tool (md5 `3a4e09176e24ca3414366952467d4944`, log `/tmp/opencode/changelog-gate/pre-fix.log`, suite md5 `9e352394d02096183adef92d55fc5a73`) → **125 passed / 22 failed**: the exact key-set pin plus every O1–O7 finding red, and M7/M8/M9 unplantable (0 matching lines) — while the six guard-style assertions inside O (absent file adds no failure; fixed commit → 0) already passed, which is what identifies them as guards rather than findings. For `[0.4.56]` the new section P against the pre-fix tool (tool md5 `3ebcf0b4ae7e290796fbed12c57e422b`, suite md5 `a50e16d7a5643bdfd18b667752e50d2c`, log `/tmp/opencode/exitcodes/pre-fix.log`) → **166 passed / 6 failed**: P1 (the contract text occurs **twice**), P2 ×2 (Go rule and CHANGELOG rule both absent from the docstring), P4 (the docstring block and `--help`'s section differ), M10's agreement surgical check (pre-fix both copies still exist, so the mutant's docstring and `--help` disagree), and M11's precondition (already 2 occurrences → unplantable, so its other three assertions could not run pre-fix — hence 172 counted pre-fix against 175 post-fix). Guards that passed pre-fix and thereby identify themselves: P2's parse rule, P3 (all four codes), P4's `--help exits 0`, and all three P5 rules — the epilog was the copy that was right. Baseline re-verified on a checkout of the same commit before the fix: **155/156 then 156/156 twice**, the single red being `L: real repo status changed during a run` (a concurrent identity committed mid-run), not this change. For `[0.4.59]` the new section Q against the pre-fix tool (tool md5 `f17563d67064a79f313ef2bab376cd66`, suite md5 `9217e2653fbed256afb704d0a01fd359`, log `/tmp/opencode/epilogderive/pre-fix.log`; baseline of the *old* suite against the old tool was **175/0** first) → **186 passed / 9 failed**: the seven findings are Q1–Q6 (every pair renders different bytes) and Q13 (the drifted synopsis still present), plus **M12's surgical render check** — which fails pre-fix only because the two renderings differ by definition, i.e. it restates Q2 — and **M13's precondition unplantable** (the derivation tuple does not exist yet, so its other three assertions could not run: hence 186 counted pre-fix against 198 post-fix). **Guards passed pre-fix and thereby identify themselves**: all six Q-source counts (each section's text already occurred exactly once — the copies differed, they were not duplicated line-for-line), `--help exits 0`, the generated-usage line, and M12's precondition plus its "caught" assertion. For `[0.4.60]` the new section R against the pre-fix tool (old tool md5 `4e6c58ffc86441a5745054a4ea45d084`, final suite md5 `e126f791dbcd4b1d9ae0bd0626022d82`, log `/tmp/opencode/epilogrefuse/pre-fix.log`; baseline of the old suite against the old tool was **198/0** first) → **203 passed / 10 failed**, captured **inside a clone of the repo** rather than from `/tmp`: pointing `REPO_LINT_BIN` at a copy outside `tools/` makes section L's live checks fail for *path* reasons, because `default_repo()` resolves relative to the script, so the tool reported `repo_root: /tmp/...` and exited 3 — a harness artifact that cost a second capture to get a red meaning what it says. **Nine of the ten are real**: **R5, R6, R7, R9 ×2, R11, R12, R12b** plus **M14's precondition unplantable** (the refusal does not exist yet, so its other five assertions could not run — hence 213 counted pre-fix against 218 post-fix); the tenth is `L: live json structurally sound`, whose `d['repo_root'] == '/data/repo'` is true in the real repo and false in a clone — disclosed as an artifact of my cloning rather than counted as a finding. **Guards passed pre-fix and thereby identify themselves**: R1 (healthy tool exits 0), R2 (no refusal on stderr), R3 (all seven labels non-empty), R4 and R10 (both mutant preconditions), R8 (the refusal names only the broken pair — pre-fix stderr is empty, so it passes vacuously, which is what makes it a guard rather than a finding). For `[0.4.61]` the widened section R against the pre-fix tool (old tool md5 `d6b50e6dcf68df6dccb5a46dfe06e5a0`, **final** suite md5 `b71b64db24d64fa65263e3867e45ba97`, log `/tmp/opencode/jsonrefuse/pre-fix.log`; baseline of the committed suite against the committed tool was **218/218** first) → **230 passed / 12 failed**, again **inside a clone** for the same path reason. **Eleven are real**: **R9b, R9c, R9d, R9e, R9f, R9g** (one cause — stdout empty, refusal on stderr), **R13** (`_add_flags` does not exist yet), **R14b, R15b, R16b** (same empty-stdout cause) and **M15's precondition unplantable** (the die()-routing line does not exist, so its five other assertions could not run — hence **242 counted pre-fix against 247 post-fix**). The twelfth is again `L: live json structurally sound` (`repo_root` is the clone, not `/data/repo`) — disclosed as a cloning artifact, not counted. **Guards passed pre-fix and thereby identify themselves**: R1–R8, R10–R12b, the exit-3 half of R9/R14/R15/R16, **R15c** (argparse really accepts `--form`), **R16c/R16d** (the healthy tool already echoed `requested_sha: probe-r9` — the reference both readers must match), R17, R17c, R18, R18b, R19; and **R17b, R18c, R18d are vacuously green** (nothing could print before a scan existed) — disclosed as guards, not findings. Two first-draft defects of mine are recorded in the CHANGELOG: R9c's predicate used `->` outside a string (the *checker* raised SyntaxError — a red meaning the wrong thing), and M15 was first planted without its trigger (mutant exited **0** and was "NOT caught", because nothing refuses when the docstring is healthy). For `[0.4.62]` the new section S against the pre-fix tool (tool md5 `f42b33e34ab28588334b5f616a551798`, **final** suite md5 `4acbd04968016e319778dda544c6596e`, log `/tmp/opencode/usagejson/pre-fix.log`; baseline of the committed suite against the committed tool was **247/247** first) → **268 passed / 16 failed** of 284, captured **in place rather than in a clone** — the tool was still unmodified at its real path, so section L's `repo_root == '/data/repo'` check passed on its own; the clone was only ever needed because a copy *outside* `tools/` changes `default_repo()`. **All sixteen are real**: **S3–S8** (one cause — stdout empty, usage on stderr), **S9b, S9c, S10b, S10c, S11b** (same cause, one per argv form), **S12b, S12c, S12e, S12f** (same cause, via our own `p.error()`), **S16b** (`_add_format_flag` does not exist yet — hence 268 counted pre-fix against 291 post-fix). **Guards passed pre-fix and thereby identify themselves**: **S1** (the human channel was already exactly right — the strongest evidence this was a *channel* defect, not a validation one), S2, S9a, S10a, S11a, S12a, S12d, **S13a–S15b** (no-format-readable argv), **S16** (the `--format` definition was already single), **S17, S18**. Two first-draft defects of mine are recorded in the CHANGELOG: S17b read `$OUT` where `s_run` wrote `$S_OUT` (a **stale** object, so the assertion failed against the *old* tool for an unrelated reason — caught as the 17th red and fixed before the tool was touched, the capture then re-taken honestly at 16), and S16b's predicate `grep -c '_add_format_flag(p)'` also matched the `def` line, reporting `3` for two call sites plus a definition — the third time this suite has been wrong in the *predicate* direction.
**Status**: Green ✅ 2026-09-27 (**348/348**; full regression **52 suites / 4267 assertions / 0 failed / 0 skipped, exit 0** — 29 shell = 2892, 23 PHP = 1375. Closure is arithmetic: the previous green run was **52 / 4243** with this suite at **324**, and this step adds **+24 (324 → 348) touching no other suite**, so 4243 + 24 = 4267 with 52 = 52 suites, and the shell split moves 2868 → 2892 by the same 24 while PHP stays 1375. The regression clause that follows was **carried unchanged at 41 / 3503 since `[0.4.67]`** — the tree had already reached 52 / 4210 by `[0.4.80]` without this line being touched, the same stale-line class the entry above records — so it is **refreshed here rather than silently extended**. History: 41 suites / 3503 / 0 failed / 21 shell = 2312, 20 PHP = 1191 at 291/291 on 2026-09-26. Was 40 / 3396 / 20 shell = 2205 with `[0.4.66]`; **`[0.4.67]` adds `tests/test_queue_source.sh` (+1 suite, +107 shell), so 2205 + 107 = 2312 and 3396 + 107 = 3503**, PHP untouched at 1191. Before that, `[0.4.66]` grew `tests/test_regression_run.sh` (+0 suites, +83 shell: 110 → 193), so 2122 + 83 = 2205 and 3313 + 83 = 3396, and `[0.4.65]` added that suite (+1 suite, +110 shell) — 2012 + 110 = 2122, 3203 + 110 = 3313. This line was itself two runs stale at `[0.4.64]` — `[0.4.63]` added `test_app_contrast.php` (+1, +185) without updating it, so 958 + 185 + 48 = 1191 and 2970 + 185 + 48 = 3203 came out then)
> build · mimo-v2.6-flash-free
[0m← [0mEdit repo/tools/REGISTRY.md
Index: repo/tools/REGISTRY.md
===================================================================
--- repo/tools/REGISTRY.md
+++ repo/tools/REGISTRY.md
@@ -2350,8 +2350,9 @@
- **Section T — the citation rule** (`[0.4.82]`, queue item (26); 24 assertions): a citation of an **existing** heading → exit 0 with `citations_seen`/`citations_in_series` counted, `citations_missing == []`, `series == ['7.1']`; **the defect** → exit 1 with `FAIL PLAN.md:2 [changelog]`, the message `cites [7.1.5] but CHANGELOG.md has no such heading`, `citations_missing == [{'path','line','version'}]`, `lang: changelog` (so `promote`'s `_lint_failure_verdict` keeps rendering it as *a rule, not a parse*), `ok`/`exit_code` flipped, and a human summary ending `citation(s) checked, 1 missing`; **blob basis** (claim committed, worktree fixed → still 1; after the fix commit → 0); **the fence** → a `[9.9.4]` token is *counted* (`seen 4`) but *not judged* (`in_series 3`, `missing []`, exit 0) with the human line `… 4 citation(s) checked, 0 missing`; **no `CHANGELOG.md`** → `seen 2, in_series 0, missing [], series []`, exit 0, no failure and no error (tokens read, nothing judged); **the contract** → the rule appears in the docstring block *and* in what `--help` renders (derived, byte-for-byte) together with the `SCOPE` sentence; **cleanup** → the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason. Fixtures use series **`7.1`** and write the missing token into a *fixture file*, never into this suite — a literal in-series version committed here would be a citation in the REAL tree and the rule would fail the repo that hosts its own test (that constraint is documented in the tool's `SCOPE` paragraph too).
- **Section U — the human closing line** (`[0.4.83]`, queue item (29); 20 assertions): **U1** a missing citation → exit 1 with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `fail to parse` anywhere in the output, `json_exit_code` mirroring the process and the failure's `lang` shown to be the field the line is derived from; **U2** a broken PHP file → `result: 1 file(s) fail to parse or compile (exit 1)` with **no** `fail lint (`, i.e. the specific diagnosis does not regress to vagueness; **U3** both at once → `result: 2 file(s) fail lint (changelog, php) (exit 1)` (sorted, de-duplicated, both kinds named); **U4** `_SYNTAX_LANGS` in `tools/repo-lint` and in `tools/promote-dev-to-prod` are **the same set**, extracted by regex from both files rather than imported (a child must not import its parent, and prose agreement is what drifted in `[0.4.53]`); **U5** the function is defined exactly once and `main()` prints it exactly once (no hand-rolled second literal — P/Q's shape applied to a runtime line); **U6** the section leaves the sandbox green so a later mutant's clean-run assertion cannot fail for its own reason; **U7** (`[0.4.85]`, queue item (31)) — U4 compares two *declarations* to each other and never asks whether either covers what the tool **emits**, so `u7_classify <path>` derives four sets from that file's own source (the `EXT_LANG` and `SHEBANG_LANG` dict values, the `_SYNTAX_LANGS` frozenset, every literal `"lang": "…"` the gates hand to `failures[]`) and asserts three things: **U7-1** it read four non-empty sets (an extraction that reads nothing would pass every subtraction below vacuously — the same "cannot verify is not a pass" discipline the tool itself has), **U7-2** every dispatch lang is classified as syntax, **U7-3** every emittable lang is syntax **or one of a DECLARED rule set** (`RULE_LANGS = {"changelog"}` — declared rather than derived as `gate − syntax`, which would absorb a new rule automatically and make the check tautological), **U7-4** `rules_match=YES`, that declaration compared back against the gate in **both** directions so it may not drift either. The same function runs against `$TOOL` and, in M23, against a copy carrying one extra `EXT_LANG` entry.
- **Section V — the NUMBER in the closing line counts files** (`[0.4.84]`, queue item (30); 14 assertions): U's two branches are both **one-failure** fixtures, so every assertion in U is satisfied by a counter that never counted files at all — V supplies the case where the two counts disagree. **V1** three `## [7.1.1]` headings → **two `FAIL CHANGELOG.md:` lines** with `result: 1 file(s) fail lint (changelog) (exit 1)` and **no** `result: 2 file(s)` anywhere (the defect, reproduced in the harness rather than quoted from a run); **V2** the same run in JSON, `len(failures) == 2` and `len({f['path'] …}) == 1`, both paths `CHANGELOG.md` — the two figures the sentence must *choose* between, asserted to differ so the fix cannot be "right" by coincidence; **V3** the opposite direction, two distinct broken PHP files → still `result: 2 file(s) fail to parse or compile (exit 1)`, so a fix that collapsed the number to 1 is caught too; **V4** the source shape, three counts (the derivation occurs once, both branch strings are fed `{n_files}`, `{len(failures)} file(s) fail` occurs zero times) — a later edit cannot silently hand the label a failure count again; **V5** the sandbox left green. `kinds` is deliberately **not** de-duplicated per file: one file tripping two rules must still be told both, so the noun decides the number while the list stays per failure.
- **Pre-fix replay for `[0.4.84]`**: the new suite against `HEAD`'s tool blob swapped **in place** (old md5 `16d7a0cc073ab416ff0d685ae666c481` → new `0df9317ebe19afafeafb4766e3f8c405`, restored and re-verified byte-identical; log `/tmp/opencode/pre-fix-replay-84.log`) → **357 passed / 6 failed**, every red a section-V finding or an unplantable precondition: **V1 ×2** (the `result: 1 file(s)` pin and its `result: 2 file(s)` twin), **V4 ×3** (the distinct-path derivation absent, both `{n_files}` branch strings absent, `{len(failures)} file(s) fail` present twice), **M22's precondition** (the needle does not exist — its other three assertions could not run, hence **357 counted pre-fix against 366 post-fix**: 366 − 6 − 3). Guards that passed pre-fix and thereby identify themselves: **V1's exit code and FAIL-line count**, **V2** (the JSON figures the line must choose between were already right — only the printed number was wrong), **V3** (the over-correction direction was already true before the fix, which is exactly why it is a guard and not a finding), **V5** and all of sections A–U unchanged. Captured **in place**, the way `[0.4.83]` learned to: a copy outside `tools/` makes section L report `repo_root: /tmp/…` and exit 3.
+- **No pre-fix replay for `[0.4.85]`, and the reason is the change**: that step edits **only** the suite — `git show HEAD:tools/repo-lint | md5sum` and `md5sum tools/repo-lint` both read `0df9317ebe19afafeafb4766e3f8c405` before it, so there is no "before" tool to swap in and a replay would be the baseline re-quoted. The red this step's assertions can produce is instead demonstrated **inside** the suite by M23, which is the same claim in a checkable form: the identical `u7_classify` call returns `dispatch_unclassified=NONE` for the tool and `dispatch_unclassified=typescript` for a copy carrying one unclassified `EXT_LANG` entry. The old suite against the untouched tool was measured at **366/0** immediately before the edit; the new suite on the same tree is **374/0**, i.e. exactly the eight assertions added and nothing moved.
- **Pre-fix replay for `[0.4.83]`**: the new suite against `HEAD`'s tool blob swapped **in place** (new md5 `16d7a0cc073ab416ff0d685ae666c481`; old `0a5ccfcbbc9093212cce0c4d54d4d28c`, restored and re-verified byte-identical) → **333 passed / 9 failed**, every red a section-U finding or an unplantable precondition: **U1 ×2** (the rule line and its `fail to parse` twin), **U2**, **U3**, **U4** (no `_SYNTAX_LANGS` exists yet, so the set is unmatched), **U5 ×2** (0 definitions, 0 prints), **M20/M21 preconditions ×2** (the `if all(k in _SYNTAX_LANGS …)` needle does not exist — their other six assertions could not run, hence **342 counted pre-fix against 348 post-fix**). Guards that passed pre-fix and thereby identify themselves: **U1's exit codes**, **U2's exit code**, **U3's exit code** and all of sections A–T unchanged. Captured **in place**, not via `REPO_LINT_BIN` pointing outside `tools/`: the first attempt did exactly that and returned 11 extra reds in section L, because `default_repo()` resolves relative to the script — a harness artifact (`repo_root: /tmp/…`, exit 3) that cost one capture to read correctly, the same trap `[0.4.60]`'s replay documented.
- **Pre-fix replay for `[0.4.82]`**: the new suite against `HEAD`'s tool blob swapped **in place** (so section L's `repo_root == '/data/repo'` still holds; old md5 `fb0d6c5d1ec55d91a0cd075dfee9e2ee` → new `0a5ccfcbbc9093212cce0c4d54d4d28c`, restored and re-verified) → **297 passed / 21 failed**: 18 section-T findings plus M17/M18/M19's three **unplantable preconditions** (their other six assertions could not run — 318 counted pre-fix against 324 post-fix). Guards passing pre-fix and thereby identifying themselves: the exit-0 halves of T1/T3/T4/T5/T6/T7, and all of A–S. **Re-taken against the final bytes**: the first capture's md5 (`f6764ec8…`, an intermediate version superseded by the `Exit codes:` 1-line wording edit) described a file that no longer existed by the time this entry was written, so the swap was re-run with the final suite — identical 297 / 21 and the identical 18 + 3 breakdown (`/tmp/opencode/pre-fix-replay-82-final.log`).
- **Section P — ONE exit-code contract** (`[0.4.56]`): P1 counts the contract text in the tool source and requires **exactly one** occurrence; P2 asserts the docstring block names all three rules — `every linted file parses cleanly`, `committed Go module compiles`, `CHANGELOG.md repeats a version token` — the last two being the finding (the stale copy kept only the parse rule); P3 asserts the block still documents codes `0`,`1`,`2`,`3`; P4 runs `--help` and compares its `exit codes:` section to the docstring block **byte for byte** (plus a `--help exits 0` guard); P5 re-asserts the three rules in the rendered `--help`. **P5 is the guard set**: all three pass against the pre-fix tool, because the epilog was the copy that was right — a passing guard that fails after the fix would identify itself.
- **Section Q — EVERY epilog section derived, not copied** (`[0.4.59]`): Q applies P's two checks to the six remaining docstring/epilog pairs (`languages`, `go compile gate`, `changelog version gate`, `reads GIT BLOBS`, `env`, `examples`). **Q-render** (Q1–Q6) runs `--help` and compares each labelled section to its docstring block **byte for byte**, requiring the docstring side to be non-empty (a heading that no longer exists in the docstring cannot pass by rendering nothing); **Q-source** (Q7–Q12) counts each section's distinctive text in the tool source and requires **exactly one** — the check that sees a copy `--help` never renders. **Q13** requires the hand-written `Usage:` synopsis to be *gone* (needle `[--sha SHA] [--format human|json]`, count 0): argparse generates the synopsis from the argument definitions, and the docstring's copy had already drifted from it (no `-h`, `human|json` vs `{human,json}`), so the fifth pair the queue named was closed by deletion rather than by keeping two things in step. Guards: `--help` exits 0 and its `usage:` line is argparse's own.
> build · mimo-v2.6-flash-free
[0m$ [0mcd /data/repo && tail -8 CHANGELOG.md; echo "=== head (top entry)"; grep -n "^## \[" CHANGELOG.md | head -3; grep -c "^## \[" CHANGELOG.md; echo "=== app version"; grep -rn "GLADEX_APP_VERSION" tools/*.php app/ 2>/dev/null | head -3
### Notes
- **Placement**: parked at the bottom like `[0.4.29]`–`[0.4.83]`, so `## [0.4.28]` stays the top entry and `GLADEX_APP_VERSION` (`0.4.28`) keeps agreeing with it.
- **Pointer-only `### Queue`**, as always: `queue-source-check`'s R1 is an equality against **111** item lines and R3 forbids a `- ` line in the newest section, so the live queue stays in `agent-logs/PROGRESS.md`.
- **Deliberately not done**: the suite's **header** mutation index still stops at M16 (M17–M21 and now M22 were never added to it either) and the header's **section** list still stops at `Section S` (T, U and V are undocumented there) — the same "second copy of a list" shape as item **(5)**, neither derived; queued as **(32)** in this run's PROGRESS entry rather than extended here, because writing into a copy nothing checks is the defect, not the fix. No `repo-lint` rule bolted on (items (14) and (18) still queued), no other tool, no `promote` behaviour, no dashboard check.
- **Safety**: model spend **0.00** (`*-free` only), **no money moved** (`BUDGET.md` untouched: **1.50 spent / 3.50 remaining**), **zero DNS writes** (no `pdns-api.py` call), no paid API key configured, **no secret read or printed** (`/root/.pdns-token` and every `*.secret` untouched — the STEP-0 probe only tested existence; no credential and no message body in any prompt/thread/commit), **no service restarted, no certificate touched, no promote executed** (the stale reviewer verdict `promote-gates` reports still refuses it), **Docker stacks and both investor apps untouched**. Live I/O was read-only: the STEP-0 SQL counts and health probes, throwaway git repos under `${TMPDIR:-/tmp}/opencode`, `--help` runs, the pre-fix blob swap (swapped in place, restored, md5 re-verified), and the read-only checks the dashboard performs during regression.
### Queue -> agent-logs/PROGRESS.md
Authoritative next-candidate queue lives in `agent-logs/PROGRESS.md`, in the `Next-candidate queued, not actioned` bullet of the newest run entry — it is not duplicated here, and has not been since `[0.4.67]`. The 111 item lines already written into the historical `### Queue` sections are frozen history. To read the live queue, open `PROGRESS.md`; to know whether that is still true, run `tools/queue-source-check`.
=== head (top entry)
7:## [0.4.28] - 2026-09-24 — Go CLI joins the single version train: build.sh derives its version from this changelog (was a hardcoded 0.2.0), download badge + docs CLI mentions follow, all four binaries rebuilt
21:## [0.4.27] - 2026-09-24 — version drift closed: nine stale `0.3.0` literals across app+docs collapse into one `GLADEX_APP_VERSION` constant sourced from this changelog
38:## [0.4.26] - 2026-09-24 — smtp-relay-probe now ASSERTS the 220 greeting (exit 4): a one-endpoint :25-greeting regression could no longer pass green
89
=== app version
app/src/php/db.php:60: * Prefers `const GLADEX_APP_VERSION = '...'` (the single source of truth;
app/src/php/db.php:74: if (preg_match("/const\s+GLADEX_APP_VERSION\s*=\s*'([^']+)'/", $src, $m)) {
app/src/php/stats.php:92:// App versions — via the shared db.php helper (const GLADEX_APP_VERSION first,
> build · mimo-v2.6-flash-free
Select another run log from the list above. Only files matching run-YYYYMMDD-HHMMSS-N.log are readable.
App log tail — prod-8001.log (last 60 lines)
[Sun Sep 27 06:40:56 2026] 127.0.0.1:60456 Accepted [Sun Sep 27 06:40:56 2026] 127.0.0.1:60456 Closing [Sun Sep 27 06:40:59 2026] 127.0.0.1:60462 Accepted [Sun Sep 27 06:40:59 2026] 127.0.0.1:60462 Closing [Sun Sep 27 06:41:00 2026] 127.0.0.1:60474 Accepted [Sun Sep 27 06:41:00 2026] 127.0.0.1:60474 Closing [Sun Sep 27 06:41:00 2026] 127.0.0.1:60482 Accepted [Sun Sep 27 06:41:00 2026] 127.0.0.1:60482 Closing [Sun Sep 27 06:41:00 2026] 127.0.0.1:60496 Accepted [Sun Sep 27 06:41:00 2026] 127.0.0.1:60496 Closing [Sun Sep 27 06:41:00 2026] 127.0.0.1:60506 Accepted [Sun Sep 27 06:41:00 2026] 127.0.0.1:60506 Closing [Sun Sep 27 06:41:15 2026] 127.0.0.1:52242 Accepted [Sun Sep 27 06:41:15 2026] 127.0.0.1:52242 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52244 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52244 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52256 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52256 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52264 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52264 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52278 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52278 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52294 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52294 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52300 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52300 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52308 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52308 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52314 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52314 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52322 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52322 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52332 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52332 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52334 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52334 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52342 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52342 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52356 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52356 Closing [Sun Sep 27 06:41:16 2026] 127.0.0.1:52368 Accepted [Sun Sep 27 06:41:16 2026] 127.0.0.1:52368 Closing [Sun Sep 27 06:47:07 2026] 127.0.0.1:35216 Accepted [Sun Sep 27 06:47:07 2026] 127.0.0.1:35216 Closing [Sun Sep 27 06:47:15 2026] 127.0.0.1:56400 Accepted [Sun Sep 27 06:47:15 2026] 127.0.0.1:56400 Closing [Sun Sep 27 06:54:36 2026] 127.0.0.1:38490 Accepted [Sun Sep 27 06:54:36 2026] 127.0.0.1:38490 Closing [Sun Sep 27 06:54:37 2026] 127.0.0.1:38502 Accepted [Sun Sep 27 06:54:37 2026] 127.0.0.1:38502 Closing [Sun Sep 27 07:03:06 2026] 127.0.0.1:33316 Accepted [Sun Sep 27 07:03:06 2026] 127.0.0.1:33316 Closing [Sun Sep 27 07:03:06 2026] 127.0.0.1:33330 Accepted [Sun Sep 27 07:03:06 2026] 127.0.0.1:33330 Closing [Sun Sep 27 07:06:41 2026] 127.0.0.1:33980 Accepted [Sun Sep 27 07:06:41 2026] 127.0.0.1:33980 Closing [Sun Sep 27 07:08:03 2026] 127.0.0.1:39948 Accepted [Sun Sep 27 07:08:03 2026] 127.0.0.1:39948 Closing [Sun Sep 27 07:20:45 2026] 127.0.0.1:38356 Accepted
Generated 2026-09-27 05:20:45 UTC · Gladex.de