mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #106] [MERGED] feat(agents-md-integrity): add exclude_paths for payload subtrees (BE-6009) #117
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#117
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/106
Author: @mattmillerai
Created: 8/2/2026
Status: ✅ Merged
Merged: 8/4/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-6009-agents-md-exclude-paths📝 Commits (2)
f465dc0feat(agents-md-integrity): add exclude_paths for payload subtrees (BE-6009)825c487fix(agents-md-integrity): harden --exclude glob semantics from review (BE-6009)📊 Changes
6 files changed (+724 additions, -19 deletions)
View changed files
📝
.github/agents-md-integrity/README.md(+49 -1)📝
.github/agents-md-integrity/check_agents_md.py(+270 -16)📝
.github/agents-md-integrity/tests/test_check_agents_md.py(+311 -0)📝
.github/workflows/agents-md-integrity.yml(+40 -1)📝
.github/workflows/test-agents-md-integrity.yml(+53 -0)📝
README.md(+1 -1)📄 Description
ELI-5
The AGENTS.md checker has a rule: "every
AGENTS.mdin a subfolder needs a one-lineCLAUDE.mdnext to it that just says@AGENTS.md." That's right for a monorepo. It's wrong for a repo whose product is agent instructions — a plugin marketplace publishesplugins/<name>/AGENTS.mdnext to a real, multi-lineCLAUDE.mdas the thing it ships to consumers, and rewriting that sibling into a shim would corrupt the published plugin. Until now the only escape wascheck_nested: false, which turns the rule off for the entire repo. This PR adds a scalpel:exclude_paths: plugins/**carves out just that subtree, prints exactly what it skipped, and refuses to let anyone exclude the root files.What changed
.github/workflows/agents-md-integrity.ymlgains an optionalexclude_pathsinput (newline- or comma-separated globs, default empty), plumbed tocheck_agents_md.pyas a repeatable/CSV--excludeflag. Per the ticket's four constraints:os.walkand skip directly-matched files before they're read, so an excluded subtree is never opened or line-counted (test_excluded_subtree_is_never_line_countedputs a 500-lineAGENTS.mdin an excluded dir and asserts the ceiling never fires).SKIP_DIRSbaseline still applies alongside--exclude.EXCLUDED: <path> (matched <glob>)plus a::notice::annotation, followed by a count line; the configured globs are echoed too, so a typo'd glob that matches nothing still leaves a trace. An exclusion nobody can see in the log is the failure mode this ticket exists to prevent.CLAUDE.md(**,*,*.md,AGENTS.md,**/CLAUDE.md,/AGENTS.md, …) raisesExcludeConfigErrorand exits 2 (0 = pass, 1 = a check failed). Validated unconditionally — even withcheck_nested: false, where the globs would never be consulted.Glob semantics are deliberately narrower than the CODEOWNERS translation already in the file: always repo-root-relative (no match-the-basename-at-any-depth magic, which is how a glob silently deletes coverage nobody asked to drop),
*/?stay inside a path segment,**crosses segments, a leading**/means "at any depth", and a glob matching a directory excludes the subtree beneath it.Also documented in the reusable's header,
.github/agents-md-integrity/README.md, and the root README catalog row.Verification
python3 -m unittest discover -s .github/agents-md-integrity/tests— 40 passed (19 pre-existing, unchanged, plus 21 new).test-agents-md-integrity.yml— a payload repo that fails without--exclude, passes withplugins/**, and must show theEXCLUDED:line; and a root-excluding glob that must exit 2. Both were run locally verbatim underbash -e.AGENTS.mdstill passes the checker (exit 0).Covering the ticket's four required cases: excluded nested pair passes (
test_excluded_nested_pair_passes), non-excluded nested pair still fails in the same run (test_non_excluded_nested_pair_still_fails), root exclusion errors out (test_exclusion_targeting_root_errors_out, six globs), and no--excludereproduces today's behavior exactly (test_no_exclude_reproduces_todays_behavior, plustest_cli_without_exclude_fails_the_same_payload).Backwards compatibility
exclude_pathsdefaults to'', and the run step adds--excludeonly when the value is non-blank, so every currently-registered caller invokes the identical command line. With an empty glob list the walk takes the same code path it always did.Two internal changes worth a reviewer's eye:
run_checks()now returns a 3-tuple(failures, warnings, exclusions), and_iter_nested_agents()became_scan_nested_agents()returning lists. Both are module-internal — the only callers aremain()and the test suite, and the CLI contract is unchanged, which is what external consumers (including the comfy-infra sweep, which shells out with--root) actually depend on.Judgment calls
check_nestedisfalsenow emit a warning that they exclude nothing. Both knobs set together is precisely the invisible-coverage-loss shape this ticket exists to replace, and it would otherwise read as "scoped" when nested checking is off repo-wide.EXCLUDED:line names the pruned directory (e.g.plugins/comfy-conventions), not each buried file — a file inside a pruned directory is never discovered, which is the point of constraint 3. A repo with 30 plugins therefore logs 30 lines; that visible cost is intentional.EXCLUDE_PATHSenv fallback for--exclude, to keep exactly one way to pass exclusions. Every other knob is env-driven; this one is CLI-only, as the ticket specified.check_nested/require_shimremain available for the cases they're actually for.Out of scope here — the ticket's other two repos
The ticket's remaining items land in different repos, so they are not in this PR (this loop is single-repo per PR):
Comfy-Org/comfy-conventions— setexclude_paths: |/plugins/**on its caller once this merges and a SHA is available (unblocks BE-5923).Comfy-Org/comfy-infra→agents-md-hygiene.yml— the daily org-wide sweep passes only--root, so it will still report comfy-conventions as non-conformant regardless of that repo's own caller. It needs a per-repo path-exclusion map (or to read each caller'sexclude_paths) so the gate and the radar agree. This PR provides the mechanism the sweep needs —--excludeis the same flag, on the same pinned checker — but does not wire it up, so acceptance criterion 3 ("the daily sweep reaches the same verdict") is not met by this PR alone. Per BE-3532's amendment, the sweep must reuse this exclusion implementation rather than growing a second one.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.