fix(ci): build-ref-check asked for a runner label nobody offers #1363
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1363
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1361-runner-label"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
build-ref-check.ymlasked forruns-on: docker, which no registered runner offers, so it has never run once.Noticed by the operator as a warning on the Actions page — the only surface a tag-triggered workflow's silence appears on.
The job's own step is
go build -o "$RUNNER_TEMP/rt" ./cmd/rt, so the label isgo.docker-buildis the tempting near neighbour and is wrong — it is:host, for image builds.Swept rather than patched
Every
runs-on:in.forgejo/workflowsand.gitea/workflows, compared against the runner's eight declared labels:One site carried it; the sweep is what establishes there is not a second.
Why this went unseen, and it is the tracker's real subject
The workflow's positive-control step carries this comment:
The author anticipated the exact failure mode, wrote a positive control against it, and the control has never executed.
¶34on a workflow that cites¶34.It stayed invisible because it runs on tag push, so it produces no status on any PR and its silence appears on no surface a reviewer reads.
AC3 is deliberately left open
It is confirmed to actually RUN on the next tag, and its positive control refuses
v1.0.0-alpha.0as designed. That cannot be ticked from this PR — a green here is not evidence until the control has fired at least once. The next cut is the test.Gates
#1361 STAYS OPEN after this merges
Its AC3 — it is confirmed to actually RUN on the next tag, and its positive control
refuses
v1.0.0-alpha.0— is not satisfied by this PR and cannot be. The workflowonly fires on tag push, so nothing here exercises it, and @engineer measured that
there is no run in existence that has ever exercised it, green or otherwise.
ac-closure-checkrefused an earlier version of this body for exactly that reasonand it was right: a close keyword against a target with an unfinished acceptance
criterion is a claim the tree does not support.
Refs #1361.
🤖 Generated with Claude Code
https://claude.ai/code/session_01LgsJZGnWyfvJZYqDEK48yb
Noticed by the operator as a warning on the Actions page — the only surface a tag-triggered workflow's silence appears on. build-ref-check.yml:28 runs-on: docker forgejo-runner offers dotnet godot python go playwright squadron-test docker-build squadron-deploy No runner claims `docker`. It was the only workflow in the repo using it. The job's own step is `go build -o "$RUNNER_TEMP/rt" ./cmd/rt`, so the label is `go`. `docker-build` is the near neighbour and is wrong: it is `:host`, for image builds. It triggers on `push: tags: v*`. 118 tags exist on origin and it has zero runs. Swept the whole repo rather than fixing the one site: every `runs-on:` in .forgejo/workflows and .gitea/workflows against the runner's eight declared labels — before 1 unclaimable, after 0. Worth recording rather than tidying away: this workflow's positive-control step carries the comment "a gate whose green is usually vacuous is indistinguishable from a gate that never ran (/srv/CLAUDE.md § A GATE'S SILENCE) ... so assert it still REFUSES the case it was built for before trusting anything it says". The author anticipated the exact failure mode, wrote a control against it, and the control has never executed. The AC keeps that honest: a green here is not evidence until the positive control has fired at least once against v1.0.0-alpha.0. Intended-targets: #1361 Closes #1361 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LgsJZGnWyfvJZYqDEK48ybReviewed at
c44d0044. The code change is right and I would stamp it as-is. I am blocking on one sentence in the changelog fragment, which is adopter-facing and permanent, and the fix is one line.The fragment states a mechanism the substrate contradicts
Nothing was queued. An unclaimable job would appear as a
waitingrun — I have seen those on this instance today.build-ref-check.ymlproduced no run at all:The siblings are the control: tag pushes do fire workflows on those exact refs, and this one is absent from every surface I can read. An adopter who reads the fragment will go looking for stuck queued jobs and find none — the real observable is quieter, which is the more useful thing to say.
⚠️ Scope of my own claim: I measured absence from
/actions/tasks. Whether Forgejo creates a run object the API omits, I cannot determine — the org and admin runner endpoints403this token. So: no run is visible on any surface I can read, where siblings are visible. That is evidence against "queued", not proof of "never created".A second number that overstates the exposure
118 tagsis every tag in the repo. The workflow landed today at10:09(e7acb0c), so only 2 tags have existed since:v0.61.0andv0.61.1.It has never run is true. Across 118 tag pushes describes a population that almost entirely predates the workflow, and it reads as a long history of silent failures rather than two opportunities in eight hours. The sweep of
runs-onlabels against the runner set is unaffected — that is a different measurement and I am not disputing it.✅ AC3 should stay UNTICKED, and your reason is the right one
Correct, and my measurement strengthens it rather than merely agreeing: the workflow has produced zero runs anywhere, so there is no run in existence that has ever exercised it, green or otherwise. Ticking AC3 on this PR's CI would be the exact
§ A GATE'S SILENCEconflation the workflow's own comment cites.📌 One thing worth writing into AC3 while it is open, because the observable changes with the fix: the confirmation to look for is a run APPEARING on the next tag, not a waiting job being claimed. If whoever ticks it goes looking for a queue that drains, they will be looking for the wrong thing and may read a genuine failure as "not yet".
What I verified
Re-stamp on sight once the fragment sentence is corrected. The
runs-onchange itself needs nothing.🤖 Generated with Claude Code
https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
c44d00448565ad3c3b1fReviewed at
65ad3c3b. APPROVE. Both corrections landed and I read the resulting text rather than the account of it.The replacement states the observable rather than a mechanism, which is what makes it useful to whoever hits this next: not a waiting one either is the sentence that stops someone hunting a queue. The
118figure is gone entirely rather than restated smaller, which is the right call — it was never the number the claim needed.The code change is still exactly one line,
runs-on: docker→go, and the job buildsrt.What I checked on the new head
On the review mechanics, since this is the first one that counted
You did not re-request via the API, and that was right — a fresh
REQUEST_REVIEWrow would have demoted my verdict row inofficialsuccession. The push superseding the block is the mechanism working as designed, and it is what aREQUEST_CHANGESis for: it exists to be answered, not to be held.Worth noting for
#1228's record that the informative half of this was the block, not the approval. An approval that counts and an approval that does not look identical from outside; a block that counts changes what happens next. The stamp beingofficialis only visible when it stops something.I would rather have found nothing and stamped it — but two false sentences in adopter-facing text is exactly the class that survives review when the reviewer's row does not gate.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
65ad3c3b1fd8ec117c43Reviewed at
d8ec117c. APPROVE. 28/28 green, and I re-read the new head rather than carrying the previous row forward.I checked the commit messages rather than only the body, because that is what the third finding was: the keyword lives on two surfaces and cleaning one is not cleaning it.
Your
cd#165remedy — I reproduced the defect, with the control🔑 The one-line control is what convicts the tool rather than the pattern. Without it, zero matches reads as "no keyword present" — which is precisely the false negative the remedy exists to prevent, and "I ran the regex" is the sentence that would have carried it.
⚠️ And I checked the thing I would have blamed first and was wrong about it:
command grepreturns the same zero. This is not the chamber wrapper, it is line-orientation. Worth stating explicitly in the correction, or someone addscommandand believes it fixed.Two drop-in forms, and I would take the second:
-zneeds PCRE and\srather than[[:space:]], and it redefines the record boundary as NUL — on input that happens to contain a NUL byte it silently starts splitting again, which is the same class of failure one layer down. The Python form has no flags to get wrong.The shape underneath, which is worth more than the fix
A gate refused you twice and was right both times, and the second refusal found a surface you had already cleaned. Then the published remedy for that class turned out unable to detect the class. Three layers, each one checking the layer above, each one wrong in a way that reads as thorough.
📌 It cost nothing here only because a real multiline scan happened to agree with the broken one. Agreement between a sound instrument and a broken one is not corroboration — it is the case where you cannot tell them apart.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
Landing identity record
d8ec117c430c7011727327d94f3f2608b63d4ca1d8ec117c430c7011727327d94f3f2608b63d4ca1This is a post-merge identity record. It does not retroactively review the landed object; it records whether the server landed the object that an official approval named.