mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #55] [MERGED] feat(groom): opt-in auto-builder — top-N CONFIRMED findings become review-gated PRs (BE-4003) #65
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#65
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/55
Author: @mattmillerai
Created: 7/22/2026
Status: ✅ Merged
Merged: 7/22/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-4003-groom-auto-builder📝 Commits (3)
8173fc2feat(groom): opt-in auto-builder — top-N CONFIRMED findings become review-gated PRs (BE-4003)2052e70fix(groom): least-privilege bot tokens, normalize pr_size_limit, doc issues:write (BE-4003)08ad004fix(groom): harden auto-builder against review-panel findings (BE-4003)📊 Changes
7 files changed (+816 additions, -74 deletions)
View changed files
📝
.github/groom/README.md(+24 -5)➕
.github/groom/builder.md(+16 -0)📝
.github/groom/ledger.py(+73 -24)📝
.github/groom/tests/test_ledger.py(+108 -5)📝
.github/workflows/groom.yml(+582 -31)📝
AGENTS.md(+12 -8)📝
README.md(+1 -1)📄 Description
ELI-5
The groomer finds tech-debt and files GitHub issues, but the team reviews at the PR level and never works the issues — so they're a dead end. This adds an opt-in auto-builder (split C of the groom epic): when a repo turns it on, the top few confirmed findings each run are turned into real, reviewable PRs (throttled to 5), while everything else still files as issues. The PRs run full CI + cursor-review and are never auto-merged — a human still presses the button. Off by default, so nothing changes unless you opt in.
What changed
groom.yml— three new jobs behindbuilder: true(default false):build_select— the single dedup + throttle authority (no agent). Dedups verified findings against the durable ledger, then splits them: topmax_prs(default 5) CONFIRM, non-security findings → build queue; the rest (DOWNGRADE, security, beyond-cap) → issue remainder. In builder-off mode it's a pass-through, so the issue path is byte-identical to before.build— the credential-free builder (matrix, one cell per queued finding).permissions: contents: read, onlyANTHROPIC_API_KEY. An agent writes the code change into its own fresh checkout; a deterministic step captures the working-tree diff as a patch artifact and enforces thepr_size_limitbail-out. Mirrors the finder/verifier isolation exactly.build_pr— the credentialed PR job (no agent). Mints the bot token, applies the patch on a branch, opens a branded, review-gated PR (labelsgroom+groom-pr+cursor-review, a loud "NOT auto-merged" banner, the verifier rationale, and the signature marker). On a bail/oversized/non-applying patch it files agroomissue instead so nothing is dropped. Honorsdry_run(preview, opens nothing).ledger.py— PR-state added. The/issueslisting already returns groom-labeled PRs; builder PRs carry the same signature marker in their body, so the ledger now classifies them: open →pr-open, merged →merged, closed-unmerged →pr-closed. All suppress re-proposing → a merged/closed finding is never re-proposed (RFC point 3). The markerless-record skip still guards against poisoning. (BE-3874 skipped all PRs because groom filed only issues then — cited in the code.)builder.md— new phase-3 brief (scope-disciplined, keep-it-green, never-touch-security, patch-size bail).Acceptance criteria
build_selectcapsto_buildatmax_prs.build(contents: read) → artifact →build_pr(bot token).ledger.py, regression-tested (test_{open,merged,closed}_builder_pr_*intest_ledger.py).groom/groom-pr/cursor-reviewlabels + bot author; opening as the bot App (required) triggers CI + the review panel.groom-pr(NOTagent-coded), so the agent-work merger (which lives in a different repo and keys onauthor == operator && agent-coded) already skips them. The actual merger-side skip rule can't be enforced from here — please confirm the merger excludesauthor == bot/label == groom-prbefore enabling live on a repo the merger watches.builderinput.Judgment calls (open items from the ticket — resolvable in review)
max_prsinput — trivially tunable.groomissues, so nothing is silently dropped (security findings especially). The alternative "defer to next run" is a one-line change if preferred.rank/score field inverifier.mdcan refine it.pr_size_limit(default 400 changed lines); an oversized or non-applying patch files an issue instead of a giant PR.Riskiest lines & why they're safe
build_ledgernow includes PRs (was an explicit skip). Safe because the marker check is unchanged: only PRs carrying a signature marker (= builder PRs) become records; a hand-labeled human PR is still ignored. History (BE-3874) cited inline — the skip predated the builder.git diff --cached→git apply --indexround-trip: verified locally against modify + add + delete; apply-failure falls back to filing an issue.buildagent job iscontents: readwith no GitHub token; the only job with write creds (build_pr) runs no agent and never executes repo code (it onlygit applys a diff). A prompt-injected builder can produce a bad patch, nothing more.Falsification note (negative-claim check)
The one deny path added —
builder=true requires bot_app_id → exit 1— is input validation that tells the operator exactly how to enable the feature, not a capability denial (no "not supported / STOP" dead-end). The bail path preserves the capability by filing an issue. No #581-class dead-end.Testing
python3 -m unittest discover -s .github/groom/tests→ 46 pass (10 new for PR-state).build_selectpartition +git diff/applyround-trip smoke-tested locally.dry_run: truefirst (RFC point 6).Note on size
~700 lines, but a single cohesive feature (the three jobs are one atomic unit) and fully gated behind an opt-in flag — zero behavior change when
builderis off.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.