Skip to content

The merge policy scans a pinned change for loosened gates in Go (frozen behavior) #860

Description

@tbhb-agent

Problem

The loosened-gate scan is the part of merge-policy.py (about 300 lines: comment and exclusion patterns, version-pin classification, constitutional paths, scan_loosening and inspect) that decides whether a pull request weakens a gate or touches a golden or constitutional file. It reads the pinned base and head, never the working tree, and its JSON is what unattended merge gates judge. It is Python run through uv, it is on the golden list, and it is under the shell freeze in #588.

This child ports the frozen behavior as it is on the main branch today. The open fixes #292 and #313 change the shell and are parked: they are re-landed as Go fixes after this port and are not prerequisites or requirements here.

Part of #324, within #588. Child 02 in #324's Children list. Replaces the scan and inspect half of packages/agents/source/skills/merge-pr/shared/scripts/merge-policy.py.

Acceptance criteria

  1. AC1: Given a base and head commit and the policy keys (golden paths, loosening markers, gate configuration paths, owner paths, disposable ignored paths), when agentrepo merge policy inspect runs, then it prints JSON whose findings (a list of path and reason pairs) and owner_paths equal the frozen helper's output on the same fixtures.
  2. AC2: Given a changed path that matches the constitutional-path pattern read from the pinned base, when the scan runs, then a changes a constitutional file finding is reported for it; given a changed path that matches the owner-path pattern, then it is listed in owner_paths (deletions and renames included) and is not by itself a finding; the two matches are independent, so a path that matches both is reported as a finding and also listed in owner_paths, exactly as the frozen helper does.
  3. AC3: Given a changed golden path that the base lock owns remotely, when the scan runs, then no golden or loosening finding is reported for it; given any other golden path, then a changes a golden file finding is reported.
  4. AC4: Given a newly added active suppression marker in a comment after code, or a newly added exclusion line in a gate configuration file, when the scan runs, then an adds a suppression or exclusion finding is reported; given a full-line comment, marker text inside a quoted value, or the exempt vendored nolint case, then none is.
  5. AC5: Given a removed hook or gate line in a gate configuration file, when the scan runs, then a removes a hook or gate finding is reported, except when a lockfile's removed checksums are all re-recorded by added ones.
  6. AC6: Given a diff that edits only version pins in the pins file form, when the scan runs, then findings is empty, even if golden or constitutional paths matched; given any other finding alongside, then all findings are reported.
  7. AC7: Given a base or head that cannot be resolved, a pinned change with no paths, or a policy value that does not compile, when the command runs, then it exits 1 with merge policy unreadable: <reason> and prints no JSON.
  8. AC8: Non-functional: the scan reads Git objects with no diff driver, text conversion or repository-controlled command, and the new command runs on macOS, Linux and Windows in CI.

Scope and non-goals

Scope: the scan, pin-only diff recognition, the owner-path and constitutional-path handling, and the agentrepo merge policy inspect command, with tests ported from loosens.bats, pins.bats and replacements.bats.

Non-goal: the behavior of #292 and #313 (gate replacement pairing, grouped reports, extended exclusions and lock semantics): they stay parked and are re-landed as Go fixes after this port. Non-goal: owner approval and required checks (child 03). Non-goal: editing the shell scripts, which stay the parity oracle until child 14.

Approach

Meet AC1 to AC8 with failing cases first: build scratch repositories from the fixtures in the three Bats files, record the Python helper's JSON, and match it in Go. Fixtures that only pass under the parked fixes are not part of this child. Mechanism is the implementer's choice.

Dependencies

Blocked by: #859, #333.

Prerequisites: #321 (configuration readers) and #333. #292 and #313 are not dependencies.

Size

M. One pull request.

Verify plan

  • AC1, AC2, AC3, AC4, AC5, AC6: golden JSON comparison against the frozen helper on scratch repositories, with a case per finding reason and per exemption; for AC2 a constitutional-only path, an owner-only path and a path matching both (the policy-file path that is on both lists today).
  • AC7: error-path table checking exit status and streams.
  • AC8: a test that sets a hostile diff driver and textconv in the scratch repository and sees them ignored; the CI matrix run.
  • 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

A scanner that finds less than the Python helper would let a loosened gate through the unattended path. Golden comparison on every fixture, plus the exemption cases, are the controls, and nothing calls the Go command until child 14. Undo: revert; no caller depends on it yet.

Operator authority

None. No owner-tier path is edited here; protection of the new Go files is settled by #753 before any rollout.

Activity

  1. tbhb-agent commented on Oct 27, 2026

    @tbhb-agent
    ContributorAuthor

    Refinement: READY — The merge policy scans a pinned change for loosened gates in Go (frozen behavior)
    Model: gpt-6-astra

    Child 02 The merge policy scans a pinned change for loosened gates in Go

    Verdict: READY

    Checked: AC2 now correctly treats constitutional and owner matches independently and verifies all three combinations. This matches packages/agents/source/skills/merge-pr/shared/scripts/merge-policy.py:508 and packages/agents/source/skills/merge-pr/shared/scripts/merge-policy.py:523. The frozen-first scope and deferred #292/#313 disposition match the binding decision and index.

    Gaps: None.

    Split: None needed; the later behavior fixes remain separate.

    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

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:readyPassed the Definition of Ready; may be picked up

    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