fix(763): round 9 — assert the repair's reason positively, not by absence
Build ErsatzTV Image / CI toolchain image resolves (pull_request) Successful in 10s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 22s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 17s
PR Gates / Docs update reminder (pull_request) Successful in 21s
review-verdict/h10 Review-verdict: MERGEABLE @ 462118d (base: main)
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 14s
PR Gates / decisions lifecycle (pull_request) Successful in 23s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Failing after 14s
Review verdict / Set review-verdict status (pull_request_target) Successful in 7s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Canceled after 1m31s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 0s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s

A sixth cold review found everything in round 8 clean except one line, and it
is the rule this branch keeps rediscovering: the test pinned the new
`raced_why` only by asserting the ABSENCE of the borrowed wording. Measured —
replacing the string with `zzz` left the suite green while an operator would
get `::error::… — zzz.` beside a sticky sentinel. The sibling test 330 lines
away states the rule and follows it; this one did not.

Now asserted positively, with the em-dash and full stop discriminating the
`::error::` reason from the `::warning::` text that continues ", which cannot
be true". The `zzz` mutation reddens it.

Three nits from the same review, all verified by execution rather than reading:
  - the earlier fixture's row was excluded by the strict `> $since` because the
    mark became its OWN id, not because it sat below the mark.
  - the predecessor comment said `main` "warned only on `null`". True of the two
    EMPTY shapes being contrasted; an empty body and a non-array object warned
    as well. Scoped.
  - `docs/ci-cd.md` and the record described the `::error::` as a two-way split
    (found vs unverifiable). Round 8's whole argument is that a complete read
    returning an IMPOSSIBLE answer is a third case, not a variety of the second
    — which is the operator-facing point, since it decides whether to go looking
    for an API failure that never happened. Both now say three.

The review re-verified, by comment-stripped diff, that round 8 changed no
executable line beyond the `raced_why` string and the if/elif restructure, and
independently reproduced both inertness measurements and the `origin/main`
predecessor behaviour.

Verification: `scripts/tests` 1097 passed, 2 skipped; decisions_validate and
build_decisions_catalog --check exit 0.

refs #763

Decisions-Edit: yes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-28 18:42:22 +02:00
co-authored by Claude Opus 5
parent 4164efbc3e
commit 462118d98d
5 changed files with 20 additions and 7 deletions
+2 -1
View File
@@ -1332,7 +1332,8 @@ jobs:
# `raced=0` — a green concluded from a list that cannot be real — on the one path whose
# failure direction is toward SUCCESS, and silently, since the walk itself reports
# success. The predecessor was not better in the way it first appears: its
# `jq -e 'type == "array"'` gate ACCEPTED `[]` and warned only on `null`, so the `[]` half
# `jq -e 'type == "array"'` gate ACCEPTED `[]` and, of the two empty shapes, warned only
# on `null` (an empty body and a non-array object warned too), so the `[]` half
# of this fail-open was already unlogged on `main`. What is new is that the paged walk
# additionally reports such a read as a SUCCESS, which is why the rejection lives here.
#
+5 -2
View File
@@ -1648,8 +1648,11 @@ well-formed "no statuses exist" is not retried (the body is valid), so accepting
asked whether ANY row sat above the mark, which an unrelated newer row satisfied; this asks only whether
the list is empty, which no unrelated row can produce.
The `::error::` distinguishes a verdict actually found from an unverifiable read; the sentinel
*description* stays generic, because the classification recognises it as a fixed point.
The `::error::` names its own cause, and there are three: a verdict actually **found**; a read that
could not be **completed**; and a read that completed but returned an **impossible** answer. The third
is not a variety of the second — an operator holding a sticky sentinel needs to know whether to go
looking for an API failure that never happened. The sentinel *description* stays generic, because the
classification recognises it as a fixed point.
Three properties of this workflow are security-relevant and are **structurally** asserted by tests in
`scripts/tests/test_pr_changed_files.py` — those tests pin the workflow's shape, which is not the same
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+11 -2
View File
@@ -1153,8 +1153,9 @@ if "/statuses/" in url:
#
# NO RACED VERDICT IS PLANTED, deliberately. An earlier shape appended one to dramatise
# the stakes, and it was inert twice over: unconditionally it also joined the PRE-write
# read and lifted the mark above itself, and gated to the post-write read it is never
# served, because page 1 answers `null` before any row reaches the wire. A row the test
# read, which set the mark to its OWN id — the strict `> $since` then excluded it — and
# gated to the post-write read it is never served at all, because page 1 answers `null`
# before any row reaches the wire. A row the test
# cannot observe is decoration that reads as coverage. What is actually under test is
# narrower and sufficient: a response asserting an empty history for a sha this job wrote
# to must not be accepted as proof that nothing raced.
@@ -3887,6 +3888,14 @@ def test_an_EMPTY_post_write_history_is_not_evidence_that_nothing_raced(tmp_path
assert "was overwritten" not in log, (
f"an unverifiable read was reported as an overwritten human verdict:\n{r.stdout[-900:]}"
)
# THE REASON IS PART OF THE FIX, so it is asserted POSITIVELY. An absence assertion alone leaves
# `raced_why` unpinned — any string at all, including a placeholder, satisfies it while the
# operator gets a sticky sentinel explained by nothing. The em-dash and full stop discriminate the
# `::error::` reason from the `::warning::` text, which continues "…, which cannot be true".
assert "— the status history came back empty after this job posted to it." in log, (
"the repair did not report its own reason; the ::error:: carries whatever `raced_why` held "
f"and nothing pins it:\n{r.stdout[-900:]}"
)
# The walk COMPLETED here, on a validated terminator — the answer was impossible, not unreadable.
# Borrowing the unreadable-history wording would send an operator staring at a sticky sentinel
# looking for an API failure that never happened.