Commit Graph
2 Commits
Author SHA1 Message Date
timothy 0cf355e494 fix(772,792): address both cold reviews — an unverified pin is no longer a green job
Two independent reviewers (one cross-family) converged on the same defect, and it was the
important one: the preflight WARNED and exited 0 on every answer that was not 200 or 404,
so a missing `curl`, a moved registry or a DNS change would have left it green forever —
"the check could not run" presenting as "the pin is fine", in a script whose own header
disclaimed exactly that. Unknown answers are now retried (3x, 5s) and then FAIL, with
wording kept distinct from the deleted case because the two send an operator to different
places.

Also from the reviews:

  * An absent secret does not arrive as an unset variable. `${{ secrets.X }}:${{ secrets.Y }}`
    interpolates to ":", a perfectly non-empty and perfectly useless credential, and the
    tests covered only the unset shape. Both halves are now required, and the parametrised
    test drives the production shape.
  * HTTP 200 is not a manifest. A proxy or a login page answers 200 too, so the body is
    fetched and matched for `schemaVersion` (a shell `case`, so no jq dependency and no
    pipeline that can inject).
  * The curl stub ignored `-u` and answered 200 regardless, so deleting the real `-u` would
    have left the suite green while the live registry rejected every request. It now 401s an
    unauthenticated read, as the registry does.
  * The mutation's declared diagnostic changed with the script: now that unknown fails too,
    the exit code no longer separates "deleted" from "could not check", so the proof turns on
    the message and `expect` says so.
  * docs/ci-cd.md: `scan` is no longer the only `docker-build.yml` job on the small lane, so
    the tag-push exclusivity claim and the lane membership were both false. Fixed.
  * "Immutable" was overstated: `ci-image.yml` tags `rev-parse --short HEAD`, so a dispatch or
    a weekly no-cache run at the same HEAD republishes that tag from a rebuilt image. Stated,
    along with what the rebuild recovery does NOT restore (mutable bases and apt, so equivalent
    rather than bit-identical).
  * The recovery recipe left you in a worktree checked out at the pin commit — where the
    verify script does not exist, and where the workflow carries the pre-bump pin. It now
    keeps `$repo`, returns, and removes the worktree. It also needed BuildKit's `http = true`
    caveat: the container driver does not inherit the daemon's insecure-registries.
  * The root cause carries its evidentiary limit and its reproduction commands, and says what
    to conclude if a pin vanishes after server-management#842 lands (refuted, not re-applied).
  * The `ci.required-job-step-execution-markers` carve-out named one container-free job; there
    are two now, and the membership is what rots.
  * The decision record's `''` YAML escapes leaked into rendered prose; "status, no comment ->
    ask" is qualified (a prior positive verdict for the SAME head still satisfies condition
    (c)); "exits 1" is "exits non-zero" (usage exits 2, jq its own status, signals 128+n).

refs #772
refs #792
Decisions-Edit: yes
2026-08-22 23:25:26 +02:00
timothy 5ba442c11c fix(772,792): name the missing toolchain image, and stop a refusal leaving a verdict comment
#772 — the pinned CI toolchain image can be deleted out from under us, and when it was
(2026-08-11..13) all five `container:` jobs died at image pull, both required contexts
included, with the cause buried in each job's log. Root cause is registry-side and is now
established rather than guessed: an owner-level Gitea package cleanup rule (keep_count 15,
remove_days 1, remove_pattern `.*`, keep_pattern no 7-hex sha can match) deletes a sha tag
once 15 newer versions exist, and `ExecuteCleanupRules` ran nightly through the window. The
`ersatztv` package carries the same rule's fingerprint exactly — every sha tag older than
the 15-slot window is gone, every keep_pattern tag back to 26.3.1 survives. Version deletes
leave no audit row, so the specific run cannot be replayed; that limit is stated where the
claim is made. The durable fix belongs to the registry's repo: server-management#842.

What lands here is what a consumer of someone else's registry can do:

  * `toolchain-preflight`, a container-free job (a job consuming the image could not run to
    report it missing) resolving every pin against the registry and failing with a message
    that names the tag and the recovery. Not a `needs:` of the jobs it diagnoses — gating
    five jobs behind a checkout and one curl taxes every green run to speed up a rare red
    one, and they already fail fast.
  * Only HTTP 404 means gone. Everything else is could-not-tell, and rejected credentials
    fail rather than pass as unknown — "the check could not run" must never present as
    "the pin is fine".
  * A recovery path that does not need CI: rebuild the SAME tag from the commit it names
    and push it. The push half was verified against this registry on 2026-08-22 with a
    throwaway package (created, resolved 200, deleted).

#792 — the reported defect was the exit code, and re-measuring says that premise is false:
every no-status path already exits 1, and eight refusal modes now assert it against the real
predecessor, where they pass. The observed 0 came from the invocation, not the script. What
WAS broken is the half-state the issue describes second: the comment was written before the
status, so every refusal left `Review-verdict: MERGEABLE @ <head>` on a PR with no gating
status behind it. The two writes are now ordered status-then-comment, which makes the only
reachable half-state the safe one — a status with no comment leaves the merge hook's
condition (c) with nothing to classify, which is an `ask`. The refusals themselves are
untouched. Ordering rather than compensating deletion: an orphaned-comment cleanup needs a
Gitea call, and these refusals are usually caused by Gitea being unreachable.

Proof for the ordering is the split against origin/main's script: the 8 orphan/ordering
tests go red there, the 8 exit-code tests stay green.

fixes #772
fixes #792
Refs: server-management#842
Decisions-Edit: yes
2026-08-22 22:52:56 +02:00