Skip to content

The unattended merge gates run in Go #864

Open

Description

@tbhb-agent

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

  1. AC1: Given unattended mode, when the context check runs, then it refuses a dirty tree, a missing gh_login and a missing check judge, and it no longer requires uv.
  2. AC2: Given the gh account differs from the configured gh_login, when the identity gate runs, then it refuses and names both logins.
  3. AC3: Given required_reviewer or merge_owner ending in [bot], when the gate reads it, then it refuses and names the key and the login to use instead.
  4. 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 with WAITING_REVIEW.
  5. 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 stating Loosens: no, then no owner approval is required and the owner rule is App review states Loosens: no; given golden files without that review, or any loosened gate, then it requires an exact-head APPROVED review by merge_owner and prints the override line naming the approving login; given a checkout whose .agents/agent-skills.conf differs from the pinned base, then the golden, owner and loosening settings and owner_review_label come from the base through Read gate settings from the pinned base in Go #980's reader and the difference is reported.
  6. 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.
  7. 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 evaluate gives for that state, and a stale merge-ref skip is reported with the same hint.
  8. 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).
  9. AC9: Given merge_ready_cmd is 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.conf differs from the pinned base, then merge_ready_cmd, gate_config_paths and ruleset_dir come from the base through Read gate settings from the pinned base in Go #980's reader and the difference is reported.
  10. 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.
  11. AC11: Non-functional: authority settings are read only from machine configuration, and the gates run against fakes on macOS, Linux and Windows in CI.
  12. AC12: Given a merge-pr or agent-merge-pr skill 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's agentrepo 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 for merge_ready_cmd, gate_config_paths and ruleset_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-by trailer and the pull request has the provenance:agent-assisted label. 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 final Status: 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.

Activity

  1. tbhb-agent commented on Oct 27, 2026

    @tbhb-agent
    ContributorAuthor

    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:169 and packages/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.

    • D1 The author verified each AC on the merged head, and the Verification section of the pull request cites each AC ID with its evidence: the command and its result, or a link.
    • D2 An independent reviewer approved the exact merged head, and the author resolved each finding or filed it as a follow-up.
    • D3 The required checks pass on that head, and any loosened gate has the owner's approval of that exact head.
    • D4 The leak scans come back clean: gitleaks, devtools' check-leaks.sh with the repository's private-strings list, and the leak review of each post.
    • D5 The author signed each commit, the squash included.
    • D6 The docs match the change (README, docs/, CHANGELOG or help text), or the Verification section says "No doc impact" and why.
    • D7 The commits and the squash have Assisted-by trailers, and the pull request has the provenance:agent-assisted label.
    • D8 The pull request stays within the size limits, or the owner approved its exact head over the hard limit.
    • D9 The author files follow-ups and deferred findings as issues with at least a Problem and numbered AC and lists them under the Related section of the pull request. Any work left in the code links its issue.
    • D10 The merge closes the issue through a closing reference and the board shows Done. The final Status: comment names the merge commit.
    • devtools-1 mise run check is green, and so are the coverage floors mise run cover-go-check and mise run cover-py-check, which check doesn't run.
    • devtools-2 A change to skill sources under packages/agents/source/ commits what mise run generate-skills, then mise run skill-tokens, then apm install rewrite, in that order, and check-generated-skills (part of lint) passes.
    • devtools-3 A consumer-visible change (the vendored payload, a skill, a reusable workflow, a task or a pin) has its consumer steps in docs/agent-skills-migration.md or the adoption docs, or the PR's Verification says "No consumer impact" and why.

    Round: 3 of 3

  2. added
    refinement:activeA refinement round is open; not ready for implementation
    and removed
    refinement:readyPassed the Definition of Ready; may be picked up
    on Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    refinement:activeA refinement round is open; not ready for implementation

    Fields

    Priority

    None yet

    Work type

    None yet

    Projects

    • Status
      Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions