Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changes/pr-pipeline/drop-trust-path-hold-apps-5d1e7a20.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
bump: patch
---

### Changed

- The agent App trust-path hold is off (owner decision Q21, 2026-10-29: path holds stay off until
open issues and pull requests reach zero). `merge.trust-path-hold-apps` names only
`trust-path-hold-off[bot]`, a login no App holds, in place of `melodic-agent[bot]`, so neither
ci-status's inline hold nor ci-workflows' `pr-require-checks-trust-paths` (through the regenerated
`.github/trust-path-hold.json`) holds an agent App pull request for a person, except that both
still fail closed on a read they cannot finish: a pull request past 250 commits or 3000 files, or
a branch history past 2000 entries. The list keeps one entry because the shared workflow fails on
an empty one. Restoring both holds takes three steps: list `melodic-agent[bot]` again, set
`merge.diff-check.path-holds` true and run `scripts/sync-hold-floor.py`. Listing the App alone
restores only ci-workflows' hold, since ci-status's inline hold runs only while `path-holds` is
true.
- ci-status no longer holds a release-App or standards-sync-App pull request for changing a
trust-gate path, and still holds a Dependabot one, whose action-pin bumps bring in third-party
code (owner decisions Q21 and Q24). While `merge.diff-check.path-holds` is false, as this
repository sets the new key, `scripts/sync-hold-floor.py` writes a guard after ci-status's
exempt-author `hold_patterns` that empties the list for every author but Dependabot. Setting
it true holds all three again. These authors still get no review lane.
5 changes: 5 additions & 0 deletions .changes/source-control/drop-trust-path-hold-apps-0c4b9e61.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
bump: none
---

