chore(readme-pin-check): split the mirror and digest graders so the digest half can be required #1463

Closed
opened 2026-09-07 23:56:12 +02:00 by bosun · 1 comment
Owner

One job posts one status for two checks that fail for unrelated reasons, so the digest check cannot be made blocking without also making every merge here depend on gitea.com being up.

readme-pin-check.yml's single job check runs both:

:105  grade README pins against what the mirror can serve   -> reads gitea.com (external)
:146  grade docs-pinned action.yml image digests (#1453)     -> reads our own tags (internal)

Both report as readme-pin-check / check, and that context is not required. It went red on #1448 naming a real defect — v0.62.4 carries the all-zero placeholder and the docs pin it 18 times — and the reviewer had no way to hold with it.

Requiring the context as it stands would put a third party on our merge path: the workflow's own header says a gitea.com outage is rc=2, which is red, so an outage would stop all merging here.

Scope

  1. Split the job so the two graders post separate contexts — readme-pin-check / mirror and readme-pin-check / digest.
  2. Add only readme-pin-check / digest to main's status_check_contexts (24th). The mirror half stays advisory and keeps its could-not-grade behaviour.
  3. In mirror-release.yml's set-adopter-pin, run tag-action-digest-check on the new tag and refuse to open the pin PR if it fails. It must refuse, not warn — the existing rc arm at :254 emits ::warning:: and continues, which is punctuation.

Acceptance criteria

  • The two graders post distinct contexts, and each names in its PASS what it did NOT check — jobs mirror (:39) and digest (:138); each PASS points at the other context by name (:130, :222)
  • readme-pin-check / digest is required on main; readme-pin-check / mirror is not — added 00:38, 23 -> 24 contexts, before/after diff shows exactly one addition and zero removals
  • The digest context reddens on a head whose docs pin a placeholder tag, verified by pointing it at v0.62.4@engineer forced all 18 pins to v0.62.4 against the real binary: rc=1, ::error::
  • A gitea.com failure reddens only the mirror context, verified by an arm that makes the mirror read failMETHOD CHANGED, state verified by stronger evidence: the arm was NOT built. The invariant is code-evident instead — --target-api-url https://gitea.com/api/v1 appears once, at :125, inside job mirror (:39-137). Job digest (:138+) contains no gitea.com path at all; its only mention is prose in its own PASS at :222 disclaiming the mirror. A code-evident invariant outranks an arm, but the AC named an instrument that does not exist and ticking it silently would have hidden that
  • set-adopter-pin does not open a pin PR when the target tag's digest is a placeholder, with a mutation showing the refusal fires — @engineer, live tripwire at the branch push: v0.63.0 -> rc=0 tripwire REACHED; 18 pins forced to v0.62.4 -> rc=1, tripwire NOT reached. @rigger then INSTALLED the echo-only mutation control in-process (tests/workflows.bats:7354-7360, asserted at :7412) so it cannot regress silently
  • Ordering recorded: the docs must already name a good tag before the digest context is required, or nothing merges — executed in that order: #1464 landed the v0.63.0 pins at 00:08, #1466 merged at 00:32, the context was required at 00:38 only after it was observed success on a real post-merge head

Anchor

@surveyor's review of #1448 found the ordering — the path that advances the doc pins (mirror-release.yml) does not grade the digest, while the path that grades it (readme-pin-check.yml) is pull_request only and advisory. The split is @bosun's; the dependency-profile argument is what makes requiring only half of it safe. Operator agreed 2026-09-07 23:44 CEST. v0.63.0 cut clean at 23:46 and baked a real digest, so the docs fix is an advance rather than a retreat.

One job posts one status for two checks that fail for unrelated reasons, so the digest check cannot be made blocking without also making every merge here depend on gitea.com being up. `readme-pin-check.yml`'s single job `check` runs both: ``` :105 grade README pins against what the mirror can serve -> reads gitea.com (external) :146 grade docs-pinned action.yml image digests (#1453) -> reads our own tags (internal) ``` Both report as `readme-pin-check / check`, and that context is not required. It went red on `#1448` naming a real defect — `v0.62.4` carries the all-zero placeholder and the docs pin it 18 times — and the reviewer had no way to hold with it. Requiring the context as it stands would put a third party on our merge path: the workflow's own header says a gitea.com outage is `rc=2`, which is red, so an outage would stop all merging here. ## Scope 1. Split the job so the two graders post separate contexts — `readme-pin-check / mirror` and `readme-pin-check / digest`. 2. Add **only** `readme-pin-check / digest` to `main`'s `status_check_contexts` (24th). The mirror half stays advisory and keeps its could-not-grade behaviour. 3. In `mirror-release.yml`'s `set-adopter-pin`, run `tag-action-digest-check` on the new tag and **refuse to open the pin PR** if it fails. It must refuse, not warn — the existing rc arm at `:254` emits `::warning::` and continues, which is punctuation. ## Acceptance criteria - [x] The two graders post distinct contexts, and each names in its PASS what it did NOT check — jobs `mirror` (`:39`) and `digest` (`:138`); each PASS points at the other context by name (`:130`, `:222`) - [x] `readme-pin-check / digest` is required on main; `readme-pin-check / mirror` is not — added 00:38, 23 -> 24 contexts, before/after diff shows exactly one addition and zero removals - [x] The digest context reddens on a head whose docs pin a placeholder tag, verified by pointing it at `v0.62.4` — @engineer forced all 18 pins to `v0.62.4` against the real binary: `rc=1`, `::error::` - [x] ~~A gitea.com failure reddens only the mirror context, verified by an arm that makes the mirror read fail~~ — **METHOD CHANGED, state verified by stronger evidence:** the arm was NOT built. The invariant is code-evident instead — `--target-api-url https://gitea.com/api/v1` appears once, at `:125`, inside job `mirror` (`:39-137`). Job `digest` (`:138+`) contains no gitea.com path at all; its only mention is prose in its own PASS at `:222` disclaiming the mirror. A code-evident invariant outranks an arm, but the AC named an instrument that does not exist and ticking it silently would have hidden that - [x] `set-adopter-pin` does not open a pin PR when the target tag's digest is a placeholder, with a mutation showing the refusal fires — @engineer, live tripwire at the branch push: `v0.63.0` -> `rc=0` tripwire REACHED; 18 pins forced to `v0.62.4` -> `rc=1`, tripwire NOT reached. @rigger then INSTALLED the echo-only mutation control in-process (`tests/workflows.bats:7354-7360`, asserted at `:7412`) so it cannot regress silently - [x] Ordering recorded: the docs must already name a good tag before the digest context is required, or nothing merges — executed in that order: `#1464` landed the `v0.63.0` pins at 00:08, `#1466` merged at 00:32, the context was required at 00:38 only after it was observed `success` on a real post-merge head ## Anchor @surveyor's review of `#1448` found the ordering — the path that advances the doc pins (`mirror-release.yml`) does not grade the digest, while the path that grades it (`readme-pin-check.yml`) is `pull_request` only and advisory. The split is @bosun's; the dependency-profile argument is what makes requiring only half of it safe. Operator agreed 2026-09-07 23:44 CEST. `v0.63.0` cut clean at 23:46 and baked a real digest, so the docs fix is an advance rather than a retreat.
Author
Owner

Closing. #1466 merged at a5223301; the required context was added at 00:38.

All six ACs graded against the substrate rather than against the PR description, and AC4 is struck rather than plainly ticked — the arm it names was never built. The property holds by a code-evident invariant instead, which is stronger, but the AC prescribed an instrument that does not exist and ticking it silently would have hidden that.

job `mirror`  :39-137   --target-api-url https://gitea.com/api/v1 appears ONCE, at :125
job `digest`  :138+     no gitea.com path at all; its only mention is prose in its own
                        PASS at :222 disclaiming the mirror

That is the property the whole split was for: requiring the digest half puts nothing outside our control on the merge path.

What this cost and what it caught

The split was @surveyor's finding from her #1448 review — the path that advances the doc pins does not grade the tag's action digest — and it was found because v0.62.4 became the pinned version while carrying sha256:0000….

Two reviewers on disjoint halves: @surveyor approved the design at 00:22, @engineer filed REQUEST_CHANGES at 00:25 on the half she had explicitly not graded. A merge on her approval alone was mechanically clear and would have landed 166 bats lines containing an arm that cannot fail — the arm guarding the refusal that is the entire point of the change. body.find("tag-action-digest-check") matched an echo.

@rigger's fix went past what was asked: he built the echo-mutant control into the arm, so it constructs the mutation in-process every run rather than depending on someone remembering to mutate. A control that was RUN once versus a control that is INSTALLED.

Known residue, not carried by this tracker

  • actual_digest_at != digest_at in tests/workflows.bats is unreachable — same function, same arguments; a comparison shaped like a guard. @engineer requested a tracker; @bosun to file.
  • Requiring the digest context blocked #1467, whose branch predated the split and therefore posts the old context name. That is @bosun's sequencing cost, recorded on that PR, and it clears on the rebase it needed anyway.
Closing. `#1466` merged at `a5223301`; the required context was added at 00:38. All six ACs graded against the substrate rather than against the PR description, and **AC4 is struck rather than plainly ticked** — the arm it names was never built. The property holds by a code-evident invariant instead, which is stronger, but the AC prescribed an instrument that does not exist and ticking it silently would have hidden that. ``` job `mirror` :39-137 --target-api-url https://gitea.com/api/v1 appears ONCE, at :125 job `digest` :138+ no gitea.com path at all; its only mention is prose in its own PASS at :222 disclaiming the mirror ``` That is the property the whole split was for: requiring the digest half puts nothing outside our control on the merge path. ## What this cost and what it caught The split was @surveyor's finding from her `#1448` review — *the path that advances the doc pins does not grade the tag's action digest* — and it was found because `v0.62.4` became the pinned version while carrying `sha256:0000…`. Two reviewers on disjoint halves: @surveyor approved the design at 00:22, @engineer filed `REQUEST_CHANGES` at 00:25 on the half she had explicitly not graded. **A merge on her approval alone was mechanically clear and would have landed 166 bats lines containing an arm that cannot fail** — the arm guarding the refusal that is the entire point of the change. `body.find("tag-action-digest-check")` matched an `echo`. @rigger's fix went past what was asked: he built the echo-mutant control *into* the arm, so it constructs the mutation in-process every run rather than depending on someone remembering to mutate. A control that was RUN once versus a control that is INSTALLED. ## Known residue, not carried by this tracker - `actual_digest_at != digest_at` in `tests/workflows.bats` is unreachable — same function, same arguments; a comparison shaped like a guard. @engineer requested a tracker; @bosun to file. - Requiring the digest context blocked `#1467`, whose branch predated the split and therefore posts the old context name. That is @bosun's sequencing cost, recorded on that PR, and it clears on the rebase it needed anyway.
bosun closed this issue 2026-09-08 00:46:01 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#1463
No description provided.