Files
ersatztv/scripts
timothyandClaude Opus 5 e3a19227c1 fix(845): two independent cold reviews — the guard did not walk the same tree, and CLAUDE.md said the status is not written
Two cold reviewers, independently briefed and worktree-isolated. One returned BLOCKED on the
first two below; the other returned MERGEABLE having not examined them. No arbitration was
needed — both are verifiable, and I reproduced each before acting.

BLOCKING 1 — the CI guard parsed a different population than the library.
`test_the_H10_REVIEWERS_list_is_glob_free_and_non_empty` read `_classify_step()["run"]`, one
step's body. `scripts/lib/h10-reviewers.sh` greps the WHOLE YAML and refuses on anything but
exactly one match. So a second anchored `H10_REVIEWERS=` in ANY other `run:` block was
invisible to the guard while making the writer refuse every verdict — and `main` is PR-only
with `review-verdict/h10` required, so that is a repo-wide merge outage. Reproduced: injecting
one into the last step left the guard green and reddened 31 writer tests whose diagnostics
said nothing about a second assignment. The guard now reads the whole file, so it walks the
same tree as its subject; the header and the decision record no longer claim coverage that
did not exist.

BLOCKING 2 — `CLAUDE.md` said an off-list verdict "fails loudly at your terminal instead of
being written". The status IS written; only the comment is withheld. The script, `ci-cd.md`
and the record all said so correctly, and the most-read doc contradicted them. It now also
says what the other docs did not: the green left standing satisfies the server-side required
check, because branch protection binds the context NAME and not its issuer.

Four clauses were shipped UNWITNESSED, found by the reviewer's own disarm matrix and each now
reddening a named test: the `.statuses` array-TYPE test, the read-back GET's explicit `|| die`,
`?limit=100`, and the `set -f` restoration. The first two passed only because a downstream
check produced the same non-zero exit — the shape this very file already documents at the
`-z`/`-n` arms. They now assert their own diagnostic. `?limit=100` was unobservable because
the shim discarded the query string; the shim now models the measured server (default 30,
clamped to 50, `total_count` reporting the page).

Also fixed, all reproduced first:
  - `[0]` over same-context rows had no uniqueness guard. Unreachable today, but the
    alternative is judging one row's author while another is the one standing.
  - The row count in the not-found refusal came out BLANK on a 200 with an empty body: jq
    exits 0 with empty output, so the `||` fallback was dead exactly where the count matters.
    Tests the value now, not jq's exit.
  - The split pinned globbing but not IFS. A caller with `IFS=-` made `renovate` read as a
    member of `renovate-bot`. Unreachable from this script (bash resets IFS), pinned because
    the header invites reuse.
  - The `set -u` rationale was inherited and is WRONG. Both reviewers measured it: the shell
    EXITS, in both the `if ! f` and the `f; rc=$?` shapes, on bash 5.3 and 3.2. Nothing here
    depended on it; the sentinel now rests on the two grounds that were measured.
  - The `?limit=100` margin was overstated. This instance clamps to MAX_RESPONSE_ITEMS = 50,
    so the headroom is ~3x over today's 8-15 contexts, not 6x, and it shrinks as checks are added.
  - The snapshot boundary now names its DIRECTION in all three places: it is a false ACCEPT,
    and the likely edit (ADDING a reviewer) is exactly the one it mis-handles.
  - The overwrite refusal told the operator to re-review when a gate re-derive needs no review.

A note on the measurements, since two of my own disarms were inert and briefly read as
"no test covers this": a mutation must be checked to actually mutate. The glob-class disarm
still excluded `*`, and the IFS disarm matched two sites and applied to neither.

fixes #845

Decisions-Edit: yes
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019zUmJZHhVP7kXg5DV237TW
2026-08-30 03:38:47 +02:00
..
2024-01-15 10:29:07 -06:00
2024-01-16 13:28:46 -06:00