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
tests/test_marker_contract.py::test_every_setup_micromamba_call_site_pins_the_binary
guards the binary version — it asserts every setup-micromamba call site declares its own micromamba-version and that all of them equal MICROMAMBA_PIN. It does not guard the action SHA in the uses: line, so the three call sites may sit on three different versions of
the action itself with CI fully green.
Nothing else is looking. No committed test asserts that a pinned action SHA agrees across call
sites: this module does read uses: values — _step_uses, and the attestation guards around it —
but for a different property, that one named step exists and can run in one named job, and f457c30a868e4760d3a6fcea5f25dc655b8edf39 appears nowhere under tests/. This repository also runs
neither actionlint nor zizmor as a committed check; zizmor is named only in a comment in .github/workflows/sidecar.yml.
The section banner above the guard already promises the property the guard does not deliver:
# --- setup-micromamba: one action version, one binary version, and Dependabot can see both ---
and the trap list under it names precisely this drift as the reason the section exists:
That is how .github/actions/setup-env sat on setup-micromamba v2 while packaging.yml and
release.yml were bumped to v3.0.0: the composite action was invisible to the bot.
Dependabot now sees both directories (that gap was closed), but it sees them through two github-actions entries in .github/dependabot.yml — group actions on directory: "/", which
for this ecosystem means .github/workflows plus a root-level action.yml, and group actions-composite on directories: ["/.github/actions/*"]. Two entries means two pull
requests, so the split re-appears for as long as only one of the pair has merged, and permanently
if one is closed or forgotten.
Codex raised it as a P2 on #446, against the setup-micromamba step in .github/workflows/packaging.yml: landing #446 without #445 would have left .github/actions/setup-env/action.yml on v3.1.0 while packaging.yml and release.yml ran v3.2.1.
Seven workflows consume that composite — uses: ./.github/actions/setup-env appears in ci.yml, schema-guard.yml, sidecar.yml, sidecar-measure.yml, deep.yml, deps-audit.yml and large-fixtures.yml, which between them provide required CI contexts — and nothing in the
repository would have said so.
Both pull requests did land together — #445 (491b603, the actions-composite group) and #446
(c16ffd2, the actions group) — so the tree is consistent. Verified at origin/mainb078f47:
all three call sites read `mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39
v3.2.1`. This issue is about the missing guard, not about a live mismatch, which is exactly
why every criterion below carries the mutation that makes it fail — a guard added against an
already-agreeing tree is green from its first commit whether or not it asserts anything.
Branch from a freshly fetched origin/main. A checkout predating #445/#446 sees ce51e99f4bb8a82ab7158c4dc59ef4634c59c4f9 # v3.1.0 at all three sites; that is still uniform, so
the demonstrations work, but the SHA quoted in the PR must be the one actually on the branch.
The existing helper's discovery glob is reusable; its extraction is not. _setup_micromamba_call_sites walks GITHUB_DIR.rglob("*.y*ml"), which already visits .github/actions/setup-env/action.yml as well as the two workflows — that half is free, and all 22
files the glob matches today parse cleanly as YAML mappings. What it does not do is survive
contact with a uses: line. It counts them with
and that expression carries both of the false-green modes this module's own _steps() docstring
records against the attestation guard (#319 — the first found by Codex, the second by CodeRabbit).
Measured against this exact expression:
input
counts
should count
- uses: mamba-org/setup-micromamba@<sha>
1
1
- uses: "mamba-org/setup-micromamba@<sha>" (quoted, and valid YAML)
0
1
the same uses: text inside a run: block scalar
1
0
A SHA assertion built on that extraction is blind to a call site written with quotes and credulous
about one that is only a line of shell. This module already settled the question — parse the
document — and the settled answer needs one adjustment before it can be reused here: _steps()
reads workflow.get("jobs"), and .github/actions/setup-env/action.yml has no jobs: key at all
(its top-level keys are name, description, inputs, runs), so _steps() and _step_uses
see none of the one call site this issue mostly exists for. Discovery has to read steps from
both jobs.*.steps and runs.steps. That is the trap to avoid: a guard that parses, looks correct,
passes review, and never sees the composite action — while len(call_sites) >= 3 keeps passing
because the text-based count is still what feeds it.
One thing a parse cannot do is see a comment — yaml.safe_load discards the trailing # v3.2.1
outright. So the tag-comment half is necessarily read from the file text, and what keeps that text
half honest is requiring its per-file count to equal the parsed call-site count: a comment pattern
that misses a spelling the parser found then fails loudly instead of quietly dropping a site.
The failure message should name the split-Dependabot-PR cause, since that is the situation a
contributor will actually be in when it fires.
On ADR-0064.tests/test_marker_contract.py is not one of "the agent test modules" the freeze
covers. It contains no reference to .agents/, claim.py or reaper.py; its subject is the
sidecar-marker collection glob and the .github/ pin and Dependabot-coverage contracts. The
agent-layer test modules are tests/test_claim.py, tests/test_reaper.py, tests/test_agent_contract_is_runnable.py, tests/test_agent_entry_points.py and tests/test_greptile_usage.py. Adding a guard here is ordinary test work, not a capability change
on a frozen layer.
Acceptance criteria
Superseded by the grooming block at the end of this issue, which is authoritative.
Scope and non-goals
In scope: tests/test_marker_contract.py only — _setup_micromamba_call_sites (its extraction,
not its glob), the setup-micromamba guard(s) in that section, the new unit test of the extraction,
and the section's header comment.
Out of scope:
bumping any action version;
generalising the guard to every repeated uses: SHA across all workflows (a bigger change with
its own false-positive questions — uses: SHAs are legitimately independent between different
actions);
anything about .github/dependabot.yml, whose directory coverage is already correct and already
guarded by test_dependabot_watches_every_composite_action and test_no_dependabot_glob_overlaps_the_workflows_directory;
the stale # v3.0.0 (node24). sentence that opens the narrative comment block above uses: mamba-org/setup-micromamba@ in .github/actions/setup-env/action.yml. It is a real
defect of the same family and the new guard cannot see it — the guard reads the trailing comment
on the uses: line, which correctly says # v3.2.1. It stays out for a measured reason: any edit
under .github/actions/setup-env/ matches the relevance pattern in .github/workflows/sidecar.yml
(the pattern='^(src/tether/idealize/|sidecar/|…|\.github/actions/setup-env/)' line), which flips
the required sidecar / parity context from a seconds-long pass into a full live run — git lfs pull, the sidecar lock restore, the pinned-tMAVEN install and the live fits — on an action that fix(ci): setup-micromamba failing intermittently on both OSes since the v3.2.1 bump #452 reports failing intermittently. That is a heavy, flaky price for a comment. It belongs with
the repository-wide uses: <action>@<40-hex> # <tag> resolver that chore(ci): agent-reaper pins two actions to SHAs its comments misname #437 already reserves for its
own issue, or in a comment-only issue of its own.
Size estimate
S — up to 150 added lines
The assertions themselves are a handful of lines. The band is set by the rest: converting the
extraction to a parse over two step containers, the unit test of that extraction with its four rows
(house style in this module is a 10–20-line docstring per test), the failure-message text and the
header comment.
Risk level
standard — the lane: Codex on the draft, then CodeRabbit
Does this need an architecture decision record?
no — no schema, dependency-isolation, architectural or scientifically consequential change.
Dependencies / blockers
none
Execution autonomy
agent-can-do-alone
Related work / file overlap
#445 and #446 (the Dependabot pair whose split surfaced this; both merged). #437 is the sibling
instance of the same family — a pin whose comment misnames it — and reserves the repository-wide
comment-resolves-to-tag check for a separate issue. Files: tests/test_marker_contract.py.
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.
Why it is agent-doable: the whole diff is one test module; the discovery glob already visits
every call site; no version is bumped and no third-party code changes.
Chosen design — one shared helper, and it parses._setup_micromamba_call_sites keeps its GITHUB_DIR.rglob("*.y*ml") walk and gains the uses: SHA and the trailing # v<X.Y.Z> tag
alongside the counts it already returns. Per-document extraction moves into a small function that
takes the document text, so it can be unit-tested directly instead of only through the file
system. Steps come from bothjobs.*.steps and runs.steps of the parsed document; the SHA
comes from the parsed step's uses value; the trailing tag comes from the file text, because a
parse discards comments; and the two are cross-checked by count. Do not add a second walk over .github/, and do not widen the guard to other actions. The micromamba-version half may
keep its existing text extraction — the only requirement on it is that its len(pins) != uses
comparison now compares against the parsed call-site count.
Review risk: low. Confined to tests/; the tree already satisfies the new assertions, so the
only way to know they assert anything is the mutation record required below.
Terminal condition: PR-ready handoff. No merge authority is granted here; a maintainer arms
the merge.
Acceptance criteria
_setup_micromamba_call_sites in tests/test_marker_contract.py additionally returns, per
file, the uses: action SHA and the trailing # v<X.Y.Z> tag comment for every call site it
finds, and it reads those call sites from the parsed document — steps taken from both jobs.*.steps and runs.steps, so .github/actions/setup-env/action.yml (top-level keys name, description, inputs, runs; no jobs:) is covered rather than silently skipped.
Discovery stays the existing GITHUB_DIR.rglob("*.y*ml") walk, so a fourth call site — in a
workflow or in a new .github/actions/*/action.yml — is covered without editing any file
list. No second walker is added.
A committed test exercises the extraction directly, on document text passed in, in the shape
of the existing test_the_anchor_guard_recognises_a_step_and_nothing_else. Four rows:
(a) a plain - uses: mamba-org/setup-micromamba@<40 hex> step counts once; (b) the quoted
spelling - uses: "mamba-org/setup-micromamba@<40 hex>" — valid YAML, and the exact form that
made the attestation guard false-green — counts once; (c) the same text inside a run: block
scalar counts zero; (d) a document whose only top-level keys are name and runs, with
the call site under runs.steps, counts once. Currently-failing demonstration, run and quoted in the PR: do it red-first, in two steps.
(i) Move today's expression — re.findall(r"^\s*(?:-\s*)?uses:\s*" + re.escape(SETUP_MICROMAMBA), text, re.M) — into the new
text-taking function unchanged, point the new test at it, and run: rows (b) and (c) are red.
Paste that output, then convert the function to the parse and paste it green. (ii) With the
parse in place, narrow its step lookup to jobs.*.steps only and confirm row (d) goes red;
paste that too, and revert. Those three reds are what distinguishes this from a guard that
parses, reviews cleanly, and still cannot see the composite action.
tests/test_marker_contract.py asserts that the set of uses: SHAs across all setup-micromamba call sites has exactly one element. The assertion may extend test_every_setup_micromamba_call_site_pins_the_binary or live in a sibling test in the same
section, but it must read the shared helper. Currently-failing demonstration, run and quoted in the PR: change the SHA in .github/actions/setup-env/action.yml — mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39
to the same action at 40 arbitrary hex digits — run the focused test, paste the red output,
revert. Repeat at one workflow call site (packaging.yml or release.yml) so both step
containers are shown to be covered. The composite is the load-bearing half: a jobs:-only
lookup stays green on that mutation, so a green run there is the signal that the guard is
blind.
The trailing # v<X.Y.Z> comment is asserted to agree across call sites as well, with no
"or the docstring says why not" alternative — no test decides a docstring. Currently-failing demonstration: change one site's # v3.2.1 to # v3.2.0, focused test
red, revert.
A call site whose uses: line carries no trailing # v… comment fails rather than being
silently skipped: the number of extracted tag comments per file must equal that file's parsed
call-site count, the same shape as the existing len(pins) != uses check. This is also what
keeps the text half and the parsed half from disagreeing in silence. Currently-failing demonstration: delete the trailing comment on one call site, focused test
red, revert. A pattern that only collects annotated lines would otherwise pass by dropping the
unannotated one.
The failure message for the SHA assertion names the cause a contributor will be in: the two
Dependabot pull requests — group actions for .github/workflows, group actions-composite
for /.github/actions/*, both entries in .github/dependabot.yml — must land together, and
one merged without the other splits the versions. git grep -n "land together" -- tests/test_marker_contract.py (or the wording actually chosen) locates it.
The section header comment above GITHUB_DIR — the block opening # --- setup-micromamba: one action version, one binary version, and Dependabot can see both ---
— records the action-SHA trap alongside the two it already numbers, and its closing sentence,
currently # These guards keep both closed: …, is rewritten so it covers the third trap rather
than the two it currently names.
Local gates green: pytest tests/test_marker_contract.py first, then 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.
The diff touches tests/test_marker_contract.py and nothing else: git diff --name-only origin/main...HEAD prints exactly that one path. Every mutation above is
local, reverted, and never committed — which is also what keeps .github/actions/setup-env/
out of the diff and the required sidecar / parity context off its full live run. In
particular no workflow, no composite action and no .github/dependabot.yml edit.
Ready condition: met; awaiting a fresh exact-scope marker.
Maintenance kind
test
Work requested
tests/test_marker_contract.py::test_every_setup_micromamba_call_site_pins_the_binaryguards the binary version — it asserts every
setup-micromambacall site declares its ownmicromamba-versionand that all of them equalMICROMAMBA_PIN. It does not guard theaction SHA in the
uses:line, so the three call sites may sit on three different versions ofthe action itself with CI fully green.
Nothing else is looking. No committed test asserts that a pinned action SHA agrees across call
sites: this module does read
uses:values —_step_uses, and the attestation guards around it —but for a different property, that one named step exists and can run in one named job, and
f457c30a868e4760d3a6fcea5f25dc655b8edf39appears nowhere undertests/. This repository also runsneither
actionlintnorzizmoras a committed check;zizmoris named only in a comment in.github/workflows/sidecar.yml.The section banner above the guard already promises the property the guard does not deliver:
and the trap list under it names precisely this drift as the reason the section exists:
Dependabot now sees both directories (that gap was closed), but it sees them through two
github-actionsentries in.github/dependabot.yml— groupactionsondirectory: "/", whichfor this ecosystem means
.github/workflowsplus a root-levelaction.yml, and groupactions-compositeondirectories: ["/.github/actions/*"]. Two entries means two pullrequests, so the split re-appears for as long as only one of the pair has merged, and permanently
if one is closed or forgotten.
Codex raised it as a
P2on #446, against thesetup-micromambastep in.github/workflows/packaging.yml: landing #446 without #445 would have left.github/actions/setup-env/action.ymlon v3.1.0 whilepackaging.ymlandrelease.ymlran v3.2.1.Seven workflows consume that composite —
uses: ./.github/actions/setup-envappears inci.yml,schema-guard.yml,sidecar.yml,sidecar-measure.yml,deep.yml,deps-audit.ymlandlarge-fixtures.yml, which between them provide required CI contexts — and nothing in therepository would have said so.
Both pull requests did land together — #445 (
491b603, theactions-compositegroup) and #446(
c16ffd2, theactionsgroup) — so the tree is consistent. Verified atorigin/mainb078f47:all three call sites read `mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39
v3.2.1`. This issue is about the missing guard, not about a live mismatch, which is exactly
why every criterion below carries the mutation that makes it fail — a guard added against an
already-agreeing tree is green from its first commit whether or not it asserts anything.
Branch from a freshly fetched
origin/main. A checkout predating #445/#446 seesce51e99f4bb8a82ab7158c4dc59ef4634c59c4f9 # v3.1.0at all three sites; that is still uniform, sothe demonstrations work, but the SHA quoted in the PR must be the one actually on the branch.
The existing helper's discovery glob is reusable; its extraction is not.
_setup_micromamba_call_siteswalksGITHUB_DIR.rglob("*.y*ml"), which already visits.github/actions/setup-env/action.ymlas well as the two workflows — that half is free, and all 22files the glob matches today parse cleanly as YAML mappings. What it does not do is survive
contact with a
uses:line. It counts them withand that expression carries both of the false-green modes this module's own
_steps()docstringrecords against the attestation guard (#319 — the first found by Codex, the second by CodeRabbit).
Measured against this exact expression:
- uses: mamba-org/setup-micromamba@<sha>- uses: "mamba-org/setup-micromamba@<sha>"(quoted, and valid YAML)uses:text inside arun:block scalarA SHA assertion built on that extraction is blind to a call site written with quotes and credulous
about one that is only a line of shell. This module already settled the question — parse the
document — and the settled answer needs one adjustment before it can be reused here:
_steps()reads
workflow.get("jobs"), and.github/actions/setup-env/action.ymlhas nojobs:key at all(its top-level keys are
name,description,inputs,runs), so_steps()and_step_usessee none of the one call site this issue mostly exists for. Discovery has to read steps from
both
jobs.*.stepsandruns.steps. That is the trap to avoid: a guard that parses, looks correct,passes review, and never sees the composite action — while
len(call_sites) >= 3keeps passingbecause the text-based count is still what feeds it.
One thing a parse cannot do is see a comment —
yaml.safe_loaddiscards the trailing# v3.2.1outright. So the tag-comment half is necessarily read from the file text, and what keeps that text
half honest is requiring its per-file count to equal the parsed call-site count: a comment pattern
that misses a spelling the parser found then fails loudly instead of quietly dropping a site.
The failure message should name the split-Dependabot-PR cause, since that is the situation a
contributor will actually be in when it fires.
On ADR-0064.
tests/test_marker_contract.pyis not one of "the agent test modules" the freezecovers. It contains no reference to
.agents/,claim.pyorreaper.py; its subject is thesidecar-marker collection glob and the
.github/pin and Dependabot-coverage contracts. Theagent-layer test modules are
tests/test_claim.py,tests/test_reaper.py,tests/test_agent_contract_is_runnable.py,tests/test_agent_entry_points.pyandtests/test_greptile_usage.py. Adding a guard here is ordinary test work, not a capability changeon a frozen layer.
Acceptance criteria
Superseded by the grooming block at the end of this issue, which is authoritative.
Scope and non-goals
In scope:
tests/test_marker_contract.pyonly —_setup_micromamba_call_sites(its extraction,not its glob), the
setup-micromambaguard(s) in that section, the new unit test of the extraction,and the section's header comment.
Out of scope:
uses:SHA across all workflows (a bigger change withits own false-positive questions —
uses:SHAs are legitimately independent between differentactions);
.github/dependabot.yml, whose directory coverage is already correct and alreadyguarded by
test_dependabot_watches_every_composite_actionandtest_no_dependabot_glob_overlaps_the_workflows_directory;# v3.0.0 (node24).sentence that opens the narrative comment block aboveuses: mamba-org/setup-micromamba@in.github/actions/setup-env/action.yml. It is a realdefect of the same family and the new guard cannot see it — the guard reads the trailing comment
on the
uses:line, which correctly says# v3.2.1. It stays out for a measured reason: any editunder
.github/actions/setup-env/matches the relevance pattern in.github/workflows/sidecar.yml(the
pattern='^(src/tether/idealize/|sidecar/|…|\.github/actions/setup-env/)'line), which flipsthe required
sidecar / paritycontext from a seconds-long pass into a full live run —git lfs pull, the sidecar lock restore, the pinned-tMAVEN install and the live fits — on an action thatfix(ci): setup-micromamba failing intermittently on both OSes since the v3.2.1 bump #452 reports failing intermittently. That is a heavy, flaky price for a comment. It belongs with
the repository-wide
uses: <action>@<40-hex> # <tag>resolver that chore(ci): agent-reaper pins two actions to SHAs its comments misname #437 already reserves for itsown issue, or in a comment-only issue of its own.
Size estimate
S — up to 150 added lines
The assertions themselves are a handful of lines. The band is set by the rest: converting the
extraction to a parse over two step containers, the unit test of that extraction with its four rows
(house style in this module is a 10–20-line docstring per test), the failure-message text and the
header comment.
Risk level
standard — the lane: Codex on the draft, then CodeRabbit
Does this need an architecture decision record?
no — no schema, dependency-isolation, architectural or scientifically consequential change.
Dependencies / blockers
none
Execution autonomy
agent-can-do-alone
Related work / file overlap
#445 and #446 (the Dependabot pair whose split surfaced this; both merged). #437 is the sibling
instance of the same family — a pin whose comment misnames it — and reserves the repository-wide
comment-resolves-to-tag check for a separate issue. Files:
tests/test_marker_contract.py.Target area
CI / repository governance
Milestone
none / cross-cutting
Required safety attestations
Grooming status — 2026-08-13
491b603; ci(deps): Bump the actions group with 3 updates #446 merged asc16ffd2.every call site; no version is bumped and no third-party code changes.
_setup_micromamba_call_siteskeeps itsGITHUB_DIR.rglob("*.y*ml")walk and gains theuses:SHA and the trailing# v<X.Y.Z>tagalongside the counts it already returns. Per-document extraction moves into a small function that
takes the document text, so it can be unit-tested directly instead of only through the file
system. Steps come from both
jobs.*.stepsandruns.stepsof the parsed document; the SHAcomes from the parsed step's
usesvalue; the trailing tag comes from the file text, because aparse discards comments; and the two are cross-checked by count. Do not add a second walk over
.github/, and do not widen the guard to other actions. Themicromamba-versionhalf maykeep its existing text extraction — the only requirement on it is that its
len(pins) != usescomparison now compares against the parsed call-site count.
tests/; the tree already satisfies the new assertions, so theonly way to know they assert anything is the mutation record required below.
the merge.
Acceptance criteria
_setup_micromamba_call_sitesintests/test_marker_contract.pyadditionally returns, perfile, the
uses:action SHA and the trailing# v<X.Y.Z>tag comment for every call site itfinds, and it reads those call sites from the parsed document — steps taken from both
jobs.*.stepsandruns.steps, so.github/actions/setup-env/action.yml(top-level keysname,description,inputs,runs; nojobs:) is covered rather than silently skipped.Discovery stays the existing
GITHUB_DIR.rglob("*.y*ml")walk, so a fourth call site — in aworkflow or in a new
.github/actions/*/action.yml— is covered without editing any filelist. No second walker is added.
A committed test exercises the extraction directly, on document text passed in, in the shape
of the existing
test_the_anchor_guard_recognises_a_step_and_nothing_else. Four rows:(a) a plain
- uses: mamba-org/setup-micromamba@<40 hex>step counts once; (b) the quotedspelling
- uses: "mamba-org/setup-micromamba@<40 hex>"— valid YAML, and the exact form thatmade the attestation guard false-green — counts once; (c) the same text inside a
run:blockscalar counts zero; (d) a document whose only top-level keys are
nameandruns, withthe call site under
runs.steps, counts once.Currently-failing demonstration, run and quoted in the PR: do it red-first, in two steps.
(i) Move today's expression —
re.findall(r"^\s*(?:-\s*)?uses:\s*" + re.escape(SETUP_MICROMAMBA), text, re.M)— into the newtext-taking function unchanged, point the new test at it, and run: rows (b) and (c) are red.
Paste that output, then convert the function to the parse and paste it green. (ii) With the
parse in place, narrow its step lookup to
jobs.*.stepsonly and confirm row (d) goes red;paste that too, and revert. Those three reds are what distinguishes this from a guard that
parses, reviews cleanly, and still cannot see the composite action.
tests/test_marker_contract.pyasserts that the set ofuses:SHAs across allsetup-micromambacall sites has exactly one element. The assertion may extendtest_every_setup_micromamba_call_site_pins_the_binaryor live in a sibling test in the samesection, but it must read the shared helper.
Currently-failing demonstration, run and quoted in the PR: change the SHA in
.github/actions/setup-env/action.yml—mamba-org/setup-micromamba@f457c30a868e4760d3a6fcea5f25dc655b8edf39to the same action at 40 arbitrary hex digits — run the focused test, paste the red output,
revert. Repeat at one workflow call site (
packaging.ymlorrelease.yml) so both stepcontainers are shown to be covered. The composite is the load-bearing half: a
jobs:-onlylookup stays green on that mutation, so a green run there is the signal that the guard is
blind.
The trailing
# v<X.Y.Z>comment is asserted to agree across call sites as well, with no"or the docstring says why not" alternative — no test decides a docstring.
Currently-failing demonstration: change one site's
# v3.2.1to# v3.2.0, focused testred, revert.
A call site whose
uses:line carries no trailing# v…comment fails rather than beingsilently skipped: the number of extracted tag comments per file must equal that file's parsed
call-site count, the same shape as the existing
len(pins) != usescheck. This is also whatkeeps the text half and the parsed half from disagreeing in silence.
Currently-failing demonstration: delete the trailing comment on one call site, focused test
red, revert. A pattern that only collects annotated lines would otherwise pass by dropping the
unannotated one.
The failure message for the SHA assertion names the cause a contributor will be in: the two
Dependabot pull requests — group
actionsfor.github/workflows, groupactions-compositefor
/.github/actions/*, both entries in.github/dependabot.yml— must land together, andone merged without the other splits the versions.
git grep -n "land together" -- tests/test_marker_contract.py(or the wording actually chosen) locates it.The section header comment above
GITHUB_DIR— the block opening# --- setup-micromamba: one action version, one binary version, and Dependabot can see both ---— records the action-SHA trap alongside the two it already numbers, and its closing sentence,
currently
# These guards keep both closed: …, is rewritten so it covers the third trap ratherthan the two it currently names.
Local gates green:
pytest tests/test_marker_contract.pyfirst, thenpre-commit run --all-filesand the test-matrix line for your lane fromAGENTS.md§Local gates beforereview. No docs or schema change, so
mkdocs build --strictandscripts/dump_schema.py --checkare not required — say so in the PR rather than leaving it ambiguous.The diff touches
tests/test_marker_contract.pyand nothing else:git diff --name-only origin/main...HEADprints exactly that one path. Every mutation above islocal, reverted, and never committed — which is also what keeps
.github/actions/setup-env/out of the diff and the required
sidecar / paritycontext off its full live run. Inparticular no workflow, no composite action and no
.github/dependabot.ymledit.Ready condition: met; awaiting a fresh exact-scope marker.