mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #67] [MERGED] feat(groom): builder authors the PR body per the comfy-pr convention (BE-4346) #76
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#76
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/67
Author: @mattmillerai
Created: 7/24/2026
Status: ✅ Merged
Merged: 7/24/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-4346-groom-builder-pr-body📝 Commits (2)
9c7ae2bfeat(groom): builder authors the PR body per the comfy-pr convention (BE-4346)6fa063bfix(groom): harden builder PR-body assembly against crash, overflow & markup injection (BE-4346)📊 Changes
4 files changed (+299 additions, -17 deletions)
View changed files
📝
.github/groom/builder.md(+9 -1)📝
.github/groom/ledger.py(+119 -0)📝
.github/groom/tests/test_ledger.py(+113 -0)📝
.github/workflows/groom.yml(+58 -16)📄 Description
ELI-5
When the groom sweep auto-builds a fix, it opens a pull request. Until now the PR description was machine-assembled — a loud banner followed by the reviewer-bot's raw "here's the problem" paragraph, with the text hard-wrapped so GitHub rendered it as a wall of mid-sentence line breaks. It didn't follow the team's PR convention (a plain-language
## ELI-5first, then a structured what/why, one line per paragraph). This change hands the PR-writing job to the agent that actually made the change — it now writes a proper ELI-5-first, structured description — while the workflow keeps prepending the "review-only, never auto-merged" banner and appending the ledger marker.What changed
.github/groom/builder.md— the builder brief now instructs the agent to write the human-facing PR body to a new{{PR_BODY_OUT}}file (when it patches):## ELI-5first, then## What changed/## Why, with the "never hard-wrap — one line per paragraph, let GitHub soft-wrap" rule embedded directly (the builder runsclaude -p --bare --setting-sources ""and cannot invoke the comfy-pr skill, so the convention is spelled out in the brief). On a bail it writes no body..github/groom/ledger.py— newbuilder_pr_body(banner, eli5_body, verifier_rationale, signature)helper assembles the final body: banner first, the builder's ELI-5 body, the verifier rationale demoted to a secondary<details>section, and thesignature_markerLAST. Falls back to the original banner +## Verifier rationale+ marker template when the body is empty or doesn't lead with an ELI-5 heading..github/workflows/groom.yml— adds thePR_BODY_OUTenv var and the builder'sEditgrant + prompt substitution for it (mirroring the provenBUILDER_OUTwrite path); the pre-publish secret scan now covers the PR body alongside the patch and summary (fail-closed bail if the key appears); the capture step hands a size-capped, scanned body tobuild_prvia the build artifact;build_prcallsbuilder_pr_bodyinstead of assembling the string inline..github/groom/tests/test_ledger.py—BuilderPrBodyTestcovers the happy path (banner first / marker last / rationale in<details>), the empty-body and non-ELI-5 fallbacks, ELI-5 heading variants, a whitespace-only body, and the spoofed-marker injection guard.Why
Groom builder PRs are read by humans, so they should follow the same PR convention as hand-written ones (evidence: comfy-cloud-mcp-server #837 opened with the raw rationale and no ELI-5). The builder agent knows exactly what it changed, so it's the right author. The banner and ledger marker stay load-bearing (the banner sets review expectations; the ledger keys dedup on the marker), so they remain workflow-controlled — the marker is appended LAST so an embedded/spoofed marker in the model body can't shadow it (
extract_signaturereads the last marker). Behavior is preserved on every non-happy path: the fallback template is byte-identical to today's output.Acceptance criteria
## ELI-5first, structured what/why, verifier rationale as a secondary<details>section (enforced:build_prfalls back to the plain template unless the body leads with an ELI-5 heading).builder.md).signature_markerlast (both inbuilder_pr_body; unit-tested).gh pr create(extended the capture-step scan;build_prholds no model key, so scanning must and does happen in the credential-free build job before the artifact is uploaded)..github/groom/testscovers the new body path incl. the fallback (54 tests pass).Judgment calls
PR_BODY_OUTfile rather than apr_bodyJSON field. The ticket offered either; a markdown file mirrors the finder/verifier*_OUTpattern and avoids the model having to emit a large multiline markdown blob as an escaped JSON string. It uses the identicalEdit(//<path>)grant that the shippedBUILDER_OUTwrite relies on.build_pr(deterministic), not by the builder.build_pralready has the verifier text in scope; keeping it out of the model's hands means the rationale is never rewritten and its own upstream secret-scan still stands. The builder only authors the ELI-5 + what/why.Out of scope (per ticket): the groom issue body, groom-security findings (filed as issues), and the finder/verifier briefs.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.