You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
.github/workflows/agent-reaper.yml pins two third-party actions to SHAs that its own trailing
comments misname. One comment is merely wrong; the other hides the fact that the reaper runs an
untagged commit from December 2023.
Every upstream claim below was re-resolved online on 2026-08-13 with git ls-remote --tags <upstream-url>, and every repository-internal count was read from origin/main at b078f47. Read them from a freshly fetched origin/main: a checkout predating #434 has no .github/workflows/wiki.yml and therefore counts 19 where this issue says 20.
1. actions/checkout — the comment is wrong, the SHA is right.
That SHA is tagged v7 and v7.0.1 upstream — git ls-remote --tags https://github.com/actions/checkout prints both refs at it; the commit subject is prep v7.0.1 release (upstream pull request 2531), dated 2026-07-17. The pin itself is current and
correct. The label is not, and it is wrong in exactly one place: the repository uses this same SHA 21 times across .github/workflows/, and the other 20 all label it # v7.0.1 — ci.yml
×6, release.yml ×3, deep-gpu.yml, deep.yml, deps-audit.yml, docs.yml, large-fixtures.yml, packaging.yml, schema-guard.yml, scorecard.yml, sidecar-measure.yml, sidecar.yml, wiki.yml. So the repository contradicts itself about one SHA, and agent-reaper.yml is the sole outlier.
That comment has never named its SHA correctly, and the real v5.0.1 is not involved at any point. # v5.0.1 entered the file when it was created — c74cdb5 (#276, 2026-07-29) — annotating 9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0, which upstream is refs/tags/v7.0.0. The actual v5.0.1 is 93cb6efe18208431cddfb8368fd83d5badbf9bfd and appears nowhere in .github/.
2. actions/setup-python — the SHA matches no release at all.
No tag in actions/setup-python points at that SHA — it appears in no git ls-remote --tags
line for that repository. It is a commit of 2023-12-14 whose subject is Replace setup-python@v4 by setup-python@v5 in README (upstream pull request 776) — a README edit, not a release. Real v5.4.0 is 42375524e23c412d93fb67b49958b491fce71c38. Meanwhile every othersetup-python pin in
the repository — six of them, in ci.yml ×4, deep-gpu.yml and docs.yml — is 5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0, and that SHA does carry v7 and v7.0.0
upstream. The reaper is the only workflow still on the old commit, and its comment asserts a pinned
release that is not what it runs.
Dependabot will not repair the label, and the record shows why.agent-reaper.yml sits in .github/workflows, which is inside the directory: "/" scope of the github-actions entry in .github/dependabot.yml, and there is no ignore entry anywhere in that file — so the bot does
reach this file, and it has: the grouped actions pull request that merged as 87da5b7 (#398,
2026-08-07) bumped this very pin from 9c091bb2… to 3d3c42e5… and carried the # v5.0.1
comment across untouched, while in the same commit updating scorecard.yml's github/codeql-action/upload-sarif comment from # v4.37.3 to # v4.37.4. A bump therefore
advances the SHA and leaves the label as it found it, which is exactly how this line came to
misname what it runs. Nothing about the setup-python pin is explained by Dependabot behaviour
either way: it has not moved since the file was created, 5fda3b95… # v7.0.0 reached the six
sibling call sites in #254 (2053241, 2026-07-29) which merged before this file existed, and
neither grouped actions pull request since (#398, #446) has touched setup-python anywhere. Both
lines need a hand.
Why this matters here specifically.agent-reaper.yml is the only thing that reclaims dead
claim refs (AGENTS.md §Concurrent GitHub Flow: "the scheduled reaper … is the only thing that
may"). It runs unattended on a schedule with contents: write and issues: write, and nobody
watches it the way a PR check gets watched. A reviewer reading the file cannot tell what is actually
executing, because the comment is the only human-readable statement of the version and it is false
in both lines.
This is a hygiene and accuracy defect, not a vulnerability. SHA pinning is the secure practice
and it is intact — both pins are immutable and resolve, so there is no injection or tag-move
exposure and no reason for the private advisory flow. What is broken is that the labels cannot be
trusted, and that one pin is over two and a half years stale relative to the rest of the repository.
Acceptance criteria
Superseded by the grooming block at the end of this issue, which is authoritative.
Scope and non-goals
In scope: .github/workflows/agent-reaper.yml only — two lines, no logic change, no permissions
change, no change to the sweep behaviour and no change to .agents/bin/reaper.py.
Out of scope: every other workflow (all already correct, re-verified in the sweep that found this
and again on 2026-08-13); any other dependency bump; and a repository-wide check that every uses: <action>@<40-hex> # <tag> comment resolves to that tag — that is the durable fix for the
class rather than the instance, but it is a new CI job or test and belongs in its own issue rather
than being absorbed here. #448 is the narrow, already-filed member of that family (one action, one
guard).
Size estimate
XS — up to 50 added lines
Risk level
high — the lane, and a Greptile credit is worth spending if the seat has budget
Stated as high because the form's own guidance puts CI and dependency changes there, and because
criterion 2 genuinely changes which third-party code executes in a scheduled workflow that holds contents: write. The diff is two lines; the scrutiny is for what those two lines run, not for
their size.
Does this need an architecture decision record?
no — a pin correction inside an existing workflow; no schema, dependency-isolation, architectural or
scientifically consequential choice.
Dependencies / blockers
none
Execution autonomy
agent-can-do-alone
Related work / file overlap
Found while finishing #189 / #434 and deliberately not absorbed into it, per AGENTS.md §Outcome
and authority ("Do not absorb unrelated discoveries"). No file overlap with #434, which touched wiki/Home.md and .github/workflows/wiki.yml only. #448 is the sibling issue on the same defect
family. Duplicate search returned nothing for setup-python pin, action pin SHA, agent-reaper, checkout v5.0.1 and pinned action version comment across open and closed issues.
Target area
CI / repository governance
Milestone
none / cross-cutting
Required safety attestations
I searched existing issues and this is not a duplicate.
I am not reporting a vulnerability publicly; security reports use the private advisory flow.
I included no secrets or private, raw, unlicensed, user, or lab data.
Grooming status — 2026-08-13
Status: unblocked.
Open dependencies: none.
Autonomy: agent-can-do-alone.
Why it is agent-doable: both target versions are determinable from the upstream repositories
with git ls-remote --tags, the edit is two lines, and the verification is a dry-run workflow_dispatch the agent can trigger. No new version is chosen — criterion 2 adopts the value
six other pins in this repository already carry.
Chosen design: keep the actions/checkout SHA and fix only its label; move actions/setup-python onto 5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0, the repository's
existing consensus pin, rather than onto real v5.4.0. That makes all seven setup-python pins
agree and puts the reaper on the same code four ci.yml jobs and docs.yml already run.
Counting note — do not use git grep -c for the before/after numbers below. It prints one path:count line per matching file (13 of them for the actions/checkout pattern), never the
total, and at zero matches it prints nothing and exits 1. Use a form that emits the number, and -F since every pattern here is a fixed string:
Review risk: high. Two lines, but one of them changes which third-party code executes in a
scheduled workflow holding contents: write and issues: write. Spend a Greptile credit if the
seat has budget (read the balance first with <py> .agents/bin/greptile_usage.py).
Terminal condition: PR-ready handoff. No merge authority is granted here; a maintainer arms
the merge.
Acceptance criteria
The actions/checkout line in .github/workflows/agent-reaper.yml keeps SHA 3d3c42e5aac5ba805825da76410c181273ba90b1 unchanged and its trailing comment reads # v7.0.1.
Counted with the command form above, over -- .github/: 3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.1 is 1 today and 0 after, and 3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 is 20 today and 21 after.
actions/setup-python in that workflow is pinned to 5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0. Counted the same way: actions/setup-python@e9d6f990972a57673cdb72ec29e19d42ba28880f is 1 today and 0 after; actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 goes from 6 to 7.
Both post-edit SHAs are re-resolved against the upstream repositories and the resolved tag is
quoted in the PR, so the fix is verified rather than asserted. git ls-remote --tags https://github.com/actions/checkout must print refs/tags/v7.0.1 at 3d3c42e5aac5ba805825da76410c181273ba90b1, and git ls-remote --tags https://github.com/actions/setup-python must print refs/tags/v7.0.0 at 5fda3b95a4ea91299a34e894583c3862153e4b97. Filter with | grep <sha> in WSL bash or | Select-String <sha> in native PowerShell. A comment may name only a tag one of those
commands actually printed. Do not soften this to "it matches what the other 20 files say" —
the repository agreeing with itself is exactly how a 21st wrong label gets written, and ci(deps): Bump the actions group with 2 updates #398
shows a bump carrying a wrong label forward untouched.
The new setup-python pin is shown to serve python-version: "3.12" from inside this
repository, not by appeal to upstream release notes: git grep -A3 -F "actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97" -- .github/
shows python-version: "3.12" under all six existing call sites, four of which are ci.yml
jobs behind required contexts. Quote that in the PR.
The reaper still works on the new setup-python: a dry-runworkflow_dispatch run of agent-reaper.ymlon the agent's own branch is green and its run URL is linked in the PR. gh workflow run agent-reaper.yml --ref agent/issue-437 -f dry_run=true — which resolves only
after agent/issue-437 has been pushed to origin, so push first. This is the only pre-merge
exercise available: the schedule trigger only ever runs the default branch, so a post-merge
green sweep is not evidence for the PR. A dry_run=true dispatch is authorized here and
mutates nothing — the workflow's step runs python .agents/bin/reaper.py --dry-run (not claim.py), which reports only; workflow_dispatch.inputs.dry_run already defaults to true
and the step's DRY_RUN is ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }},
so leaving the input alone is the read-only path. Never dispatch it with dry_run=false: a
live sweep deletes claim refs, and AGENTS.md reserves that to the schedule. The workflow's concurrency group is agent-reaper with cancel-in-progress: false, so the run may queue
behind a scheduled sweep — read its conclusion before quoting it, and quote the conclusion, not
the fact that it started.
If the dispatch cannot be performed — the operator's permission layer refuses it, or the run
cannot be read — say exactly that in the PR in those words and hand off. Do not imply the run
happened, and do not substitute a static assertion for it.
The change is confined: git diff --name-only origin/main...HEAD prints exactly .github/workflows/agent-reaper.yml, and the diff of that file touches only the two uses:
lines' trailing comment and SHA. No permissions: block change, no concurrency change, no
sweep-behaviour change, no .agents/bin/reaper.py change, no other workflow.
Local gates green: pre-commit run --all-files and the test-matrix line for your lane from AGENTS.md §Local gates before review. No docs or schema change, so mkdocs build --strict
and scripts/dump_schema.py --check are not required — say so in the PR rather than leaving it
ambiguous.
Ready condition: met; awaiting a fresh exact-scope marker.
Maintenance kind
CI
Work requested
.github/workflows/agent-reaper.ymlpins two third-party actions to SHAs that its own trailingcomments misname. One comment is merely wrong; the other hides the fact that the reaper runs an
untagged commit from December 2023.
Every upstream claim below was re-resolved online on 2026-08-13 with
git ls-remote --tags <upstream-url>, and every repository-internal count was read fromorigin/mainatb078f47. Read them from a freshly fetchedorigin/main: a checkout predating#434 has no
.github/workflows/wiki.ymland therefore counts 19 where this issue says 20.1.
actions/checkout— the comment is wrong, the SHA is right.That SHA is tagged
v7andv7.0.1upstream —git ls-remote --tags https://github.com/actions/checkoutprints both refs at it; the commit subject isprep v7.0.1 release(upstream pull request 2531), dated 2026-07-17. The pin itself is current andcorrect. The label is not, and it is wrong in exactly one place: the repository uses this same SHA
21 times across
.github/workflows/, and the other 20 all label it# v7.0.1—ci.yml×6,
release.yml×3,deep-gpu.yml,deep.yml,deps-audit.yml,docs.yml,large-fixtures.yml,packaging.yml,schema-guard.yml,scorecard.yml,sidecar-measure.yml,sidecar.yml,wiki.yml. So the repository contradicts itself about one SHA, andagent-reaper.ymlis the sole outlier.That comment has never named its SHA correctly, and the real
v5.0.1is not involved at any point.# v5.0.1entered the file when it was created —c74cdb5(#276, 2026-07-29) — annotating9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0, which upstream isrefs/tags/v7.0.0. The actualv5.0.1is93cb6efe18208431cddfb8368fd83d5badbf9bfdand appears nowhere in.github/.2.
actions/setup-python— the SHA matches no release at all.No tag in
actions/setup-pythonpoints at that SHA — it appears in nogit ls-remote --tagsline for that repository. It is a commit of 2023-12-14 whose subject is
Replace setup-python@v4 by setup-python@v5 in README(upstream pull request 776) — a README edit, not a release. Realv5.4.0is42375524e23c412d93fb67b49958b491fce71c38. Meanwhile every othersetup-pythonpin inthe repository — six of them, in
ci.yml×4,deep-gpu.ymlanddocs.yml— is5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0, and that SHA does carryv7andv7.0.0upstream. The reaper is the only workflow still on the old commit, and its comment asserts a pinned
release that is not what it runs.
Dependabot will not repair the label, and the record shows why.
agent-reaper.ymlsits in.github/workflows, which is inside thedirectory: "/"scope of thegithub-actionsentry in.github/dependabot.yml, and there is noignoreentry anywhere in that file — so the bot doesreach this file, and it has: the grouped
actionspull request that merged as87da5b7(#398,2026-08-07) bumped this very pin from
9c091bb2…to3d3c42e5…and carried the# v5.0.1comment across untouched, while in the same commit updating
scorecard.yml'sgithub/codeql-action/upload-sarifcomment from# v4.37.3to# v4.37.4. A bump thereforeadvances the SHA and leaves the label as it found it, which is exactly how this line came to
misname what it runs. Nothing about the
setup-pythonpin is explained by Dependabot behavioureither way: it has not moved since the file was created,
5fda3b95… # v7.0.0reached the sixsibling call sites in #254 (
2053241, 2026-07-29) which merged before this file existed, andneither grouped
actionspull request since (#398, #446) has touchedsetup-pythonanywhere. Bothlines need a hand.
Why this matters here specifically.
agent-reaper.ymlis the only thing that reclaims deadclaim refs (
AGENTS.md§Concurrent GitHub Flow: "the scheduled reaper … is the only thing thatmay"). It runs unattended on a schedule with
contents: writeandissues: write, and nobodywatches it the way a PR check gets watched. A reviewer reading the file cannot tell what is actually
executing, because the comment is the only human-readable statement of the version and it is false
in both lines.
This is a hygiene and accuracy defect, not a vulnerability. SHA pinning is the secure practice
and it is intact — both pins are immutable and resolve, so there is no injection or tag-move
exposure and no reason for the private advisory flow. What is broken is that the labels cannot be
trusted, and that one pin is over two and a half years stale relative to the rest of the repository.
Acceptance criteria
Superseded by the grooming block at the end of this issue, which is authoritative.
Scope and non-goals
In scope:
.github/workflows/agent-reaper.ymlonly — two lines, no logic change, no permissionschange, no change to the sweep behaviour and no change to
.agents/bin/reaper.py.Out of scope: every other workflow (all already correct, re-verified in the sweep that found this
and again on 2026-08-13); any other dependency bump; and a repository-wide check that every
uses: <action>@<40-hex> # <tag>comment resolves to that tag — that is the durable fix for theclass rather than the instance, but it is a new CI job or test and belongs in its own issue rather
than being absorbed here. #448 is the narrow, already-filed member of that family (one action, one
guard).
Size estimate
XS — up to 50 added lines
Risk level
high — the lane, and a Greptile credit is worth spending if the seat has budget
Stated as
highbecause the form's own guidance puts CI and dependency changes there, and becausecriterion 2 genuinely changes which third-party code executes in a scheduled workflow that holds
contents: write. The diff is two lines; the scrutiny is for what those two lines run, not fortheir size.
Does this need an architecture decision record?
no — a pin correction inside an existing workflow; no schema, dependency-isolation, architectural or
scientifically consequential choice.
Dependencies / blockers
none
Execution autonomy
agent-can-do-alone
Related work / file overlap
Found while finishing #189 / #434 and deliberately not absorbed into it, per
AGENTS.md§Outcomeand authority ("Do not absorb unrelated discoveries"). No file overlap with #434, which touched
wiki/Home.mdand.github/workflows/wiki.ymlonly. #448 is the sibling issue on the same defectfamily. Duplicate search returned nothing for
setup-python pin,action pin SHA,agent-reaper,checkout v5.0.1andpinned action version commentacross open and closed issues.Target area
CI / repository governance
Milestone
none / cross-cutting
Required safety attestations
Grooming status — 2026-08-13
with
git ls-remote --tags, the edit is two lines, and the verification is a dry-runworkflow_dispatchthe agent can trigger. No new version is chosen — criterion 2 adopts the valuesix other pins in this repository already carry.
actions/checkoutSHA and fix only its label; moveactions/setup-pythononto5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0, the repository'sexisting consensus pin, rather than onto real
v5.4.0. That makes all sevensetup-pythonpinsagree and puts the reaper on the same code four
ci.ymljobs anddocs.ymlalready run.git grep -cfor the before/after numbers below. It prints onepath:countline per matching file (13 of them for theactions/checkoutpattern), never thetotal, and at zero matches it prints nothing and exits 1. Use a form that emits the number, and
-Fsince every pattern here is a fixed string:git grep -o -F "<pattern>" -- .github/ | wc -l(git grep -o -F "<pattern>" -- .github/ | Measure-Object -Line).Linesscheduled workflow holding
contents: writeandissues: write. Spend a Greptile credit if theseat has budget (read the balance first with
<py> .agents/bin/greptile_usage.py).the merge.
Acceptance criteria
The
actions/checkoutline in.github/workflows/agent-reaper.ymlkeeps SHA3d3c42e5aac5ba805825da76410c181273ba90b1unchanged and its trailing comment reads# v7.0.1.Counted with the command form above, over
-- .github/:3d3c42e5aac5ba805825da76410c181273ba90b1 # v5.0.1is 1 today and 0 after, and3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1is 20 today and 21 after.actions/setup-pythonin that workflow is pinned to5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0. Counted the same way:actions/setup-python@e9d6f990972a57673cdb72ec29e19d42ba28880fis 1 today and 0 after;actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0goes from 6 to7.
Both post-edit SHAs are re-resolved against the upstream repositories and the resolved tag is
quoted in the PR, so the fix is verified rather than asserted.
git ls-remote --tags https://github.com/actions/checkoutmust printrefs/tags/v7.0.1at3d3c42e5aac5ba805825da76410c181273ba90b1, andgit ls-remote --tags https://github.com/actions/setup-pythonmust printrefs/tags/v7.0.0at5fda3b95a4ea91299a34e894583c3862153e4b97. Filter with| grep <sha>in WSL bash or| Select-String <sha>in native PowerShell. A comment may name only a tag one of thosecommands actually printed. Do not soften this to "it matches what the other 20 files say" —
the repository agreeing with itself is exactly how a 21st wrong label gets written, and ci(deps): Bump the actions group with 2 updates #398
shows a bump carrying a wrong label forward untouched.
The new
setup-pythonpin is shown to servepython-version: "3.12"from inside thisrepository, not by appeal to upstream release notes:
git grep -A3 -F "actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97" -- .github/shows
python-version: "3.12"under all six existing call sites, four of which areci.ymljobs behind required contexts. Quote that in the PR.
The reaper still works on the new
setup-python: a dry-runworkflow_dispatchrun ofagent-reaper.ymlon the agent's own branch is green and its run URL is linked in the PR.gh workflow run agent-reaper.yml --ref agent/issue-437 -f dry_run=true— which resolves onlyafter
agent/issue-437has been pushed toorigin, so push first. This is the only pre-mergeexercise available: the
scheduletrigger only ever runs the default branch, so a post-mergegreen sweep is not evidence for the PR. A
dry_run=truedispatch is authorized here andmutates nothing — the workflow's step runs
python .agents/bin/reaper.py --dry-run(notclaim.py), which reports only;workflow_dispatch.inputs.dry_runalready defaults totrueand the step's
DRY_RUNis${{ github.event_name == 'workflow_dispatch' && inputs.dry_run }},so leaving the input alone is the read-only path. Never dispatch it with
dry_run=false: alive sweep deletes claim refs, and
AGENTS.mdreserves that to the schedule. The workflow'sconcurrencygroup isagent-reaperwithcancel-in-progress: false, so the run may queuebehind a scheduled sweep — read its conclusion before quoting it, and quote the conclusion, not
the fact that it started.
If the dispatch cannot be performed — the operator's permission layer refuses it, or the run
cannot be read — say exactly that in the PR in those words and hand off. Do not imply the run
happened, and do not substitute a static assertion for it.
The change is confined:
git diff --name-only origin/main...HEADprints exactly.github/workflows/agent-reaper.yml, and the diff of that file touches only the twouses:lines' trailing comment and SHA. No
permissions:block change, noconcurrencychange, nosweep-behaviour change, no
.agents/bin/reaper.pychange, no other workflow.Local gates green:
pre-commit run --all-filesand the test-matrix line for your lane fromAGENTS.md§Local gates before review. No docs or schema change, somkdocs build --strictand
scripts/dump_schema.py --checkare not required — say so in the PR rather than leaving itambiguous.
Ready condition: met; awaiting a fresh exact-scope marker.