Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .agents/skills/agent-merge-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Install sibling `merge-pr` and `review-squash-message` from the same package. Th
1. Run `bash .agents/skills/agent-merge-pr/scripts/preflight.sh <pr>`. Stop for a dirty tree, interrupted Git operation, detached head, missing machine identity or required reviewer, missing required checks, or unreadable policy. No checks means no merge.
2. Read the published description and all commits. Run `bash .agents/skills/agent-merge-pr/scripts/squash-message.sh <pr>` for the full briefing and skeleton. Write the squash body in `SQUASH_AGENTMSG`, explaining why the branch exists. Keep the PR reference and complete trailers. Add closing references only for work this delivery completes.
3. Run `bash .agents/skills/agent-merge-pr/scripts/lint-squash-msg.sh <pr>`, then `bash .agents/skills/agent-merge-pr/scripts/review.sh <pr>`. The lint wrapper reads cspell policy from the pinned pull request head. Under the policy and approval checks, the shared review script gathers pinned Git objects and independently reviews the message. Review stamps bind the message, head, base, and repository configuration. Findings return 2. The persistent bound returns 3. Failed execution, timeout, and input drift don't spend a finding round.
4. Run `bash .agents/skills/agent-merge-pr/scripts/merge.sh <pr>`. The shared merger requires the stamped inputs, a current exact-head approval from machine `required_reviewer`, successful required checks, readiness, and session pre-approval or machine delegation for `merge`. It checks live policy and authority again after delegation and changing the base branches of dependent pull requests. It never uses administrator or automatic merge.
4. Run `bash .agents/skills/agent-merge-pr/scripts/merge.sh <pr>`. The shared merger requires the stamped inputs, a current exact-head approval from machine `required_reviewer` or, failing that, from `merge_owner`, successful required checks, readiness, and session pre-approval or machine delegation for `merge`. It checks live policy and authority again after delegation and changing the base branches of dependent pull requests. It never uses administrator or automatic merge.
5. Report the full merge commit, owner paths, any owner override and its login, and retained branches or worktrees. A failed or uncertain write requires inspection before retrying. A remote message mismatch preserves evidence and skips cleanup.

Repository behavior comes from declarative `.agents/agent-skills.conf`. Authorities come only from machine configuration: `gh_login`, `required_reviewer`, optional `required_reviewer_type`, optional `merge_owner`, reviewer selection, and delegation. Golden files and detected gate loosening require an APPROVED review from `merge_owner` on the exact current head. A later push invalidates it. The owner-review label still holds the merge.
Repository behavior comes from declarative `.agents/agent-skills.conf`. Authorities come only from machine configuration: `gh_login`, `required_reviewer`, optional `required_reviewer_type`, optional `merge_owner`, reviewer selection, and delegation. Golden files and detected gate loosening require an APPROVED review from `merge_owner` on the exact current head. A later push invalidates it. The same approval by `merge_owner` also satisfies the `required_reviewer` gate, and the report states the approving login. The owner-review label still holds the merge.

The protected-path scan reads APM ownership from the pinned base lockfile and skips non-local deployments. It ignores full comment lines and matches exclusion keys rather than words inside values. Repository policy changes require the same owner approval. Reviewers must still identify policy changes the scan can't detect.

Expand Down
6 changes: 3 additions & 3 deletions .agents/skills/agent-merge-pr/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
"bundled_files_tokens": 331,
"generated_by": "tools/skill-tokens.sh",
"manifest": {
"body_tokens": 933,
"bytes": 4832,
"body_tokens": 969,
"bytes": 4992,
"frontmatter_tokens": 58,
"tokens": 992
"tokens": 1028
},
"model": "gpt-5.6-sol",
"skill": "agent-merge-pr",
Expand Down
12 changes: 10 additions & 2 deletions .agents/skills/merge-pr/scripts/merge-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ ma_identity() {
# Reused before review and again immediately before every merge write.
ma_gates() {
ma_require_gates || return 0
local view=$1 pr=$2 base_oid=$3 final=${4:-false} head base reviewer reviewer_type label ready config key value required default dir st root encoded merge_base
local view=$1 pr=$2 base_oid=$3 final=${4:-false} head base reviewer reviewer_type owner label ready config key value required default dir st root encoded merge_base
ma_context || return $?
st=$(dt_state_dir) || return $?
root=$(dt_root) || return $?
Expand All @@ -121,7 +121,15 @@ ma_gates() {
'' | Bot | User) ;;
*) dt_die "required_reviewer_type must be Bot or User when set" ;;
esac
"$_DEVTOOLS_AGENTREPO_BIN" merge approval --file "$view" --login "$reviewer" --head "$head" --author-type "$reviewer_type" || dt_die "WAITING_REVIEW: $reviewer must approve the current head"
if ! "$_DEVTOOLS_AGENTREPO_BIN" merge approval --file "$view" --login "$reviewer" --head "$head" --author-type "$reviewer_type"; then
# The operator's own exact-head approval counts as the independent review.
owner=$(ma_login merge_owner) || return $?
if [ -n "$owner" ] && "$_DEVTOOLS_AGENTREPO_BIN" merge approval --file "$view" --login "$owner" --head "$head"; then
printf 'reviewer satisfied by merge_owner: %s approved %s\n' "$owner" "$head"
else
dt_die "WAITING_REVIEW: $reviewer or merge_owner must approve the current head"
fi
fi
label=$(dt_owner_review_label) || return $?
if jq -e --arg label "$label" '.labels | any(.name == $label)' "$view" >/dev/null; then
dt_die "needs-owner: the PR has the owner-review label"
Expand Down
6 changes: 3 additions & 3 deletions .agents/skills/merge-pr/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
"tokens": 375
},
{
"bytes": 11068,
"bytes": 11455,
"path": "scripts/merge-agent.sh",
"tokens": 3217
"tokens": 3322
},
{
"bytes": 29915,
Expand Down Expand Up @@ -74,7 +74,7 @@
"tokens": 392
}
],
"bundled_files_tokens": 40864,
"bundled_files_tokens": 40969,
"generated_by": "tools/skill-tokens.sh",
"manifest": {
"body_tokens": 3802,
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/agent-merge-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ Install sibling `merge-pr` and `review-squash-message` from the same package. Th
1. Run `bash .claude/skills/agent-merge-pr/scripts/preflight.sh <pr>`. Stop for a dirty tree, interrupted Git operation, detached head, missing machine identity or required reviewer, missing required checks, or unreadable policy. No checks means no merge.
2. Read the published description and all commits. Run `bash .claude/skills/agent-merge-pr/scripts/squash-message.sh <pr>` for the full briefing and skeleton. Write the squash body in `SQUASH_AGENTMSG`, explaining why the branch exists. Keep the PR reference and complete trailers. Add closing references only for work this delivery completes.
3. Run `bash .claude/skills/agent-merge-pr/scripts/lint-squash-msg.sh <pr>`, then `bash .claude/skills/agent-merge-pr/scripts/review.sh <pr>`. The lint wrapper reads cspell policy from the pinned pull request head. Under the policy and approval checks, the shared review script gathers pinned Git objects and independently reviews the message. Review stamps bind the message, head, base, and repository configuration. Findings return 2. The persistent bound returns 3. Failed execution, timeout, and input drift don't spend a finding round.
4. Run `bash .claude/skills/agent-merge-pr/scripts/merge.sh <pr>`. The shared merger requires the stamped inputs, a current exact-head approval from machine `required_reviewer`, successful required checks, readiness, and session pre-approval or machine delegation for `merge`. It checks live policy and authority again after delegation and changing the base branches of dependent pull requests. It never uses administrator or automatic merge.
4. Run `bash .claude/skills/agent-merge-pr/scripts/merge.sh <pr>`. The shared merger requires the stamped inputs, a current exact-head approval from machine `required_reviewer` or, failing that, from `merge_owner`, successful required checks, readiness, and session pre-approval or machine delegation for `merge`. It checks live policy and authority again after delegation and changing the base branches of dependent pull requests. It never uses administrator or automatic merge.
5. Report the full merge commit, owner paths, any owner override and its login, and retained branches or worktrees. A failed or uncertain write requires inspection before retrying. A remote message mismatch preserves evidence and skips cleanup.

Repository behavior comes from declarative `.agents/agent-skills.conf`.

Authorities come only from machine configuration: `gh_login`, `required_reviewer`, optional `required_reviewer_type`, optional `merge_owner`, reviewer selection, and delegation. Golden files and detected gate loosening require an APPROVED review from `merge_owner` on the exact current head. A later push invalidates it. The owner-review label still holds the merge.
Authorities come only from machine configuration: `gh_login`, `required_reviewer`, optional `required_reviewer_type`, optional `merge_owner`, reviewer selection, and delegation. Golden files and detected gate loosening require an APPROVED review from `merge_owner` on the exact current head. A later push invalidates it. The same approval by `merge_owner` also satisfies the `required_reviewer` gate, and the report states the approving login. The owner-review label still holds the merge.

The protected-path scan reads APM ownership from the pinned base lockfile and skips non-local deployments. It ignores full comment lines and matches exclusion keys rather than words inside values. Repository policy changes require the same owner approval. Reviewers must still identify policy changes the scan can't detect.

Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/agent-merge-pr/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
"bundled_files_tokens": 621,
"generated_by": "tools/skill-tokens.sh",
"manifest": {
"body_tokens": 1553,
"bytes": 5001,
"body_tokens": 1605,
"bytes": 5161,
"frontmatter_tokens": 180,
"tokens": 1737
"tokens": 1789
},
"model": "claude-opus-5",
"skill": "agent-merge-pr"
Expand Down
12 changes: 10 additions & 2 deletions .claude/skills/merge-pr/scripts/merge-agent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ ma_identity() {
# Reused before review and again immediately before every merge write.
ma_gates() {
ma_require_gates || return 0
local view=$1 pr=$2 base_oid=$3 final=${4:-false} head base reviewer reviewer_type label ready config key value required default dir st root encoded merge_base
local view=$1 pr=$2 base_oid=$3 final=${4:-false} head base reviewer reviewer_type owner label ready config key value required default dir st root encoded merge_base
ma_context || return $?
st=$(dt_state_dir) || return $?
root=$(dt_root) || return $?
Expand All @@ -121,7 +121,15 @@ ma_gates() {
'' | Bot | User) ;;
*) dt_die "required_reviewer_type must be Bot or User when set" ;;
esac
"$_DEVTOOLS_AGENTREPO_BIN" merge approval --file "$view" --login "$reviewer" --head "$head" --author-type "$reviewer_type" || dt_die "WAITING_REVIEW: $reviewer must approve the current head"
if ! "$_DEVTOOLS_AGENTREPO_BIN" merge approval --file "$view" --login "$reviewer" --head "$head" --author-type "$reviewer_type"; then
# The operator's own exact-head approval counts as the independent review.
owner=$(ma_login merge_owner) || return $?
if [ -n "$owner" ] && "$_DEVTOOLS_AGENTREPO_BIN" merge approval --file "$view" --login "$owner" --head "$head"; then
printf 'reviewer satisfied by merge_owner: %s approved %s\n' "$owner" "$head"
else
dt_die "WAITING_REVIEW: $reviewer or merge_owner must approve the current head"
fi
fi
label=$(dt_owner_review_label) || return $?
if jq -e --arg label "$label" '.labels | any(.name == $label)' "$view" >/dev/null; then
dt_die "needs-owner: the PR has the owner-review label"
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/merge-pr/tokens.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
"tokens": 616
},
{
"bytes": 11068,
"bytes": 11455,
"path": "scripts/merge-agent.sh",
"tokens": 5293
"tokens": 5464
},
{
"bytes": 29915,
Expand Down Expand Up @@ -79,7 +79,7 @@
"tokens": 610
}
],
"bundled_files_tokens": 66702,
"bundled_files_tokens": 66873,
"generated_by": "tools/skill-tokens.sh",
"manifest": {
"body_tokens": 6180,
Expand Down
4 changes: 4 additions & 0 deletions .devtools/shell-allowlist.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,7 @@ commands = [
"id",
"sleep",
]

# Operator-approved exception for #1053; remove when the Go port in #864 lands.
# Exact source path only; generated copies are already excluded by --changed.
exemptions = ["packages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh"]
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Repository configuration supplies squash lint, readiness, ruleset location, owne

devtools keeps its merge patterns in `.agents/agent-skills.conf`. They protect the published payload, workflows, rule sets, gate definitions, and skill guards. Cleanup permits build and cache output and preserves local settings and agent worktrees. Policy errors include the refusal reason and specify any empty pattern.

Golden files and detected gate loosening require an exact-head APPROVED review by machine `merge_owner`, also available as `DEVTOOLS_MERGE_OWNER`. Use the GraphQL login without `[bot]` for `merge_owner` too. Keep this authority a person: an App owner override can approve its own golden-file waivers. Repositories can't choose this authority, and pushing invalidates approval.
Golden files and detected gate loosening require an exact-head APPROVED review by machine `merge_owner`, also available as `DEVTOOLS_MERGE_OWNER`. Use the GraphQL login without `[bot]` for `merge_owner` too. Keep this authority a person: an App owner override can approve its own golden-file waivers. Repositories can't choose this authority, and pushing invalidates approval. The same exact-head approval by `merge_owner` also satisfies the `required_reviewer` gate when the required reviewer hasn't approved, because the operator's approval counts as the independent review. The merge report prints `reviewer satisfied by merge_owner` with the approving login and head. Required checks, the owner-review label, write authority, and a clean mergeable state still apply.

When using an override, the merge report specifies the approving login. It doesn't waive the owner-review label, required checks, independent review, or write authority.

Expand Down
Loading
Loading