Test-only: the merge-holds sync test checks that the trust-path hold's `apps` is non-empty instead of naming `melodic-agent[bot]`, and checks ci-status's exempt-author patterns as the generator writes them with path holds on and the Dependabot-only guard it adds with them off; the plugin ships no change.
2 changes: 1 addition & 1 deletion .github/trust-path-hold.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@
"docs/standards/*"
],
"apps": [
"melodic-agent[bot]"
"trust-path-hold-off[bot]"
]
}
6 changes: 5 additions & 1 deletion .github/workflows/pr-require-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4931,7 +4931,9 @@ jobs:
# standards-sync App, by numeric author id, are exempt: no review lane
# reviews them. An exempt author's PR still fails when a changed file
# (or a renamed file's old path) is a trust-gate path, since no security
# lane reads it; a person merges it. So does any other same-repository
# lane reads it; a person merges it (with merge.diff-check.path-holds
# false, Dependabot alone: the generated guard after hold_patterns
# empties the list for every other author). So does any other same-repository
# PR changing one that an agent App (merge.trust-path-hold-apps in the
# base commit's pr-pipeline.yaml) opened, authored or committed a commit
# of, or pushed to its head branch (the repository activity API, one
Expand Down Expand Up @@ -4994,6 +4996,8 @@ jobs:
# The trust-gate paths, as bash patterns (`*` crosses `/`).
# BEGIN hold-floor hold_patterns: generated by scripts/sync-hold-floor.py
hold_patterns=('.github/standards/trusted-actors/*' '.github/actions/check-trusted-trigger/*' 'CODEOWNERS' '*/CODEOWNERS' '.gitmodules' '*/.gitmodules' '.github/actions/resolve-config/*' '.github/actions/check-kill-switch/*' '.github/actions/request-lane-token/*' '.github/actions/log-api-budget/rate-guard.mjs' '.github/actions/log-api-budget/rate-limits.json' '.github/scripts/pr-merge/merge-holds.mjs' '.github/scripts/pr-merge/enable-auto-merge.mjs' '.github/scripts/pr-merge/superseded.mjs' '.github/scripts/pr-merge/clear-escalations.mjs' '.github/scripts/pr-merge/carry-run-cache.mjs' '.github/scripts/pr-merge/gate-check.mjs' '.github/scripts/pr-merge/head-ref-map.mjs' '.github/scripts/pr-merge/lane-records.mjs' '.github/scripts/pr-merge/last-report.mjs' '.github/scripts/pr-merge/rate-stop.bash' '.github/scripts/pr-merge/refire-refused.mjs' '.github/scripts/pr-merge/rotation.mjs' '.github/scripts/pr-merge/sweep-summary.mjs' '.github/scripts/pr-merge/who.mjs' '.github/scripts/pr-merge/post-unarmed-status.mjs' '.github/scripts/pr-merge/verify-answers.mjs' '.github/scripts/pr-merge/listing-carry.mjs' '.github/actions/report-check-run/posting-run.mjs' 'scripts/sync-hold-floor.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_risk.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_check_inputs.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_checks.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_classify.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_dependabot.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_feedback.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_gh.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_merge.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_merge_policy.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_postmerge.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_repo_config.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_review_evidence.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_review_trigger.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_run_cache.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_state.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_util.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_verify_evidence.py' 'plugins/source-control/skills/babysit-prs/scripts/babysit_whole_review.py' 'docs/conventions/pr-pipeline.yaml' '.github/scripts/pr-unblock/address-feedback.mjs' '.github/scripts/pr-unblock/escalation-routes.mjs' '.github/scripts/pr-unblock/escalation-routes.json' '.github/scripts/pr-unblock/gate-source.mjs' '.github/scripts/pr-unblock/thread-scope.mjs' '.github/scripts/pr-unblock/retry-fetch.mjs' '.github/scripts/work-resolve-issue/report-outcome.mjs' '.github/scripts/work-resolve-issue/limits.mjs' '.github/scripts/work-resolve-issue/retry-fetch.mjs' '.github/scripts/pr-unblock/report-escalation.sh' '.github/scripts/pr-unblock/adjudicate-feedback.mjs' '.github/scripts/pr-unblock/publish-feedback.mjs' '.github/scripts/pr-unblock/request-budget.mjs' '.github/scripts/pr-unblock/dependency-classify.mjs' '.github/scripts/apply-patch/apply-patch.mjs' '.github/scripts/apply-patch/predicates.mjs' '.github/scripts/apply-patch/protected-paths.mjs' '.github/scripts/apply-patch/retry-fetch.mjs' '.github/scripts/pr-unblock/fix-ci-context.mjs' '.github/scripts/pr-unblock/feedback-dispatch.mjs' '.github/scripts/pr-unblock/verify-notes.mjs' '.github/scripts/pr-unblock/limit-stop.mjs' '.github/scripts/pr-unblock/dispatch-record.mjs' '.github/scripts/pr-unblock/verify-cap.mjs' '.github/scripts/maintenance-reconcile-lost-runs/infra-failure.mjs' '.github/scripts/work-resolve-issue/stop-routes.json' '.github/scripts/work-resolve-issue/stop-routes.mjs' '.github/scripts/lib/stop-reason.mjs' '.github/scripts/lib/done-evidence.mjs' '.github/scripts/pr-review-main/*' '.claude/*' '*/.claude/*' '.claude-lane/*' '*/.claude-lane/*' 'docs/conventions/instruction-exception-register/*' 'docs/conventions/untrusted-content/*' '.mcp.json' '*/.mcp.json' 'CLAUDE.md' '*/CLAUDE.md' 'CLAUDE.local.md' '*/CLAUDE.local.md' 'AGENTS.md' '*/AGENTS.md' 'REVIEW.md' 'docs/standards/*' '.github/workflows/dependabot-fragments.yml' '.github/workflows/eval-browser-dispatch.yml' '.github/workflows/intake-reenter.yml' '.github/workflows/intake-triage.yml' '.github/workflows/maintenance-audit-lane-runs.yml' '.github/workflows/maintenance-reconcile-lost-runs.yml' '.github/workflows/post-merge-demotion-alert.yml' '.github/workflows/post-merge-test-mutation.yml' '.github/workflows/pr-feedback-dispatch.yml' '.github/workflows/pr-merge.yml' '.github/workflows/pr-refine.yml' '.github/workflows/pr-require-checks.yml' '.github/workflows/pr-review-hosted.yml' '.github/workflows/pr-review-main.yml' '.github/workflows/pr-review-security-hosted.yml' '.github/workflows/pr-run-activity-read.yml' '.github/workflows/pr-run-activity-write.yml' '.github/workflows/pr-unblock-dispatch.yml' '.github/workflows/pr-unblock.yml' '.github/workflows/pr-verify.yml' '.github/workflows/release-publish-plugins.yml' '.github/workflows/work-resolve-issue.yml' '.github/workflows/work-unblock.yml')
# merge.diff-check.path-holds is false: only Dependabot stays held.
[ "$AUTHOR_ID" = 49699333 ] || hold_patterns=()
Comment thread
kyle-sexton marked this conversation as resolved.
Resolved
# END hold-floor hold_patterns
if [[ ! $PR_NUMBER =~ ^[1-9][0-9]*$ ]]; then
echo "::error::the pull request number '$PR_NUMBER' is not a number."
Expand Down
20 changes: 15 additions & 5 deletions docs/conventions/pr-pipeline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -954,12 +954,18 @@ merge:
rung: C2
authority: pr-merge
agent-identity: melodic-automation-lanes[bot]
# The agent App, installed on every repository on purpose: ci-status holds
# a pull request it opened, wrote a commit of or pushed to when it changes a
# trust-gate path, and a person merges it (README.md, Both lanes review the
# head).
# The Apps whose touch holds a trust-gate path change for a person
# (README.md, Both lanes review the head): ci-status here, and ci-workflows'
# pr-require-checks-trust-paths through .github/trust-path-hold.json. Owner
# decision Q21 (2026-10-29) turned the hold off until open issues and pull
# requests reach zero: the one entry is a login no App holds, because the
# shared workflow fails on an empty list. Restoring both holds takes three
# steps: list melodic-agent[bot] again, set `diff-check.path-holds` true, and run
# scripts/sync-hold-floor.py.
# Listing the App alone restores only ci-workflows' hold; ci-status's inline
# hold also needs `path-holds`.
trust-path-hold-apps:
- melodic-agent[bot]
- trust-path-hold-off[bot]
Comment thread
kyle-sexton marked this conversation as resolved.
Resolved
Comment thread
kyle-sexton marked this conversation as resolved.
Resolved
# true: report each decision and write nothing.
report-only: false
# true: post-merge-dispatch starts a full run of main inside its 30-minute
Expand Down Expand Up @@ -1104,6 +1110,10 @@ merge:
# Owner decision 2026-10-17: the lane hold covers structural and untrusted-
# provenance work only; scoped lane PRs off the HIGH floor merge on the
# verifier verdict.
# `path-holds` also sets whether ci-status holds an exempt author's PR for
# a trust-gate path or an App-authored one (`trust-path-hold-apps`), except
# that ci-status holds a Dependabot PR for one either way (owner decision
# Q24, 2026-10-29: its action-pin bumps bring in third-party code).
# `path-holds: false`: no changed path holds a pull request for its path
# alone, not the floor above, denied-paths nor `review-path:` (owner
# decision Q15, 2026-10-29: "We shouldn't really have any path
Expand Down
12 changes: 9 additions & 3 deletions docs/conventions/pr-pipeline/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2509,15 +2509,21 @@ them on every `pull_request` run, contract-only runs included:
author id, except that their PR fails when a changed file (or a renamed file's old path) is a
trust-gate path (the hold-paths above less the security review's own files, matched
case-insensitively), since no lane
reviews it; a person merges it. The same holds a same-repository PR that changes a trust-gate
reviews it; a person merges it. While `merge.diff-check.path-holds` is false (this repository's
setting, owner decision Q21, 2026-10-29), `scripts/sync-hold-floor.py` writes a guard after
`hold_patterns` that empties it for every author but Dependabot, so only a Dependabot PR is held
for its paths: its action-pin bumps bring in third-party code (owner decision Q24). The same holds a same-repository PR that changes a trust-gate
path when an App named in `merge.trust-path-hold-apps` (the base commit's `pr-pipeline.yaml`,
`[bot]` logins; this repository names the agent App, `melodic-agent[bot]`) opened it, is the
`[bot]` logins; this repository names only `trust-path-hold-off[bot]`, a login no App holds, so
the hold is off) opened it, is the
author or committer of one of its commits by account or noreply address, or pushed to its head
branch (the repository activity API), since its head can rewrite the review callers; a person
merges it. Such a PR still needs both lanes when no trust-gate path changed. ci-status reads the
App list, the PR's commits and the branch's push history only once a trust-gate path matched,
and an unreadable one, a commit list shorter than the PR, or a full page of pushes fails closed.
A draft is exempt.
A draft is exempt. Restoring the App hold takes three steps: list `melodic-agent[bot]` again, set
`merge.diff-check.path-holds` true and run `scripts/sync-hold-floor.py`, because ci-status's inline hold runs only while `path-holds` is
true; listing the App alone restores only ci-workflows' `pr-require-checks-trust-paths` hold.
- **A stopped lane holds its head.** ci-status fails while the newest `pr-unblock/*` commit status
on the head by `github-actions[bot]` is `failure` or `error`, naming each such context; a later
`success` on the same head (`report-escalation.sh clear`) supersedes it, and another account's
Expand Down
6 changes: 3 additions & 3 deletions docs/conventions/pr-pipeline/pr-pipeline.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1147,8 +1147,8 @@
"type": "array",
"items": { "type": "string", "pattern": "^[A-Za-z0-9]+(-[A-Za-z0-9]+)*\\[bot\\]$" },
"uniqueItems": true,
"default": [],
"description": "[bot] logins of GitHub Apps whose touch puts a trust-gate path change in a person's hands. ci-status fails a same-repository pull request that changes a trust-gate path when one of them opened it, authored or committed one of its commits, or pushed to its head branch, as it fails an exempt author's (README.md, Both lanes review the head). It is read at the base commit. Empty or absent: no App is held this way."
"minItems": 1,
"description": "[bot] logins of GitHub Apps whose touch puts a trust-gate path change in a person's hands. ci-status fails a same-repository pull request that changes a trust-gate path when one of them opened it, authored or committed one of its commits, or pushed to its head branch, as it fails an exempt author's (README.md, Both lanes review the head). It is read at the base commit. It needs at least one entry, because the shared ci-workflows hold fails on an empty list; a login no App holds turns the hold off."
},
"diff-check": {
"type": "object",
Expand Down Expand Up @@ -1177,7 +1177,7 @@
"path-holds": {
"type": "boolean",
"default": false,
"description": "pr-merge lane only: true holds a pull request for a changed path alone, on the risk scorer's path floor and denied-paths (`high-path:` and `review-path:`), enable-auto-merge's and ci-status's hold paths. Absent or false: no path holds it; the gate report lists each skipped hold. Unsafe or aliasing paths, the manifest review, cost holds and the trusted-actor widening count either way. The local babysit lane always holds paths."
"description": "Controls the pr-merge lane's path holds and ci-status's exempt-author and App holds on trust-gate paths. True holds a pull request for a changed path alone, on the risk scorer's path floor and denied-paths (`high-path:` and `review-path:`), enable-auto-merge's and ci-status's hold paths. Absent or false: no path holds it, except that ci-status still holds a Dependabot pull request that changes a trust-gate path; the gate report lists each skipped hold. Unsafe or aliasing paths, the manifest review, cost holds and the trusted-actor widening count either way. The local babysit lane always holds paths."
},
"c2-contradictions": {
"type": "boolean",
Expand Down
Loading
Loading