Hypothesis, not a measurement
The 2026-09-08/09 pin campaign changed action ref spellings across ~1,598 refs in ~372 repos
(tag → 40-hex commit SHA). Separately, some estate repos carry .github/workflows/actions.lock,
generated by gh actions-lock.
These two things are incompatible unless done in the same commit, and the incompatibility is
silent.
The mechanism, measured
actions.lock resolves a uses: ref by its literal ref string, not by the commit it resolves
to. Measured in hyperpolymath/cicd-suite@31b5b45a, the lockfile contained:
'actions/checkout@v7.0.1':
ref: 'v7.0.1'
commit: 'sha1-3d3c42e5aac5ba805825da76410c181273ba90b1'
and the workflow contained:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Same commit, different spelling → references actions not present in the lockfile →
Invalid workflow file, startup death at 0s. Full write-up: hyperpolymath/cicd-suite#9.
Why this is worth checking estate-wide
The failure is invisible in every way we normally look:
jobs.total_count == 0, no job ever starts
conclusion reports failure, not startup_failure — so censusing on the label misses it
- the run is absent from the PR check rollup entirely, so the PR looks green, not red
- the reason is not in the REST API — it is only on the run page's
/workflow HTML partial
So a repo in this state looks configured and passing while running no gate at all. That is exactly
the fake-green class we have been hunting.
The check, if someone picks this up
For every repo containing .github/workflows/actions.lock: for each uses: ref in each workflow
named under the lock's workflows: map, assert the literal ref string is a key in dependencies:.
Set difference, no network needed beyond fetching the two files. A repo with a non-empty difference
is startup-dead on that workflow.
The rule regardless of the census outcome
In a repo carrying actions.lock, a uses: ref-spelling change and gh actions-lock
regeneration are one atomic commit. Worth adding to the pinning policy text, because the current
policy as written actively instructs the edit that breaks it.
Related: the same collision from the detector side in
codeql-unpinned-tag vs actions.lock.
Not chasing this now — filing so it is not lost.
Hypothesis, not a measurement
The 2026-09-08/09 pin campaign changed action ref spellings across ~1,598 refs in ~372 repos
(tag → 40-hex commit SHA). Separately, some estate repos carry
.github/workflows/actions.lock,generated by
gh actions-lock.These two things are incompatible unless done in the same commit, and the incompatibility is
silent.
The mechanism, measured
actions.lockresolves auses:ref by its literal ref string, not by the commit it resolvesto. Measured in
hyperpolymath/cicd-suite@31b5b45a, the lockfile contained:and the workflow contained:
Same commit, different spelling →
references actions not present in the lockfile→Invalid workflow file, startup death at 0s. Full write-up: hyperpolymath/cicd-suite#9.Why this is worth checking estate-wide
The failure is invisible in every way we normally look:
jobs.total_count == 0, no job ever startsconclusionreportsfailure, notstartup_failure— so censusing on the label misses it/workflowHTML partialSo a repo in this state looks configured and passing while running no gate at all. That is exactly
the fake-green class we have been hunting.
The check, if someone picks this up
For every repo containing
.github/workflows/actions.lock: for eachuses:ref in each workflownamed under the lock's
workflows:map, assert the literal ref string is a key independencies:.Set difference, no network needed beyond fetching the two files. A repo with a non-empty difference
is startup-dead on that workflow.
The rule regardless of the census outcome
In a repo carrying
actions.lock, auses:ref-spelling change andgh actions-lockregeneration are one atomic commit. Worth adding to the pinning policy text, because the current
policy as written actively instructs the edit that breaks it.
Related: the same collision from the detector side in
codeql-unpinned-tagvsactions.lock.Not chasing this now — filing so it is not lost.