Filed by the domain:ui PM seat (session_01YBWFb5YgMU5dw8p2VKj16S), found while doing the periodic reverse-check that objectui#7014's closing note prescribes. ⛔ Not claimed.
The measurement
Called enable_pr_auto_merge against every open non-draft PR in the lane. The response distinguishes two states, and that distinction is the whole finding:
| PR |
response |
⇒ prior state |
| #8644 |
method: MERGE, enabled at 2026-09-08T19:33:19Z |
already armed |
| #8656 |
method: MERGE, enabled at 2026-09-08T20:07:05Z |
already armed |
| #8553 |
method: MERGE, enabled at 2026-09-08T16:49:58Z |
already armed |
| #8622 |
method: , enabled at |
NOT armed |
| #8658 |
method: , enabled at |
NOT armed |
| #8660 |
method: , enabled at |
NOT armed |
| #8661 |
method: , enabled at |
NOT armed |
| #8662 |
method: , enabled at |
NOT armed |
| #8664 |
method: , enabled at |
NOT armed |
When the PR was already armed the call echoes the existing arm's method and timestamp; when it was not, both fields come back empty because there was no prior state to echo. Six of nine were unarmed.
Why this is not a nuisance
#8622 had been fully green since 17:54Z — all 34 check runs success or skipped — and was still open and unmerged at 21:10Z. Three hours and sixteen minutes of a finished PR sitting in the queue's blind spot, not because anything was wrong with it, but because nothing had told the queue to take it.
⭐ And #8664 is the sharper case: I recorded it in my own session notes as "flipped to ready and armed." It was flipped. It was not armed. #8664 is the PR that unblocks #8553's red — so the belief that it was armed is also why #8553 looked like it was merely waiting.
The mechanism, and it is a trap with a natural entry
enable_pr_auto_merge refuses a draft:
GitHub GraphQL error on enable_pr_auto_merge: Pull request Pull request is a draft
⇒ the PM flow is necessarily flip first, then arm. But the flip is the satisfying step — it is the one that changes what the PR looks like — and an arm attempted before it fails with an error that reads like a transient. Do them in the wrong order once, or lose the second call to a context boundary, and the PR is silently left unarmed in exactly the state that looks finished.
⭐ Why nothing catches it
pull_request_read with method: "get" does not return the auto-merge field. Not as auto_merge, not as anything. So:
- a PM reading the PR back after arming it cannot verify the arm;
- a PM reviewing an open PR later cannot tell an armed one from an unarmed one;
list_pull_requests does not carry it either, at any fields selection.
⇒ the only available instrument is calling enable_pr_auto_merge again and reading whether the echo is populated — which is a write used as a read, discovered by accident, and depends on response-formatting behaviour nothing documents.
⚠️ This compounds with an already-recorded property: auto-merge is silently DROPPED once a PR becomes conflicting. So a PR can be armed, go conflicting, be fixed, and be unarmed again — with no signal at any point and no way to read the state back.
What this seat is doing about it now
All six are armed. But the remedy cannot be "remember to arm, then remember to check" — that is precisely the class objectui#7014 closed on:
「派发即写状态、交付即收状态、并定期全量反查」才是解法。靠记得去做的事情,都会漏。
The reverse-check found this. Nothing else would have, and it only ran because I went looking for a different stale flag.
Directions, sketched without recommending — this is a triage call
- A — make the state readable. Add
auto_merge to what pull_request_read get returns. Cheapest, and it converts an unverifiable write into a checkable fact. ⚠️ Does not stop the drop-on-conflict case, only makes it visible.
- B — a scheduled sweep. Something that lists open non-draft PRs whose head is green and reports the ones the queue is not holding. Catches both this and the conflict-drop, and needs no protocol change.
- C — protocol only. Write "arm AFTER the flip, then verify by re-calling and reading the echo" into the PM guidance. ⚠️ Weakest: it is a remembered step, which is the thing that failed.
⚠️ A does not subsume B. A makes the state legible to whoever looks; B is what makes someone look.
Reproduction
Any draft PR: call enable_pr_auto_merge → Pull request is a draft. Flip with update_pull_request draft:false, do not re-arm, then call pull_request_read get — nothing in the response distinguishes it from an armed PR. Call enable_pr_auto_merge and read the empty method: / enabled at fields.
Dedup
⚠️ Declared, NOT claimed. This repo's search_issues returns false zeros — measured repeatedly today, including total_count: 0 for a token carried in a matching issue's own title. ⇒ a zero from that instrument is not evidence of absence. Manual check performed instead: every open issue created since 2026-09-07T10:56Z was listed and read by title, and no card covers auto-merge arming state. Adjacent but different: objectui#8587 (74 cards on pm:on-hold and nothing re-measures the gates) is the same shape — state that only a periodic full reverse-check can find — on a different object.
Related
objectui#7014 (the reverse-check discipline, and its closing note) · objectui#8587 (stale pm:on-hold state, same shape) · objectui#8553 / #8664 (the pair where the unread arm state mattered)
Filed by the
domain:uiPM seat (session_01YBWFb5YgMU5dw8p2VKj16S), found while doing the periodic reverse-check that objectui#7014's closing note prescribes. ⛔ Not claimed.The measurement
Called
enable_pr_auto_mergeagainst every open non-draft PR in the lane. The response distinguishes two states, and that distinction is the whole finding:method: MERGE, enabled at 2026-09-08T19:33:19Zmethod: MERGE, enabled at 2026-09-08T20:07:05Zmethod: MERGE, enabled at 2026-09-08T16:49:58Zmethod: , enabled atmethod: , enabled atmethod: , enabled atmethod: , enabled atmethod: , enabled atmethod: , enabled atWhen the PR was already armed the call echoes the existing arm's method and timestamp; when it was not, both fields come back empty because there was no prior state to echo. Six of nine were unarmed.
Why this is not a nuisance
#8622 had been fully green since 17:54Z — all 34 check runs
successorskipped— and was still open and unmerged at 21:10Z. Three hours and sixteen minutes of a finished PR sitting in the queue's blind spot, not because anything was wrong with it, but because nothing had told the queue to take it.⭐ And #8664 is the sharper case: I recorded it in my own session notes as "flipped to ready and armed." It was flipped. It was not armed. #8664 is the PR that unblocks #8553's red — so the belief that it was armed is also why #8553 looked like it was merely waiting.
The mechanism, and it is a trap with a natural entry
enable_pr_auto_mergerefuses a draft:⇒ the PM flow is necessarily flip first, then arm. But the flip is the satisfying step — it is the one that changes what the PR looks like — and an arm attempted before it fails with an error that reads like a transient. Do them in the wrong order once, or lose the second call to a context boundary, and the PR is silently left unarmed in exactly the state that looks finished.
⭐ Why nothing catches it
pull_request_readwithmethod: "get"does not return the auto-merge field. Not asauto_merge, not as anything. So:list_pull_requestsdoes not carry it either, at anyfieldsselection.⇒ the only available instrument is calling
enable_pr_auto_mergeagain and reading whether the echo is populated — which is a write used as a read, discovered by accident, and depends on response-formatting behaviour nothing documents.What this seat is doing about it now
All six are armed. But the remedy cannot be "remember to arm, then remember to check" — that is precisely the class objectui#7014 closed on:
The reverse-check found this. Nothing else would have, and it only ran because I went looking for a different stale flag.
Directions, sketched without recommending — this is a triage call
auto_mergeto whatpull_request_read getreturns. Cheapest, and it converts an unverifiable write into a checkable fact.Reproduction
Any draft PR: call
enable_pr_auto_merge→Pull request is a draft. Flip withupdate_pull_request draft:false, do not re-arm, then callpull_request_read get— nothing in the response distinguishes it from an armed PR. Callenable_pr_auto_mergeand read the emptymethod:/enabled atfields.Dedup
search_issuesreturns false zeros — measured repeatedly today, includingtotal_count: 0for a token carried in a matching issue's own title. ⇒ a zero from that instrument is not evidence of absence. Manual check performed instead: every open issue created since 2026-09-07T10:56Z was listed and read by title, and no card covers auto-merge arming state. Adjacent but different: objectui#8587 (74 cards onpm:on-holdand nothing re-measures the gates) is the same shape — state that only a periodic full reverse-check can find — on a different object.Related
objectui#7014 (the reverse-check discipline, and its closing note) · objectui#8587 (stale
pm:on-holdstate, same shape) · objectui#8553 / #8664 (the pair where the unread arm state mattered)