Repository navigation
fix(pr-pipeline): hold native lane PRs on marketplace and cost paths - #9488
Conversation
ci-status and enable-auto-merge now hold a lanes App pull request that changes the root marketplace manifest (a hold path, lifted by a trusted approval of the head) or a merge-gate cost path. The cost hold lifts only on the owner's unedited `**Decision recorded.** Cost:` comment linked from the body, read as the gate's cost_decision reads it, with the owner a person on the trusted-actor list as ci-status's cost-only review step names one. A Python test keeps the JS cost globs and matches in step with babysit_risk.COST_PATHS and is_manifest_path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Match `*.tf`-style cost globs against a segment that opens with ".", as babysit_risk.glob_match does, and escape the hold reason enable-auto-merge logs so a changed file's name cannot start a workflow command. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The native cost hold's costDecision copies babysit_merge_policy.cost_decision by hand. Run one fixture table through both so a change to either rule fails the sync test instead of letting native auto-merge clear a comment the gate rejects. Also narrow the docstring to the repository's pipeline config, the one the floor holds. 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-review reviewed Incremental review of The change is comment-only, in two places. It rewords the cost-decision explanation near line 97, and the note about pull request 42 in the cost-path test near line 419. The new wording says pull request 40's closing issue holds the owner's comment, and that each pull request closes its own number plus 1000. That matches the previous wording, where 40 maps to issue 1040 and 42 to issue 1042. Code, assertions and test behaviour are unchanged. I did not run the tests. Nothing here touches a hold class (cost, trust-gate or critical-security), and no manifest items apply. The wrapper supplied no closing-issue criteria that this change could affect. |
|
claude-security-review reviewed Incremental security review of critical-findings: 0 |
…ments comment-hygiene refuses issue references in code comments. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #9449
Summary
Under
merge.lane-prs: native, onlyci-statusandenable-auto-merge.mjshold a lanes App pull request, and both readHOLD_PATH_FLOORinmerge-holds.mjs. Two gaps meant a lane PR could merge where the pr-merge gate would have held it:.claude-plugin/marketplace.json, which the gate scores HIGH (babysit_risk.is_manifest_path), was not a hold path.babysit_risk.COST_PATHS) were not held at all.Fix
.claude-plugin/marketplace.jsonjoinsHOLD_PATH_FLOORas a plain path. Lane PRs rarely edit it, so the whole file is held and no content diff is read. It clears the way every floor path clears: a trusted person approves the head.merge-holds.mjsgainsCOST_PATHSandcostHold, kept apart from the floor so an approval cannot lift them. Only the owner's cost decision lifts the hold.costDecisionreads it by the gate'scost_decisionrule: an unedited comment opening**Decision recorded.** Cost:, by a User and not posted through an App, linked from the body outside HTML comments. The comment sits on the PR itself, or on its one closing issue in this repository and posted after the PR was created. Matching is case-folded, and a glob covers whatever sits under it, asglob_matchdoes.ci-statusruns this insidemerge-holds.mjs. It reads only when a cost path changed and the body links a comment, and it uses the step's existingGH_TOKEN, so the workflow step's shell is unchanged.enable-auto-merge.mjsruns the samecostHoldandcostDecisionindecideand its read step. It reads the owner list from.base/.github/standards/trusted-actors/trusted-actors.json, orTRUSTED_ACTORSwhen set.Clear a cost-only review hold the owner decidedstep uses the same rule, and Python'scost_decisionasks for admin permission instead. This choice needs no permission read with either token. It also drops Python's agent-identity and self-login exclusions: those accounts are Apps, which the User check already refuses.test_merge_holds_sync.pyruns the module under node. It checks thatCOST_PATHSequalsbabysit_risk.COST_PATHS, that sample paths (case variants, dot directories, a path under a glob) match the same way in both, and that every pathis_manifest_pathtakes is a hold path.merge.lane-prsis unchanged.Verification
node --testin.github/scripts/pr-merge: 252 pass, 0 fail.node --test merge-authority.test.mjsin.github/actions/resolve-config: 26 pass.pytest tests/test_merge_holds_sync.py tests/test_verify_rules_sync.py tests/test_babysit_merge_cost.py tests/test_babysit_risk_cost.py: 60 passed, 222 subtests.scripts/ci-lanes-pr-hold.test.sh(100 pass),ci-hold-lifted-by.test.sh(33),ci-hold-merge-group.test.sh(22).decidetest and the ci-status test fail.costHoldmade inert, thedecide/maintest, thecostHoldtest and the ci-status cost test fail.costDecisionnegatives mirrortest_babysit_merge_cost.py.scripts/run-ruff.sh checkandformat, typos, actionlint and markdownlint are clean on the changed files.*.tf-style globs now match a dot-led file name such as.tf, asglob_matchdoes. The sync test covers this.casefoldand backslash path forms differ between the two implementations.test_merge_holds_sync.pynow runs one table of 14 decision cases through bothcost_decisionandcostDecision; it fails whencostDecisionstops checking edits. Its docstring now names only the repository's pipeline config. Left as is:fetchGitHubmakes one attempt per read, which fails closed.*.tf.json/*.tfvars.jsonare not cost paths (no IaC is tracked); a decision is not tied to the head; owner comments posted through the owner's own token count as the owner's.Related
🤖 Generated with Claude Code