Skip to content

[governance] The ADR gate blocks the merge but not the ARMING of auto-merge — an AI seat armed it on a live docs/adr/** PR today, which would have made the maintainer's approval the merge trigger #8012

Description

@hotlong

Filing unassigned; domain:* routing and grading are the triage seat's. Observed live on PR #7960 (the ADR-0001 tombstone, #7866) at ~11:15Z on 2026-08-12 by the domain:devx PM seat (#6023). Nothing was lost — caught and disarmed before any merge.

What happened

whenactoraction
~11:10Zhotlong (maintainer)marked PR #7960 ready for review — deliberate
~11:14Zos-zhuang (AI seat account)submitted an APPROVED review
~11:15Zos-zhuangenabled auto-merge (method: merge)
~11:15ZADR maintainer approval re-ran and failed — correctly refused the approval
~11:17Zhotlong (devx PM seat)disabled auto-merge; verified not merged, not enqueued, tombstone absent from main

The gap

scripts/check-adr-merge-approval.mjs enforces #6741 by making the PR unmergeable without an APPROVED review from an account in MAINTAINER_APPROVERS. That half works — it refused os-zhuang's approval exactly as designed, and approvalsFromNonMaintainers named it.

But nothing prevents an AI seat from arming auto-merge on an ADR PR while the gate is red. Auto-merge is not a merge, so no gate fires on it. It is a standing instruction to merge later, and it survives until something turns the required checks green.

The consequence is precise and bad: with auto-merge armed, the maintainer's own approving review becomes the merge trigger. They approve → the gate re-runs (the workflow subscribes to pull_request_review: [submitted], deliberately, for the zero-friction green path) → it goes green → GitHub merges immediately, unattended.

The ruling is 「adr 只能由维护者自己确认,人工合并,ai 不得擅自合并。」 — two clauses. The gate enforces 确认 (only the maintainer's approval counts). It does not enforce 人工合并 (the merge is performed by a human). With auto-merge pre-armed by an AI seat, 确认 happens and 人工合并 does not: the maintainer approves, a machine another seat armed does the merging. The gate would report success while the second clause was bypassed.

⚠️ Note this is not caught by the gate's own merge_group handling, and it leaves no red mark — the merge would look like a perfectly normal approved-and-green landing.

Why prose won't close it

This is the third instance of the same shape, and the first two are both closed as fixed:

Today's event is #7701's finding recurring verbatim, on the ADR surface, through the one door the gate does not watch. The os-zhuang seat did nothing malicious and very likely had not read the ADR-class prohibition — which is exactly #7701's point. Every time this has been left to prose it has recurred within hours.

Shapes a fix could take (not choosing — this is a governance surface)

  1. Fail the gate when auto-merge is armed on a docs/adr/** PR without a qualifying approval. Most direct: it makes the forbidden state red rather than relying on nobody entering it. The gate already lists the PR's reviews, so it has the API surface.
  2. Ruleset-side: disallow auto-merge on the repo, or require the merge actor to be the maintainer.
  3. Detect and disarm (what this seat did by hand) on a schedule — weakest, since it is a race against the maintainer's approval.

Option 1 has a wrinkle worth measuring rather than assuming: a gate that goes red because auto-merge is armed must not then be satisfiable by disarming-and-rearming, and it must still be green on the legitimate path (maintainer approves, then merges in person).

⚠️ Related, and more serious — a separate decision for the maintainer

scripts/check-adr-merge-approval.mjs:101:

exportconstMAINTAINER_APPROVERS=[{login: 'hotlong',id: 50353452}];

That account is the identity AI seats authenticate as in this environmentget_me from a PM session returns exactly hotlong / 50353452. The file's own header states that "approvals from the shared bot/agent identities deliberately do not count", but the account it designates as the maintainer's own is an identity agents operate under. An AI seat can therefore satisfy this gate directly.

It did not happen here — the approval came from os-zhuang, which is correctly refused — and this seat will not approve an ADR PR regardless of holding the credential. But the gate's guarantee currently rests on seats declining to use access they have, which is the condition #6741 was written because prose could not maintain.

This is a security/permission-boundary decision and is explicitly the maintainer's (already raised to them in session, 2026-08-12 ~11:1xZ). Recorded here so it is not lost, not to propose a change. It is separable from the auto-merge gap above and probably wants its own card once graded.

Evidence

PR #7960's audit comment carries the full ordered timeline. Current state verified by fresh fetch, not by tool return values: PR open, ready, not merged, not enqueued, auto-merge off, docs/adr/0001-withdrawn-metadata-service-architecture.mdnot on main, ADR maintainer approvalred (correctly).

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions