mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #318] [MERGED] test(bump-callers): assert the suite's own trigger covers every fleet paths: positive #320
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#320
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/318
Author: @mattmillerai
Created: 9/18/2026
Status: ✅ Merged
Merged: 9/19/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-15318-trigger-covers-fleet-positives📝 Commits (3)
c1c86fbtest(bump-callers): assert the suite's own trigger covers every fleetpaths:positive8c0c54etest(bump-callers): match the trigger-coverage probe the way Actions matchesf44200dMerge remote-tracking branch 'origin/main' into matt/be-15318-trigger-covers-fleet-positives📊 Changes
2 files changed (+326 additions, -30 deletions)
View changed files
📝
.github/bump-callers/README.md(+9 -10)📝
.github/bump-callers/tests/test_paths_contract.sh(+317 -20)📄 Description
ELI-5
This repo's
bump-*-callers.ymlfleets each watch a few directories. A test(
test_paths_contract.sh) walks those directories looking for one specificbooby-trap: a
!x/*_test.goexclusion behaves differently in a GitHub Actionspaths:filter than in agit diffpathspec the moment a matching file shows upone directory down.
That measurement only runs when this suite runs. So it is only useful if the
suite's own trigger fires on the PR that plants the booby-trap. It does today —
test-bump-callers.ymlwatches.github/**andscripts/**, two whole trees —but nothing asserted it, so the day a fleet starts watching something outside
those trees the measurement would quietly go blind and first speak up on some
unrelated later PR.
This adds that assertion, plus a fixture that proves it can actually fail.
What changed
test_paths_contract.shALL_POSITIVESaccumulates every fleet's positivepaths:entry verbatim,mirroring how
ALL_EXEC_ENTRIESis accumulated. It is appended before anyof the per-fleet checks can
continueout of the iteration — including thehas_preflightand empty-WATCHEDguards, which are themselves the mid-editcase: a fleet whose preflight inputs are mid-edit is still a fleet whose
surface the trigger has to cover. (
compare_pathspecsstill receives thenormalize_globedpositives; the two consumers no longer share one reducedform that suits neither.)
== this suite's trigger covers the paths it reads ==block runs those positives through the same match as the existing WATCHED_EXEC
pass:
ok: test-bump-callers.yml triggers on all 23 distinct fleetpaths:positivesbadnaming the count, a 4-entry sample, and the fix ("add the tree toBOTH
paths:lists in that workflow").only mean every entrypoint failed to parse.
uncovered_against_filter, used by bothpasses, and it matches the way Actions matches rather than leaning on the
shell's glob (see Review round below):
actions_glob_matchtranslates a filter entry to an anchored ERE —**→.*,*→[^/]*,?→[^/], every other regex metacharacter escaped literal —so a single
*stops at/the way an Actions filter does and bash's does not.coverage_probedecides what to match: anX/**entry names a TREE, and theproperty this pass claims is that a file DEEP inside it fires the trigger, so it
probes a synthetic descendant. A literal-file entry probes itself, which is what
the WATCHED_EXEC pass needs.
!entry actuallyexcludes and a later positive can re-include — Actions' own rule.
== trigger-coverage self-test ==section, in the style ofpathspec_case/guard_case— six cases, all driven throughparse_push_paths, the same parserthat reads the real files:
.github/bump-callers/**vs ascripts/x/**fleet →uncovered;scripts/*) vs ascripts/x/**fleet →uncovered(Actions'
*stops at/);scripts/**) →covered;!exclusion over the fleet's surface →uncovered;covered;covered.cover_caseguards a fixture whose FILTER parsed no patterns as vacuous, themirror of the existing guard on a fixture that parsed no positives — with an
empty filter every entry reports uncovered, so an
uncoveredcase wouldotherwise pass for the wrong reason.
uncovered_against_filter's exit status (commandsubstitution, not process substitution): a helper that aborted previously
emitted no lines, left
uncoveredempty and reported the passing verdict.pull_request/pushlist-identity check.parse_push_pathsis anchored to^ push:, so it is thepull_requestlistthat could drift out from under these passes, not the
pushone..github/bump-callers/README.md— one sentence recording that themeasurement's usefulness rests on the trigger:
test-bump-callers.ymlruns on anychange under
.github/**orscripts/**(#302), so the measurement fails the PRthat creates the divergence, and the contract test now asserts that filter
covers every fleet's positive
paths:entry.No
bump-*-callers.ymlis modified. No workflow file is modified.Corpus swept
All 13
bump-*-callers.ymlentrypoints, read as they ship:paths:entries!) entries — not covered by this checkThe 14 negatives are deliberately out of this assertion: an exclusion only ever
narrows a surface already listed as a positive, so covering the positive covers
it. They are named here because that is the half this PR does not measure.
Verification
bash .github/bump-callers/tests/test_paths_contract.sh→ 147 passed, 0 failedon bash 5.2.21, and 147 passed, 0 failed on bash 3.2.57 (run in a
bash:3.2container with the repo and its gitdir mounted and
gitinstalled into theimage — the suite's
git ls-filesprobe needs a git binary as well as bothmounts; without it 10 fleets fail the tracked-file check identically on this
branch and on its parent, which is the environment, not the diff).
implementation it replaced — checked by reverting each one in turn:
a depth-1 filter does not cover a tree fleetreportscovered, wantuncovered;a fleet watching exactly a filter tree root(uncovered, wantcovered, namingscripts/**) plus the exclusion case;!→a!exclusion in the filter uncovers the surface it removesreportscovered, wantuncovered;want=uncoveredcase pointed at apaths:-less workflow reportsokinstead of failing as vacuous;exit 9mid-loop → both live passes now emit the new"aborted rather than answering"
badwhere they previously reportedok.'.github/**'+'scripts/**'fromtest-bump-callers.yml, leaving the three entries the filter carried before#302 → the new message fires, naming the count and a 4-entry sample. The
workflow was restored afterwards; it is untouched in the diff.
shellcheck -xover the exact five filestest-bump-callers.ymllists → clean(SC2053 is no longer suppressed anywhere — the match is a regex now, not a glob).
test_bump_callers.sh437/0,test_preflight.sh445/0,test_paths_contract.sh147/0.python3 .github/agents-md-integrity/check_agents_md.py --root .→ passed(2 pre-existing warnings, unrelated).
python3 .github/workflow-pins/check_workflow_pins.py→ OK.Review round
The panel raised six findings on the first revision, all on the same gap: the new
pass claimed a deep file under a watched surface fires this suite, but
measured the surface ROOT against the filter using bash's own glob. All six
are fixed in
8c0c54e; each thread carries the specific fix and the fixture thatpins it.
*crosses/, an Actions filter's does not → ascripts/*filter reported every surface covered (false green)actions_glob_match+ descendantcoverage_probe!entries loaded as independent positives, so an exclusion matched nothing (false green)/**filter entries → a fleet on a filter tree root read uncovered (false red, with a remediation that stays red)ALL_POSITIVESverbatim +coverage_probecover_casedid not guard an empty FILTER, so anuncoveredfixture could pass for the wrong reasonALL_POSITIVESappend sat below two guards its own comment claimed it sat abovepaths:parseNothing was deferred; no follow-up ticket is proposed.
Judgment calls
uncovered_against_filterinstead of inlining a second copy ofthe loop. The task described an inline second pass. Two hand-copied match
loops are free to drift, and — more importantly — an inline loop is not
drivable from a fixture, so the new self-test could not exist. That is the
same reason
compare_pathspecswas extracted. The cost is that the difftouches lines #302 added. The review round made this load-bearing rather than
merely tidy: all six findings were fixed in the one helper, and both passes
got them.
fixture whose filter parsed no patterns — are not in the task text. They cost
a few lines each and close the one failure mode a coverage check must not
have: reporting the passing verdict because it measured nothing.
deliberately: without it the fixture only proves the helper can say
uncovered, and an implementation that saysuncoveredfor everything wouldpass it.
permissive-but-safe shortcut. The first revision matched with bash's glob and
argued the permissiveness was safe "for
**prefixes — the only shape usedhere". That argument is true of today's filter and is exactly the kind that
stops being true silently, which is the failure this whole check exists to
prevent.
actions_glob_matchis ~15 lines and removes the caveat instead ofdocumenting it; it is deliberately limited to the three wildcards Actions'
filter syntax defines, and every other metacharacter is escaped literal.
Residual
The README paragraph this work was supposed to delete is not on
mainyet, sothis PR could not delete it. The plan behind this change had two parts, and one
of them assumed a base that does not exist yet:
One caveat on "the day it becomes true": the measurement runs when …— which describes the old three-entry filter and isfalse now that #302 has landed — is added by PR #308, which is still
open at the time of writing.
maindoes not contain it, so there wasnothing to remove. What this PR does instead is write the replacement
statement (the trigger + the new assertion) into the same paragraph on
main.#308 and this PR merges second will hit a conflict on those exact README lines
— resolve it by keeping #308's three "scope of the measurement" bullets and
this PR's trigger sentence, and dropping the caveat paragraph entirely. If #308
merges without that resolution,
maincarries both a paragraph saying themeasurement can miss the divergence PR and a sentence saying it cannot; the
first is the false one.
miss the divergence PR" is satisfied on
mainas it stands but notguaranteed after #308 merges, and that is the single piece of this work left
undone.
Unexercised artifacts.
main(f22ad8f), not againstmain+ #308. The contract-test half does notoverlap #308's hunks (it adds a function above
# --- the contract ---, aself-test section, and a pass inside the trigger-coverage block; #308 edits the
fleet loop's exclusion branch and appends a
guardfixture section), so noconflict is expected there — but that is read off the two diffs, not measured
against a merged tree.
~5,000 lines of
main, so a stacked PR would have shown six unrelated mergedPRs in its own diff, and the
self_filterblock this change extends does notexist on it at all.
Capability-denial check. This diff adds no capability-denying path — no
"unsupported"/"unavailable" string, no throw, no test flipped to assert a
dead-end. The two new
badbranches are test-failure diagnostics that name thefix ("add the tree to BOTH
paths:lists"), and both were driven to fire againsta real narrowed filter rather than only asserted in prose.
Provenance
test_paths_contract.sh147 passed / 0 failed on bash 5.2.21 and on bash 3.2.57 (container withgitinstalled; without a git binary 10 fleets fail the tracked-file probe identically on this branch and its parent); each of the six review fixes driven to fail against the implementation it replaced; narrowed-filter negative run carries the new message;test_bump_callers.sh437/0;test_preflight.sh445/0;shellcheck -xclean over the five files the CI job lists;check_agents_md.py --root .passed;check_workflow_pins.pyOKmain; see## Residual. The## Corpus sweptcounts (25 entries / 23 distinct / 57 WATCHED_EXEC) were re-measured after the review round and are unchanged; the entries are now carried verbatim rather thannormalize_globed, which did not alter the distinct count.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.