Skip to content

[governance] ADR maintainer approval is unsatisfiable on any PR the maintainer authored — GitHub forbids self-approval, so the gate is permanently red exactly when the human IS driving #8161

Description

@hotlong

Filed by the domain:devx PM seat (#6023) after the maintainer stated in session on 2026-08-12 ~18:2xZ that they judge the #7960 blockage to be a CI-rule defect rather than a PR defect. Measured on origin/main; #8012 anticipated this ("probably wants its own card once graded") and this is that card. Unassigned — recording only.

The deadlock, mechanically

scripts/check-adr-merge-approval.mjs has exactly one pass condition. From decide():

  • latestMaintainerReviewState(reviews) walks the PR's reviews, keeps only those whose author matches MAINTAINER_APPROVERSby numeric account id, keeps only the state-setting kinds (APPROVED / CHANGES_REQUESTED / DISMISSED), and returns the last one;
  • the gate returns ok: trueonly when that value is APPROVED. There is no other exit that passes.

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

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

One entry. And scripts/check-required-contexts.mjs:194 records that ADR maintainer approval is a required context, put there deliberately after #6942/#6962 landed while it sat outside the required set.

Now compose that with a GitHub platform rule: an account cannot submit a review on a pull request it authored. So for any PR whose user.login is hotlong:

  • the only account whose approval the gate accepts is the one account GitHub will not let approve;
  • therefore latestMaintainerReviewState can never return APPROVED;
  • therefore a required context is permanently red;
  • therefore the PR cannot be merged through the normal path, or enter the merge queue, no matter what anyone does on it.

Live instance: PR #7960 (ADR-0001 tombstone, #7866). user.login is hotlong. The maintainer has marked it ready, has armed auto-merge, and reports that nothing they try lands it. That is not a misuse — it is the only possible outcome of the rule as written.

Why this is a rule defect and not "the gate doing its job"

The ruling the gate implements (#6741) is 「adr 只能由维护者自己确认,人工合并,ai 不得擅自合并。」 The gate does not measure that. It measures a proxy: "an APPROVED review exists from account 50353452". The proxy was sound only while maintainer-account ≠ author-account — historically true, because ADR PRs were authored by os-zhuang / os-help / os-project-manager. Cloud dev sessions in this environment now author under hotlong, so the proxy's premise is gone.

⚠️The proxy is not merely broken — it is inverted. Under the current single shared identity:

casewhat the gate should dowhat it does
PR authored by hotlong (the human is the one driving it)pass once the human confirmscan never pass — self-approval is impossible
PR authored by some other account, with an AI seat holding the hotlong credentialrefuse — an AI must not confirm on the maintainer's behalfpasses — the seat can submit the approving review itself

So the gate is closed on the case it was meant to admit and open on the case it was meant to stop. #8012 recorded the second row already; this card is the first. Both rows have one root cause: the human maintainer and the agent fleet are the same GitHub account, and an account-identity gate is not implementable under that condition.

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

1. Fix the identity (closes both rows, and #8012 with them). Give the agent fleet its own GitHub account; reserve hotlong for the human. Then ADR PRs are authored by the bot, the human's approval is both possible and meaningful, and the existing gate becomes correct as written with no code change. Highest cost (org/token work, outside CI), and the only shape that restores the gate's guarantee rather than re-routing around it.

2. Admit a second maintainer signal that self-approval does not block. Keep the approval path; additionally pass when the PR author is a maintainer and a maintainer comment carries an explicit confirmation token pinned to the head SHA (e.g. a literal marker plus ac278e6). The SHA pin is load-bearing: an unpinned token survives a force-push and would confirm code nobody looked at. Under shared credentials this adds no real assurance — but it takes none away either, since row 2 shows the approval path is already reachable by a seat. Cheapest unblock; ⚠️ it also makes the gate satisfiable by an AI seat by design rather than by accident, which should be stated out loud rather than discovered later.

3. Ruleset-side bypass for this one PR. Not a fix — the next ADR PR authored by a session lands in the identical hole. Listed only so it is not mistaken for one.

What must not be done, and why it is the tempting one: "the PR author is a maintainer ⇒ pass". Every session-authored ADR PR is authored by hotlong, so that predicate is true on precisely the population the gate exists to catch. It would weld the gate permanently open while still reporting green. Naming it because it is the one-line change an implementer will reach for first.

Establishment

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions