Repository navigation
Description
Problem
ma_gates and its helpers in merge-agent.sh (about 150 of its 235 lines) are the unattended merge authority: the unattended context and clean-tree check, the configured gh_login match, the GraphQL login rules for required_reviewer and merge_owner, the exact-head approval, the owner-review label, the policy inspection and evaluation, the owner override, the required-checks verdict and the readiness command. The file is on the golden and owner path lists, it needs uv, and it is under the shell freeze in #588.
Part of #324, within #588. Child 05 in #324's Children list. Replaces the gate half of packages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh. The exact-head approval selection is owned by #761; this child consumes it and orchestrates the gates.
Acceptance criteria
- AC1: Given unattended mode, when the context check runs, then it refuses a dirty tree, a missing
gh_loginand a missing check judge, and it no longer requiresuv. - AC2: Given the gh account differs from the configured
gh_login, when the identity gate runs, then it refuses and names both logins. - AC3: Given
required_reviewerormerge_ownerending in[bot], when the gate reads it, then it refuses and names the key and the login to use instead. - AC4: Given a required reviewer whose latest decisive review is not APPROVED on the exact current head, or whose author type differs from a configured
required_reviewer_type, when the gate runs, then it holds withWAITING_REVIEW. - AC5: Given the owner-review label, when the gate runs, then it refuses with
needs-owner; given only golden-file findings and an unedited APPROVED review by the required App on the exact head statingLoosens: no, then no owner approval is required and the owner rule isApp review states Loosens: no; given golden files without that review, or any loosened gate, then it requires an exact-head APPROVED review bymerge_ownerand prints the override line naming the approving login; given a checkout whose.agents/agent-skills.confdiffers from the pinned base, then the golden, owner and loosening settings andowner_review_labelcome from the base through Read gate settings from the pinned base in Go #980's reader and the difference is reported. - AC6: Given a pull request that is not open, ready, MERGEABLE and CLEAN, or whose required check set is empty, when the gate runs, then it refuses.
- AC7: Given a required check that is missing, skipped, neutral, failing, still running or unreadable, when the gate runs, then it refuses or holds with the same outcome and status as
agentrepo checks evaluategives for that state, and a stale merge-ref skip is reported with the same hint. - AC8: Given the final pass before the merge write, when the gate runs again, then it reuses the pinned policy and required-check names, re-reads live approvals and live check results, and evaluates them against the pinned policy and required names: it refuses when the re-read state fails those gates, and passes when the re-read state still satisfies them (a newer qualifying approval or another passing check result does not refuse).
- AC9: Given
merge_ready_cmdis configured, when the first pass runs, then the executable is invoked with the repository root, the pull request number and the pinned head and a failing exit status refuses with that status; given it names a non-executable, then it refuses; the final pass does not invoke it again; given a checkout whose.agents/agent-skills.confdiffers from the pinned base, thenmerge_ready_cmd,gate_config_pathsandruleset_dircome from the base through Read gate settings from the pinned base in Go #980's reader and the difference is reported. - AC10: Given a machine with or without a delegation or session grant, when the gates pass, then the gate result grants no authority: it does not itself confirm the merge, which is the confirmation chain of child 25.
- AC11: Non-functional: authority settings are read only from machine configuration, and the gates run against fakes on macOS, Linux and Windows in CI.
- AC12: Given a
merge-proragent-merge-prskill directory that differs from the base lock, when the first pass runs, then the gate refuses through Run the skill-directory integrity gate in the merge entry points #982'sagentrepo merge integrity, runs helpers only from the trusted snapshot and removes the snapshot on every exit path; the live head and base re-reads stay in this issue, and the gate adopts the machine reader of feat(config): read merge authority from machine configuration #942.
Scope and non-goals
Scope: the unattended gate sequence for the first and the final pass, using children 02, 03, 04 and 21 and the approval selection of #761, with tests ported from policy.bats, confirmation.bats and workflow.bats.
Non-goal: the exact-head approval predicate itself, which #761 owns. Non-goal: the post-merge retargeting, remote-message verification and report (child 11). Non-goal: the squash lint (child 06). Non-goal: widening what any repository configuration can choose; reviewer and authority settings stay machine-only.
Approach
Meet AC1 to AC12 with failing cases first: reproduce each die and exit status of the shell gate on the same snapshots, then match them. Mechanism is the implementer's choice.
Dependencies
Blocked by: #860, #861, #862, #863, #333, #761, #980, #982.
Prerequisites: #321 (agent context, GraphQL identity, machine configuration), #761 (exact-head approval) merged first, #333, #980 (pinned-base settings reader) and #982 (integrity command and snapshot).
Size
M. One pull request.
Verify plan
- AC1, AC2, AC3, AC9: table-driven refusals with fake
gh, machine configuration fixtures and a stub readiness executable that records its arguments; AC9 adds a divergent-checkout case formerge_ready_cmd,gate_config_pathsandruleset_dir. - AC4, AC5, AC6: snapshot fixtures for each review and label state, including the golden-only waiver and the golden-without-waiver path, comparing the printed lines to the shell gate's (cases at
tests/skills/agent-merge-pr/workflow.bats). AC5 adds a divergent-checkout case whose golden, owner, loosening and label settings differ from the base, asserting the base values are used and the difference is reported. - AC7: required-check fixtures for each state listed, comparing status and message with the shell gate.
- AC8: tests that change a live approval and, separately, a live check result between the two passes so that it invalidates a gate (the second pass refuses) and so that it still qualifies (the second pass passes), and one that confirms the pinned policy was not re-read.
- AC10: a test that sets session and delegation grants and asserts the gate result is unchanged and that no confirmation is recorded by the gates; confirmation itself is proved in child 25.
- AC11: a test that supplies authority keys from the repository file and sees them ignored; the CI matrix run.
- AC12: tests with a skill directory that differs from the base lock, asserting the first pass refuses through
agentrepo merge integrity, helpers run only from the snapshot (a sentinel-writing checkout helper never runs), and the snapshot directory is gone after a pass, a refusal and a failure. - Definition of done: D1 each AC is verified at the merged head, with the commands and results cited in the pull request's Verification. D2 an independent review approves the exact merged head, and every finding has a recorded disposition. D3 required checks pass with no gate loosened. D4 the leak scans the repository specifies are clean, and every post made for this work passes the per-post leak review before it is posted. D5 every commit is signed. D6 the documentation matches the change or the Verification says why there is no impact. D7 every commit has an
Assisted-bytrailer and the pull request has theprovenance:agent-assistedlabel. D8 the pull request stays within the size limits. D9 follow-ups are filed as issues and listed under Related. D10 the merge closes the issue through a closing reference, the board shows Done, and the finalStatus:comment names the merge commit.
Risks
This is the authority path: a gate that passes where the shell refused would merge unreviewed work. Case-for-case parity with the shell refusals is the control, and nothing calls the Go gate until child 14. Undo: revert; the shell gate is untouched.
Operator authority
None. The Go files are new, and nothing in this area edits an owner-tier path: deleting merge-agent.sh and merge-policy.py is the single cutover under #588.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Work type
Projects
- StatusShow more project fieldsBacklog
Activity
tbhb-agent commentedon Oct 27, 2026
Refinement: READY — The unattended merge gates run in Go
Model: gpt-6-astra
Child 05 The unattended merge gates run in Go
Verdict: READY
Checked: AC8 now requires reevaluation rather than refusal on every live change, with both invalidating and still-valid changes verified. Confirmation ownership correctly points to child 25. Required checks, readiness invocation and golden-only waivers match
packages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh:150,packages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh:169andpackages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh:177. Approval selection remains owned by #761.Gaps: None.
Split: None needed.
Definition of done
The definition of done for this issue (Feature). Tick each item and give its evidence.
check-leaks.shwith the repository's private-strings list, and the leak review of each post.docs/, CHANGELOG or help text), or the Verification section says "No doc impact" and why.provenance:agent-assistedlabel.Status:comment names the merge commit.mise run checkis green, and so are the coverage floorsmise run cover-go-checkandmise run cover-py-check, whichcheckdoesn't run.packages/agents/source/commits whatmise run generate-skills, thenmise run skill-tokens, thenapm installrewrite, in that order, andcheck-generated-skills(part oflint) passes.docs/agent-skills-migration.mdor the adoption docs, or the PR's Verification says "No consumer impact" and why.Round: 3 of 3