fix(rivet): a resolved finding is release-ready — v0.7.0 was one artifact from cuttable - #367
Merged
Merged
Conversation
…fact from cuttable #342 said the readiness verdict was wrong in BOTH directions. #363 fixed the permissive direction (Cuttable with nothing verified). This is the other one, which I identified three days ago and then did not chase: v0.7.0 SHIPPED on 2026-08-26 and its burn-down still called it not-cuttable. The blocker is FIND-OS-TIMER-SLEEP-CONTRACT-001, a `finding` at `resolved`. Findings do not have a `verified` state — their lifecycle is active -> resolved, and `resolved` IS the terminal one. So the readiness rule was demanding a status this artifact type never reaches. It is not that the finding was unfinished; it is that the rule asked the wrong question of it. `ready-when: [resolved]` is rivet's mechanism for exactly this. Checked before using it that it cannot leak: every artifact at `resolved` in gale is a finding — FIND-OS-TIMER-SLEEP-CONTRACT-001 finding GAP-ZMS-5 / GAP-ZMS-8 / GAP-ZMS-10 finding 4 result(s) so no requirement or verification can slip through on this status. Measured across every release, and only ONE verdict moved: v0.7.0 NOT cuttable -> Cuttable the release that had already shipped v0.5.0 NOT (3) -> NOT (3) unchanged v0.7.1 NOT (6) -> NOT (6) unchanged v0.7.2 NOT (6) -> NOT (6) unchanged v0.9.0 NOT (3) -> NOT (3) unchanged v0.8.0 Cuttable -> Cuttable unchanged That is the discrimination test: a change that flipped several would be widening the ready set, not correcting a type mismatch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This was referenced Sep 9, 2026
avrabe
added a commit
that referenced
this pull request
Sep 9, 2026
…ded" installing nothing (#370) #367 failed on `llvm-lto-test (msgq)`, a Zephyr kernel test, on a PR that touches only rivet YAML. That is the shape of a flake, and it is not one. ## What actually happened Installing 'arm-zephyr-eabi' GNU toolchain ... ERROR: GNU toolchain download failed FATAL ERROR: command "/root/zephyr-sdk-1.0.1/setup.sh -t arm-zephyr-eabi -h" failed (x3, ~10s apart) The step that ran it — `Initialize west workspace` — **passed**. The job failed one step later, in `Setup SDK paths`, looking for a toolchain that had never been installed. Confirmed against the job's own step conclusions: step 7 success, step 8 failure, step 9 skipped. ## Why the step passed for attempt in 1 2 3; do CMD && break || sleep 5; done When every attempt fails the last command executed is `sleep`, which succeeds, so the loop's exit status is 0. `bash -e` — which is what Actions runs `run:` under — does not help: a failing command inside an `&&`/`||` list is exempt from `set -e`, and the list's status is the final `sleep`. Verified rather than reasoned: $ bash -e -c 'for attempt in 1 2 3; do false && break || sleep 0.1; done'; echo $? 0 So no `west update` or `west sdk install` anywhere in this repo could fail its own step. 28 of them, across 10 workflows, in one-line and multi-line spellings. ## The fix n=0; until CMD; do n=$((n+1)); if [ $n -ge 3 ]; then echo "::error::CMD failed after 3 attempts" >&2; exit 1; fi; sleep $((N*n)); done Exits non-zero when the attempts run out, and the backoff now GROWS. The old form slept a fixed 5s, so three attempts landed inside ~22 seconds — one throttle window, which is no retry at all against a rate-limited asset host. All three paths verified: all-fail exits 1, first-try-success exits 0 without sleeping, fail-then-succeed exits 0. ## The guard tools/check-retry-loops.py sweeps every workflow for the shape and fails on it, because this will be reintroduced by anyone copying a neighbouring line. It matches `&& break ||` generally, not just the sleep spelling — `|| true` is the same defect with a shorter name. Negative control, run on the real tree: reintroducing one loop in coverage.yml fails the gate at the right file and line; removing it returns green. Its --self-test pins all three cases including the `|| true` variant. Wired as `retry-loops` in kill-criteria.yml. NOT added to required-contexts.txt in this PR — a new gate earns a merge cycle before it becomes a merge blocker, the same way wcet-sidecar is waiting. ## What this does not claim This does not explain WHY the SDK's toolchain fetch failed. It failed 0.4s after starting while the 70MB SDK tarball downloaded fine at 185MB/s in the same step, which points at an instant refusal from the asset host rather than a slow network, and the same job passed on #369 at the same minute. That is still intermittent and still upstream. What changes is that it can no longer pass silently and reappear as a confusing error in a later step. Claude-Session: https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#342 said the readiness verdict was wrong in both directions. #363 fixed the permissive
one (Cuttable with nothing verified). This is the other, which I identified three days ago
and then did not chase: v0.7.0 shipped on 2026-08-26 and its burn-down still called it
not-cuttable.
The blocker is
FIND-OS-TIMER-SLEEP-CONTRACT-001, a finding atresolved. Findingshave no
verifiedstate — their lifecycle isactive → resolved, andresolvedisterminal. The rule was demanding a status this artifact type never reaches. The finding
wasn't unfinished; the rule asked the wrong question of it.
Checked before widening anything
ready-when: [resolved]is rivet's mechanism for this, but it would be a leak ifrequirements used the status too. Every artifact at
resolvedin gale is a finding:Only one verdict moved
That's the discrimination test. A change that flipped several would be widening the ready
set rather than correcting a type mismatch.
Kill-criterion: a requirement or verification reaches release-ready via
resolved.🤖 Generated with Claude Code
https://claude.ai/code/session_011QG86sovTbfnPNY9SfhSmo