Repository navigation
fix(pr-merge): arm a hold-path pull request a trusted person approved at its head - #10397
Conversation
… at its head enable-auto-merge held every lanes App pull request on a hold path and never read approvals, while ci-status lifts that hold on a trusted person's approving review of the head (merge-holds.pathLifters). The reader now fetches each review's state, commit and author id, builds the lifters with the same pathLifters and trusted-actor list, and lets the remaining checks decide once the head is approved. An unread listing or hold-path list and a capped listing still hold. 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. |
|
claude-security-review reviewed Security review of #10397 (head daa86e4). The diff touches the merge-hold controls, which this lane treats as trust controls. I found no exploitable bypass, but the change narrows two merge holds, so it is CRITICAL by this lane's rules and held for a person. critical-findings: 0 (the one CRITICAL finding has an inline comment) CRITICAL: weakens merge holds (
Manifest items: none changed. No plugin or marketplace manifests are in the diff. Cost: this change only adds API reads, and no paid plan, billing setting or billed resource. PR context text contained no embedded instructions to the lane. |
|
claude-security-review holds this pull request for a person (critical-security) at The change to .github/scripts/pr-merge/enable-auto-merge.mjs:967 narrows a merge hold. A trusted person's approval of the head now lets the lane arm auto-merge on a hold-path pull request, which previously always held for a person to merge. This lane treats any narrowing of a merge hold as a CRITICAL trust-control change. claude-lane: claude-security-review |
|
claude-review reviewed No blocking or advisory findings. I read the full diff and the PR context, and checked it against What I checked
Not a finding: the PR leaves the |
…approval After enable-auto-merge stopped holding an approved hold-path pull request, the reader's risk score (evidence --lane-reviews) still refused it: babysit_risk flags every HIGH_FLOOR and configured path as high-path:, a person's hold no approval lifted. lane_risk_refusal now drops those reasons when a trusted person's newest deciding review of the head approves it (babysit_merge_policy.path_lifters, held equal to merge-holds pathLifters by test_merge_holds_sync.py), reading the trusted list through the reader. An aliasing path, cost, trust-gate, manifest, file-cap and review-lane reasons keep holding, and an unread review or trusted list lifts nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
claude-security-review holds this pull request for a person (critical-security) at Trust-control change: the PR narrows the merge hold on hold paths. claude-lane: claude-security-review |
|
claude-security-review holds this pull request for a person (critical-security) at Narrows merge holds: enable-auto-merge.mjs decide() no longer holds hold-path pull requests (including the trust/gate floor) once a trusted person approves the head, and babysit_verify_evidence.lane_risk_refusal drops high-path: reasons on the same approval. This is a merge-hold narrowing, which this lane treats as a CRITICAL trust-control change. The lift mirrors ci-status's pathLifters and fails closed on unread inputs, but a person should confirm it. claude-lane: claude-security-review |
Refs: #10224
Summary
A lanes App pull request that changes a hold path could not be armed after a trusted person approved its head.
ci-statuslifts that hold on a trusted person's approving review of the current head (merge-holds.pathLifters). Two places did not:enable-auto-mergedecide()held every hold-path pull request and never read approvals.evidence --lane-reviews,lane_risk_refusal) held the same paths ashigh-path:reasons, which only a person clears, and read no approval either.#10224 was approved by the owner at
790239cc, armed by hand, and disarmed by the lanes App nine minutes later with no new commit.Fix
enable-auto-merge.mjs:REVIEW_FIELDSreads each review'sstate,commit { oid }and the author'sdatabaseId. One item mapper (itemOf) feeds both the veto check and the lifters. The reader computeslifterswithpathLiftersand the trusted-actor list it already reads for cost decisions.decide()skips the hold-path hold only when its kind ishold-pathand a lifter exists. Anunreadresult and a capped file listing still hold.babysit_merge_policy.path_lifters: the Python twin ofpathLiftersover REST review rows. For each trusted user it takes the newest APPROVED, CHANGES_REQUESTED or DISMISSED review atcommit == head; a newer request for changes or a dismissal blocks.babysit_verify_evidence.lane_risk_refusal: whenhigh-path:<glob>reasons hold, it reads the pull request's reviews and the reader's trusted list (Reader._trusted_humans, the base trusted-actors.json), then drops those reasons whenpath_liftersnames someone. The lift sits at the point where verify turns risk reasons into a refusal, soscore()stays a pure path scorer. It never liftshigh-path:**(an aliasing path, symlink, submodule or mode change) or any cost, trust-gate, manifest, file-cap or review-lane reason. A review list or trusted list that does not read lifts nothing.docs/conventions/pr-pipeline/README.md, and fragments under.changes/pr-pipeline/and.changes/source-control/.Not changed: the human-gated label. A pull request already labeled
needs-humanstays held by that label until it is removed; #10389 owns clear-escalations.Verification
[{ mutation: 'disarm', id: 'PR_51' }], expected an arm of PR_50).('high-path:.github/actions/resolve-config/**: .github/actions/resolve-config/resolve.mjs', True), expectedNone).high-path:**, lifting on an unread review list, ignoring the head, ignoring trust, and taking any approval over a newer block.test_merge_holds_sync.pyadds a parity case. JSpathLiftersoverfromRestand Pythonpath_liftersgive the same answers on 10 shared REST review fixtures.node --test .github/scripts/pr-merge/*.test.mjs: 523 pass, 0 fail. Three integration mocks oflane_risk_refusalnow accept the new keyword.scripts/check-affected.sh --uncommitted: 12 passed, 5 skipped.enable-auto-merge.mjs,babysit_verify_evidence.py,babysit_merge_policy.py), soci-statusholds it on a hold path until a trusted person approves its head.Related
merge-holds.mjsandenable-auto-merge.test.mjs. This change keeps to small, separate hunks.🤖 Generated with Claude Code