mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #350] [MERGED] feat(cursor-approve): axis base, correctness + conformance axes, and the decide workflow #355
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#355
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/350
Author: @mattmillerai
Created: 10/7/2026
Status: ✅ Merged
Merged: 10/7/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-19325-cursor-approve-axes📝 Commits (3)
81901e5feat(cursor-approve): axis base + correctness/conformance axes and the decide workflowdd0391afix(cursor-approve): close the approval-window, forged-verdict and stale-base gaps the panel founda815cfcMerge origin/main into matt/be-19325-cursor-approve-axes📊 Changes
15 files changed (+1965 additions, -16 deletions)
View changed files
📝
.github/cursor-approve/aggregate.py(+109 -7)➕
.github/cursor-approve/card.py(+278 -0)📝
.github/cursor-approve/tests/test_aggregate.py(+123 -0)➕
.github/cursor-approve/tests/test_card.py(+242 -0)📝
.github/cursor-review/auto-approve.py(+197 -6)➕
.github/cursor-review/tests/test_approve_external.py(+204 -0)📝
.github/workflow-pins/tests/test_check_workflow_pins.py(+6 -3)📝
.github/workflow-pins/tests/test_inputs_docs_drift.py(+10 -0)➕
.github/workflows/axis-conformance.yml(+43 -0)➕
.github/workflows/axis-correctness.yml(+43 -0)➕
.github/workflows/cursor-approve.yml(+322 -0)➕
.github/workflows/cursor-axis-base.yml(+205 -0)📝
.github/workflows/test-cursor-review-scripts.yml(+10 -0)📝
README.md(+1 -0)➕
docs/callers/cursor-approve.md(+172 -0)📄 Description
ELI-5
Once a cursor-review round passes, two new "axis" reviewers (correctness, conformance) each judge the PR on their own and return green/yellow/red. A new
cursor-approve.ymlcollects their verdicts, keeps one live status card on the PR, and approves only when no axis is red and few enough are yellow. It goes through the existing auto-approve protections.What changed
.github/workflows/cursor-axis-base.ymlis the shared axis body. It renders the prompt (aggregate.py render), installs the pinnedcursor-agentwithinstall-cursor-cli.sh, runs it over a read-only full-history checkout of the PR head (persist-credentials: false), extracts exactly one JSON verdict (newaggregate.py extract, which fails closed on duplicate keys, a second"verdict"key or an over-cap reply) stamped with the judgedcommit_sha, and uploadsaxis-<name>. The job hascontents: readonly, a 20-min timeout, refuses fork PRs, and a failed run uploads nothing.mcp_configandno_shellare reserved extension points that fail if set.axis-correctness.ymlandaxis-conformance.ymlare thin wrappers that declare onlyCURSOR_API_KEY. A test enforces this.cursor-approve.ymlhasphase: start|decide.startfirst withdraws the approver's own approvals, because cursor-review has already approved whenapprove_gate == 'pass'. In the caller example the axesneeds: approve-start.decidereads each axis only from its ownaxis-<name>artifact, and only forcommit_sha. Its guard step is a byte-for-byte copy of cursor-review's (a test enforces this). It holdsAPPROVER_TOKEN; if the token is empty it warns and exits 0, with no fallback. It never checks out PR code..github/cursor-approve/card.pyis the status card. It finds the card by<!-- cursor-approve-card -->and the token's own login, and edits it in place. It covers four states: pending, verdicts + result + rule, superseded, round-limit. Model strings go throughneutralize_mentions+ markdown/HTML escaping.auto-approve.py approve-externalis the new subcommand. It re-reads the head and base: if the head moved or the base differs from the axes'--base-ref, it posts no review (outcomesuperseded) and withdraws only approvals that are stale against the live head and base. never approves overneeds-human-review, re-checks the decision itself (every expected axis green/yellow), and adds the reviewed-SHA + base markers. It withdraws its own earlier approvals on every other non-approval and re-reads after the POST. A newwithdrawsubcommand backs the start phase. An empty approver login is refused everywhere. The approval body is one line that links the card.docs/callers/cursor-approve.mdwith the example caller, plus a README row. The workflow-pins guarded-site count goes 20 → 21, and docs-drift rows are added for the four new reusables.Judgment calls
job.workflow_sha, not aworkflows_refinput. The ticket's base input list has no ref, and the wrappers can't pin their own SHA. The base fails closed whenjob.workflow_shais empty, so it never falls back to the default branch../.github/workflows/cursor-axis-base.yml. GitHub documents a./call as resolving to the same commit as the calling workflow. I have not checked this against a live cross-repo run (see Residual).neutralize_mentionsplus backslash-escaping of markdown/HTML characters rather thanrender_code_ref's code-span rendering. Escaping<also breaks a forged marker.env:. A test asserts it equals cursor-review.yml's pin.approve-externalunderalways(). A failedaggregate.py decidethen still withdraws an earlier approval instead of leaving it in place.always(). A failed axis then reads as "no result" instead of skipping the decision.Residual
./reusable resolution from a consumer repo, the artifact handoff between the axis jobs and the decide job, thecursor-agentinvocation and the prompt's{{context_file}}path (written under the checkout's.git/) are all untested end to end. A first pilot caller should confirm them.job.workflow_shaas an unknown property, plus shellcheck SC2018/SC2019 info notes on the guard copied byte-for-byte. main'scursor-review.ymlalready has the same findings (12 + 22 + 22), so they are not new. No other findings.mcp_configandno_shellare reserved for them but not implemented.Provenance
.github/cursor-approve/tests(80),.github/cursor-review/tests(842),.github/workflow-pins/tests(530),.github/agents-md-integrity/tests(46)check_workflow_pins.pyOK,check_agents_md.pypassed,check-org-repo-literals.shOKworkflows_ref(it loads atjob.workflow_sha). The ticket's actionlint-clean criterion is met only up to the findings main's cursor-review.yml already has.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.