Repository navigation
feat(pr-pipeline): arm native auto-merge for lane pull requests - #9399
Conversation
The pr-merge lane's new enable-auto-merge activity turns on GitHub's native auto-merge (squash, expectedHeadOid) for each open lanes App pull request into main that closes an issue and carries no hold, and turns it off on an armed one that now carries a Hold: line, do-not-merge or the human-gated label. pr-merge.yml runs it in its own job when the issue lane finishes, on a listed human's PR edit, and on the schedule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…merge # Conflicts: # .github/scripts/pr-merge/workflow.test.mjs
…omments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…merge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The arm rule reads the first body line as Closes #<issue>; feed it the body report-outcome builds, clean, with its hold line, and as Refs, so a change on either side that stops lane pull requests from arming fails a test. Also pin that enable-auto-merge never runs on a push to main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec4936f705
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
claude-review reviewed Code review: PR #9399, arm native auto-merge for lane pull requestsI found no blocking or advisory findings, so I am not holding this pull request. What I read: the full diff (all 14 files, What I checked:
Notes, not findings:
|
|
claude-security-review reviewed Security review: PR #9399 (native auto-merge for lanes App pull requests)I found no CRITICAL issues, so I am not holding the merge. I read the full diff ( critical-findings: 0 Scope.
Findings
I could not read Findings not posted inline (their path, line or side is malformed):
Unescaped changed-file names in workflow-command-capable log lines.
Fix: pass |
Native auto-merge skips the gate's human veto, so the arm rule now reads each candidate's comments, reviews and inline comments and applies babysit_merge.human_veto_logins: a member's newest comment with text saying "do not merge" holds it (disarming an armed one), a later comment lifts it, and a discussion it cannot read whole is not armed. Auto-merge a person turned off is not turned back on. A missing merge.report-only now reaches the script as report-only instead of being rewritten to false, and the workflow test pins the workflow_run filter positively. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…merge Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
report-outcome's Hold: line covers only the files at opening, and native auto-merge stays armed across later pushes. The arm rule now reads the files the head changes now (renamed-from paths included) against the merge lane's denied paths from the resolved config, using report-outcome's readHoldPaths; a match leaves it unarmed or disarms it, and unreadable hold paths or more than 300 changed files arm nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mber veto Native auto-merge merges a lanes App pull request without pr-merge's gate, so ci-status now fails on the two text holds that gate honours, on each pull request event and in the merge queue: a body hold (a Hold: line or "do not merge") and a member's newest comment saying not to merge. The rules move to .github/scripts/pr-merge/merge-holds.mjs, which enable-auto-merge.mjs arms by and ci-status runs from the base commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pull request event read merge-holds.mjs at the payload's base, so a lanes App pull request into a branch it pushed could run its own module with the ci-status token. The step now reads only pull requests into main, at their live base, and the queue's base in a merge group. It also fails closed on an unreadable author and on a module exit 0 without its verdict line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…status ci-status's lanes App hold step now also reads the live changed files, renamed-from paths included, against main's merge.diff-check.denied-paths plus the floor resolve-config forces, so a push that adds a hold path after arming fails ci-status on its own head instead of waiting for the next scheduled enable-auto-merge run. The rule is merge-holds.pathHold, which enable-auto-merge.mjs now imports, so arm time and ci-status share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ction Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…old path A hold path on a lanes App pull request failed ci-status with no way for a person to merge it short of an admin bypass. A person on the trusted-actor list (as main has it) now lifts it by approving the head: their newest deciding review of the head must approve. It lifts no body hold, veto or unreadable file list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-unblock lane stopped on this pull request and needs a person: a conflicted path is a workflow, submodule config or a settings file, which the lane does not resolve.
To resume, deal with the reason above, remove the gh workflow run pr-unblock.yml -R melodic-software/claude-code-plugins -f pr-number=9399 -f activity=resolve-conflicts |
path.matchesGlob has no dot option, so `.github/**` skipped `.github/workflows/.x.yml` and a lanes App pull request adding one armed and passed ci-status. matchesHoldPath marks a segment opening with "." the same way on both sides before matching. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…merge # Conflicts: # .github/workflows/pr-require-checks.yml
A held file name can carry a newline, which printed into the step log could start a workflow command. Escape %, CR and LF in the ::error:: reasons and the lift line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-unblock lane escalated this pull request as |
…-status The lanes App hold paths now add CODEOWNERS, .gitmodules and every plugin manifest (a path-wide stand-in for the gate's executable-key check) to the forced denied paths, at arm time and in ci-status. ci-status sets up Node from main's .node-version before the hold step, so path.matchesGlob comes from the pinned Node, not the runner image's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs: #9276
Summary
PR 8 of the #9276 plan: lane pull requests merge through GitHub's native auto-merge. The new
enable-auto-mergeactivity arms each clean lanes App pull request right after the issue lane opens it, and refuses or disarms one that carries a hold.ci-status, which since #9361 fails onneeds-humanand requires both review lanes on the head, is the gate auto-merge waits on.Fix
.github/scripts/pr-merge/enable-auto-merge.mjs(no model): lists open pull requests into main and callsenablePullRequestAutoMerge(SQUASH, expectedHeadOid)on each one that the lanes App opened from this repository, that is not a draft, that opens withCloses #<issue>, and that carries no hold. A hold is thedo-not-mergelabel, the tracker's human-gated label (needs-human), or a body hold under the gate's own rule (BODY_MERGE_HOLD_RE: aHold:line or the do-not-merge phrase). Each candidate is also refused while a member's newest comment, review or inline comment vetoes the merge (babysit_merge.human_veto_logins, ported with a parity test), while its head changes a path inmerge.diff-check.denied-paths(read from the files the head changes at each run, through report-outcome'sreadHoldPaths), and while a person has turned its auto-merge off. It callsdisablePullRequestAutoMergeon an armed one that now fails any of those rules. It writes nothing whilemerge.report-onlyis true..github/workflows/pr-merge.yml: a newenable-auto-mergejob with its own broker token (lanepr-merge, effectmerge), woken by a newworkflow_runtrigger onwork-resolve-issuecompletion (the merge job ignores it), by a listed human'sedited/unlabeled/ready_for_review(so a newHold:line disarms at once), and by the 15-minute schedule, which arms or disarms anything the events missed.docs/conventions/pr-pipeline.yaml: theenable-auto-mergeactivity (effectmerge) in thepr-mergelane. README section "Native auto-merge".enable-auto-merge, notarm-merge.pr-merge.yml, notwork-resolve-issue.yml, because the broker mintsmergeonly forpr-merge.yml. Basis: azure-iacsrc/lanes-token-broker/src/claims.mjsMERGE_CALLER = "pr-merge.yml"andauthorize.mjs:308.authorize.mjscheckActors). An issue run started by the lanes App's ownagent-readylabel is therefore armed by the next scheduled run, within 15 minutes.Fail a lanes App pull request its body or a member holdsinpr-require-checks.ymlfails a lanes App pull request (author id 337595936, type Bot, read live) on a body hold or a member veto, on eachpull_requestevent and in themerge_grouprun, so a hold added after arming failsci-statusand the merge queue removes the pull request. It reads the body, comments, reviews and inline comments live (all pages, REST, as the Python gate reads them) and runs.github/scripts/pr-merge/merge-holds.mjsas main has it (the queue's base in a merge group, the live base of a pull request into main otherwise; a pull request into another branch is not read), so a pull request cannot rewrite its own hold or run its own module with the ci-status token. An unreadable author, and a module exit 0 without its verdict line, fail closed. That module now holdsBODY_HOLD,HUMAN_VETOand the newest-comment-per-member rule, andenable-auto-merge.mjsimports it, so arming and ci-status share one rule. Unreadable reads fail closed. Lifting works as before: remove the body line (theeditedevent re-runs ci-status), or post a later comment as the same person. A comment fires nopull_requestevent, so a veto posted while armed takes effect when the queue builds the group, and ci-status needs a re-run after a veto is lifted.ci-statustimeout-minutesgoes from 7 to 9 for the new reads' retries. AGENTS.md and the README say ci-status now reads these two holds on lanes App pull requests.pr-merge.yml, and pr-verify). The orchestrator chose option A for the owner.Verification
node --test .github/scripts/pr-merge/*.test.mjs: 203/203 pass, plusreport-outcome.test.mjs. Contract test: report-outcome's owndecide()PR body arms when clean; its hold-line, hold-path andRefs:bodies do not, and changing the first-line rule fails the test. Tests that failed before their fixes cover the veto (and the regex's parity withHUMAN_MERGE_VETO_RE), a person's manual disable, hold paths on the current head, andreport-onlywhen the key is missing.scripts/ci-lanes-pr-hold.test.sh(new, 40 cases) runs the step body against stubgh; it fails on the base workflow (no step). It covers aHold:line and "do not merge" in the body, a MEMBER, OWNER, COLLABORATOR, review-summary and inline veto failing, NONE, CONTRIBUTOR and bot vetoes not holding, a later comment by the same person lifting (an empty review does not, another member does not), the merge_group path failing on a body hold and a veto and passing once lifted, a person's PR and a PR into another branch skipped before any module read, and fail-closed reads. The lanes App id is checked againstpr-pipeline.yamlmerge.agent-identityintrusted-actors.json.scripts/check-affected.shon eea9401: 10 passed, 3 skipped (--tests: every selected suite passes exceptci-test-node-stop-commands.test.sh, which needs PyYAML this machine lacks).actionlintclean,zizmorno findings, lane coverage passes.Hold:line or edit its own body to lift a hold (text holds have no untrusted-lifter check like the label's);.github/scripts/pr-merge/**is not in CODEOWNERS or the babysit HIGH floor, so a lanes PR could weakenmerge-holds.mjs;enable-auto-merge.mjsdoes not apply the HIGH path floor.scripts/check-affected.sh --testson 2f6b030: 10 passed, 4 skipped.check-lane-coverage,check-read-caller-keys,check-orphaned-fixtures,check-line-citations,check-killswitch-hoistandcheck-silent-skipspass.actionlintis clean.zizmor --offline .github/workflows/pr-merge.ymlreports no findings.resolve-config.pin=39fed34a, fetched withscripts/deploy/fetch-resolve-config.sh) runsloadConfigandresolveGrantagainst this branch. It accepts the config, andpr-merge:enable-auto-mergeresolves to effectmergewith contents/pull-requests/issues write.MERGE_EVENTSincludesworkflow_run. No azure-iac re-pin is needed.allow_auto_merge: true.enablePullRequestAutoMerge, or for howexpectedHeadOidinteracts with the merge queue.merge.report-onlyisfalse, so this goes live when it merges.pr-require-checks.yml:3357-3376, from feat(pr-pipeline): turn on review-lane holds and require both review lanes in ci-status #9361) fails on a missing, pending or failed review. Thebabysit_merge.py:271comment it cited predates that step.report-only(689f2bb). Hold paths on later pushes, from pr-verify (2f6b030).Related
🤖 Generated with Claude Code