Repository navigation
Commit 2d5fe76
docs(agents,pm-dispatch): a draft conversion drops only an unqueued PR's auto-merge; a queued governed pull-back goes to the maintainer (#20854)
Fixes #20847
Clause-②: no
## What changes
Four sentences stop saying that a draft conversion, or draft plus an
auto-merge disable, removes a PR from the merge queue. Each keeps the
half that holds: on an **unqueued** PR, the conversion drops auto-merge.
Prime Directive 14 now names the one removal act that is measured, the
maintainer's manual removal, and says why a seat cannot do it.
| site | before | after |
|:--|:--|:--|
| `AGENTS.md` Prime Directive 14, "Already armed or queued" (was
`:285-:287`, now `:285-:288`) | Convert it back to **draft** AND disable
auto-merge — draft is what removes queue membership, disabling alone
drops only the arming — then confirm from the remote that it is in
neither the queue nor `origin/main`. | Disable auto-merge AND convert it
back to **draft**, which disarms an unqueued PR; no seat act, those two
included, is measured to dequeue one (`platform-readings.md`, queue
membership), so ask the maintainer at once to remove a queued PR by hand
— then confirm from the remote that it is in neither the queue nor
`origin/main`. |
| `AGENTS.md` "State on your PR" (`:428-:429` → `:429-:430`) | the draft
flag, which flipped back destroys auto-merge and queue membership at
once | the draft flag, which flipped back destroys an unqueued PR's
auto-merge at once |
| `AGENTS.md` multi-agent §7 (`:532-:533` → `:533-:534`) | **flipping
back to draft drops auto-merge and queue membership at once**, and
neither returns by itself | **flipping back to draft drops an unqueued
PR's auto-merge at once**, and it does not return by itself |
| `.claude/skills/pm-dispatch/SKILL.md:202` | 已入队才读到本条 ⇒ 转 draft 与
disable 都做;出队以阳性探针答,ref 缺席只旁证。 | 已入队 ⇒ 转 draft 并
disable,即请维护者手动出队(席位无实测手段);出队以阳性探针答。 |
Every clause that still holds is kept: "**Draft is no barrier by itself
— the barrier is this directive**", "confirm from the remote that it is
in neither the queue nor `origin/main`", "ready *first*, arm *second*",
and the positive-probe reading of a dequeue. The rule text cites
`platform-readings.md` and restates no reading. The readings themselves
are in PR #20845 (issue #20764).
**The grep.** `AGENTS.md` and every file under `.claude/**` were
searched for other copies of the claim: `queue membership`, draft next
to queue or auto-merge, 转 draft, 出队, 踢队, dequeue, evict. The four sites
above are all of them. `references/platform-readings.md:41-:43` is PR
#20845's, and this PR leaves it alone. `lanes/cli.md:17` only points at
that file.
## Is there a seat act that removes a queued PR? (the claim's
measurement)
Every step was read-only. ⛔ No mutation was called and no PR was
dequeued.
1. **Live GraphQL introspection was refused.** The request was `POST
https://api.github.com/graphql` with `query { __type(name: "Mutation") {
fields { name description } } }`. It returned **403** from this
session's egress, with the message "GitHub GraphQL is not available from
Claude Code sessions". The same message lists the pull-request routes
the egress does serve: `ccr/auto_merge` (PUT/DELETE),
`ccr/ready_for_review` and `ccr/convert_to_draft`. None of them
dequeues.
2. **GitHub's published GraphQL schema does declare the mutation.** This
is a document reading, not a live introspection. The source is
`octokit/graphql-schema` `schema.graphql` on `main`, fetched
2026-09-30T12:18Z (1,223,842 bytes, sha256 prefix `3c62d0526d133cee`).
It declares `dequeuePullRequest(input: DequeuePullRequestInput!)` with
the description "Remove a pull request from the merge queue." Its input
is `id: ID!`, the pull request id.
3. **REST has no dequeue endpoint.** In `github/rest-api-description`,
`api.github.com.json` (info version 1.1.4, `main`), no path contains
`queue`. The word "dequeue" appears only in the `pull_request.dequeued`
webhook schemas.
4. **GitHub's own docs list the ways a PR leaves the queue.** The source
is `github/docs` on `main`
(`data/reusables/pull_requests/merge-queue-removal-reasons.md`). The
list has four entries: CI failure, timeout, "User requesting a removal
via the API or merge queue interface", and a branch-protection failure.
Neither a draft conversion nor a close is on it. The how-to page
(`merging-a-pull-request-with-a-merge-queue.md`) removes a PR through
the web page's **Remove from queue** button and says the CLI cannot do
it.
5. **The relay cannot carry it.** `scripts/pm/fleet-write/ops.mjs` at
`05a7547c9` has 15 ops: comment, comment_edit, labels_add,
labels_remove, assign, unassign, issue_patch, issue_create, pr_create,
pr_request_reviewers, pr_ready, pr_draft, automerge_enable,
automerge_disable and transfer. `ALLOWED_MUTATIONS` has five entries,
and `dequeuePullRequest` is not one of them.
⇒ **No dequeue act is measured to be available to a seat.** The platform
documents one (the GraphQL mutation), but neither this session's egress
nor the relay can reach it. So the rule sends a queued pull-back to the
maintainer and says why. The triage direction on the card reserves the
next step for the triage seat: whether to file a tooling child for a
relay dequeue op. That would be a new relay capability.
## Coordination with PR #20845
The new rule cites the queue-membership section of
`platform-readings.md`. At `origin/main` (`05a7547c9`), line `:42` of
that section still carries the old reading, and PR #20845 rewrites
`:41-:43`. Until #20845 lands, the rule and line `:42` disagree. #20845
should land first, or with this PR. The citation names a file section,
not a PR, so it is correct once both have landed, whatever the order.
## Line budget
- `AGENTS.md`: 1107 → **1108** lines, against a ceiling of 1116
(headroom 9 → 8). The +1 is all in Prime Directive 14. The new sentence
adds the maintainer route and the reason for it, and it needs four lines
where the old one took three. The other two `AGENTS.md` sentences are
net 0.
- `pm-dispatch/SKILL.md`: 319 → **319** lines (ceiling 319, headroom 0).
Line `:202` is edited in place and goes from 107 to 116 bytes.
- Every added line is at most 120 bytes: 118 / 110 / 120 / 118 (Prime
Directive 14), 83 / 87 ("State on your PR"), 88 / 88 (§7) and 116
(`SKILL.md`). `check:pm-skill-ratchet` reports no over-length line and
leaves the table-row pins unchanged (768 and 342).
## Deviations from the dispatch
1. **`SKILL.md:202` drops two parts.** They are the clause 「ref 缺席只旁证」
and the 「才读到本条」 of the trigger. The 120-byte cap left 13 bytes of room
on the line, and the maintainer route with its reason needs about 50.
The dropped clause is kept in `platform-readings.md:44` (「ref 缺席只作旁证,⛔
永不承载结论」), and the positive-probe half of the line stays.
2. **`AGENTS.md` is net +1, not ≤ 0.** None of the three sentences frees
a whole line by deleting content. Freeing one would need a re-wrap of
text this PR does not otherwise change. The pin is not exceeded.
3. **The introspection is a schema-document reading.** The live endpoint
refused this session (item 1 above).
## Acceptance notes
- **Same family, outside this PR's scope (the dispatch rules out any
script edit).** `scripts/pm/check-governed-queue-guard.mjs` makes the
same claim in both of its refusal texts, at `:1451-:1452` and
`:1911-:1912` (at `05a7547c9`): "take the pull request out of the queue:
convert it back to DRAFT (disarming auto-merge alone does NOT dequeue
it)". Parking the PR in draft after the guard's red is still useful: an
armed PR re-enters the queue, and a draft cannot be armed. The part in
parentheses is the falsified premise. This is reported to the seat so it
can join the card's family. No card is filed.
- **An unmeasured candidate, for triage.** Closing the PR is an act a
seat has, through the relay's `issue_patch` with `state: closed`. A code
comment in `.github/workflows/cross-repo-issue-closer.yml:399-:401` says
that closing drops queue membership. GitHub's list of removal reasons
does not name it, and I know of no reading of it in this repo. It was
not attempted.
- **Changeset.** None. `.claude/**` and `AGENTS.md` are not in any
package's `files[]`, so this PR publishes nothing. `skip-changeset` is
for the seat to apply.
- **Landing.** This is a Tier H governed surface (`AGENTS.md`). The PR
stays a draft until an authorized approval.
## Verification (head `b095ba02e`)
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands`, with no paths, derived 22 commands for this change set (2
paths against merge base `05a7547c9`). All 22 exited 0:
- `check-closing-keyword-parity`, plus its `--self-test`;
- `check-comment-mask-corpus`;
- `check-governed-queue-guard --self-test` and `check-harness-current
--self-test`;
- `@objectstack/lint check:doc-formula-expressions`, run after building
`@objectstack/lint` and its dependency closure under `os-verify-lock.sh`
(`VERDICT command-exit 0`);
- the `check:` family: `agent-test-spelling`,
`cross-package-test-inputs`, `doc-authoring`, `docs-audit-scope`,
`driver-memory-census`, `gitlink-declared`, `nul-bytes`,
`pm-expected-skips`, `pm-governed-merges`, `pm-governed-prose`,
`pm-skill-id-lint`, `pm-skill-ratchet`, `refd-timer-probe`,
`required-contexts`, `skill-frame-sync` and `watch-hint-literal`.
- `pnpm check:pm-settings-deny-roster` was also run, because its roster
lives under `.claude`. It exited 0.
- The `--ran` reconciliation read "22 derived, 22 run, 0 NOT-MEASURED, 0
UNRUN". All 22 commands recorded an exit code.
- Readings from the gates:
- `check:pm-skill-ratchet`: "AGENTS.md is 1108 lines (ceiling 1116;
headroom 8)" and "pm-dispatch/SKILL.md is 319 lines (ceiling 319;
headroom 0)".
- `check:pm-skill-id-lint`: "34 file(s) clean".
- `check:pm-governed-prose`: "2 instruction surface(s) name all 6
registered governed surfaces".
- NOT MEASURED:
- `check-required-contexts --verify-required-set`, which reads the
workflow event and so runs only in CI;
- the four CI type-check lanes. This diff touches no TypeScript.
## 维护者速读(草稿)
- **改了什么**:`AGENTS.md` 三句、`pm-dispatch/SKILL.md` 一行。旧文说「转 draft 会把 PR
踢出合并队列」,现在都不再这么说。改后:转 draft 只在**未入队**时掉 auto-merge。已入队的受管 PR
要撤回时,两手照做,并**立即请你手动出队**。
- **为什么改**:实测里 4 个已入队后转 draft 的 PR 都没有因此出队,其中 2 个带着 draft 被队列直接合入,读数在 PR
#20845。「转 draft 能出队」的说法写在第 14
条指令里,那是防止坏合并的撤回手段,而这个手段实际不起作用。**出队手段问题**:目前席位**没有**经实测可用的出队手段。GitHub 公开
schema 里有 GraphQL `dequeuePullRequest`,但本会话出口拒绝 GraphQL(403),中继也没有这个
op。所以规则暂时把已入队的撤回交给你手动出队。要不要给中继加出队 op,属于新能力,由分诊决定是否立子卡。子卡立了,你会看到裁决请求。
- **风险与代价(含回滚)**:只改规则文字,不改代码。代价是已入队的撤回要等你点「Remove from queue」。队列落地约需
15–30 分钟,所以需要你及时响应。PR #20845 应先合或同合,否则被引用的读数第 42 行暂时和本规则说法相反。回滚就是 revert
这一个 PR。
- **席位意见**:
- **你要做的**:审阅后批准本 PR(或直接合并)。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 1d20245 commit 2d5fe76
2 files changed
Lines changed: 9 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
202 | | - | |
| 202 | + | |
203 | 203 | | |
204 | 204 | | |
205 | 205 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
282 | 282 | | |
283 | 283 | | |
284 | 284 | | |
285 | | - | |
286 | | - | |
287 | | - | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
288 | 289 | | |
289 | 290 | | |
290 | 291 | | |
| |||
425 | 426 | | |
426 | 427 | | |
427 | 428 | | |
428 | | - | |
429 | | - | |
| 429 | + | |
| 430 | + | |
430 | 431 | | |
431 | 432 | | |
432 | 433 | | |
| |||
529 | 530 | | |
530 | 531 | | |
531 | 532 | | |
532 | | - | |
533 | | - | |
| 533 | + | |
| 534 | + | |
534 | 535 | | |
535 | 536 | | |
536 | 537 | | |
| |||
0 commit comments