Skip to content

docs(pm-dispatch): the draft-conversion reading splits by queue state — no queued PR left the queue on a draft conversion - #20845

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20764-draft-dequeue-reading
Sep 30, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-20764-draft-dequeue-reading

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #20764

Clause-②: no

What changes

.claude/skills/pm-dispatch/references/platform-readings.md, lines 41-43 only. The rewrite is net 0 lines, and the three new lines are 120 / 118 / 120 bytes (cap 120).

line before after
:41 转 draft 不是可靠的踢队手段:两向相反读数并存,处置按最坏走。 转 draft 不是可靠的踢队手段:本仓与姊妹仓均见已入队转 draft 仍保位照合,处置按最坏走。
:42 本仓转 draft 同时掉 auto-merge 与队列成员资格,不自动恢复,转正后重挂;姊妹仓曾保位照合。 本仓转 draft 同秒掉 auto-merge 仅见于未入队时,转正后重挂;已入队者 2026-08-08、09-29 照合。
:43 补救:转 draft 与卸载 auto-merge 都做 —— 本仓卸载 auto-merge 单独不踢队。 补救:转 draft 与卸载 auto-merge 都做,本仓卸载单独不踢队;两手齐做亦未见踢队(08-08、09-28)。

The remedy on :43 is unchanged: do both acts. No rule is added. The in-file citations are dates, because pnpm check:pm-skill-id-lint goes red on a #-number anywhere under .claude/skills/pm-dispatch/, and this file cites no PR number today. The PR numbers and timeline events are in this body. That is where the id-lint header puts a reading's provenance.

The readings (re-readable: GET /repos/objectstack-ai/objectstack/issues/N/timeline)

I ran a read-only timeline scan over #4700-#4900, #6650-#6850 and #20400-#20840. It looked for two patterns: a convert_to_draft between added_to_merge_queue and the next removed_from_merge_queue, and a convert_to_draft on a PR that was armed but not queued. The scan found every row below. The table is complete for those windows only, not for the whole repo.

Queued, then converted to draft. None of the four left the queue because of the conversion.

PR queued draft disable sent? what followed
#6732 2026-08-08T14:01:50Z 14:04:32Z claimed in #6799's text; no auto_merge_disabled event the queue merged it at 14:38:56Z, 34 min later, still draft
#20420 2026-09-28T13:43:01Z 14:02:28Z claimed in the seat's 14:04Z comment; no event its own group pr-20420-3cf6449 had Lint & Type Check = failure at 14:01:49Z, before the draft; github-merge-queue[bot] removed it at 14:11:24Z, unmerged
#20442 2026-09-28T13:45:42Z 14:02:50Z claimed in the seat's 14:04Z comment; no event the queue built a new group pr-20442-b285508 for it at 14:11:29Z, 9 min after the draft; that group's CI = failure at 14:30:14Z; removed at 14:35:44Z, unmerged
#20695 2026-09-29T23:32:51Z 23:57:02Z no (the card discloses: draft alone) the queue merged it at 00:04:21Z, 7 min later, still draft

Armed, not queued, then converted to draft. Each one dropped auto-merge.

PR armed draft auto_merge_disabled after
#4745 2026-08-03T01:28:46Z 01:29:30Z 01:29:30Z (same second) ready, re-armed 01:30:52Z, queued, merged
#6727 2026-08-08T13:42:58Z 13:44:36Z 13:44:36Z (same second) ready, re-armed 13:46:02Z
#6829 2026-08-08T23:37:05Z 23:40:25Z 23:40:26Z (1 s) ready and enqueued 6 h later

Each disable event carries the converter as its actor. A timeline cannot tell whether the platform wrote it or a scripted follow-up did. The line records what was observed ("同秒").

Where the old reading came from

How this departs from the triage direction (5903760674)

I did not choose these quietly. Each one is a place where a measurement changed what the direction assumed:

  1. :42 is split by queue state, not "mixed" in the sense of opposite readings. No queued PR in the scanned windows left the queue because of a draft conversion. The direction assumed the old half had its own measurement. It has none, and the one PR later cited for it reads the other way. What does go both ways in this repo is the effect by state: unqueued, auto-merge drops; queued, the PR keeps its place.
  2. :43 says "not seen to dequeue", not "not measured". Three PRs (docs(adr),chore(devx): reconstruct ADR-0079 + make every cited ADR number resolve #6732, feat(spec): ComponentPropsMap rows for action:button/group/menu/icon and element:definition-list/repeater #20420, feat(spec): declare the staged $empty filter operator and its per-type expansion (#20311) #20442) have both acts claimed in writing, and none was removed by them. The caveat: on a queued PR, the disable leaves no timeline event, so whether it was sent rests on the seats' own comments.
  3. :41 loses "两向相反读数并存". No opposite reading survived the re-read.

Acceptance notes

Verification (head 02ea176a1)

  • The 20 gates from node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands all exit 0. They are check-closing-keyword-parity (plus --self-test), check-comment-mask-corpus, check-governed-queue-guard --self-test, check-harness-current --self-test, lint check:doc-formula-expressions (after building @objectstack/lint and its dependency closure under os-verify-lock.sh), check:agent-test-spelling, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:nul-bytes, check:pm-governed-merges, check:pm-half-states, check:pm-skill-id-lint, check:pm-skill-ratchet, check:refd-timer-probe, check:required-contexts, check:skill-frame-sync and check:watch-hint-literal.
  • pnpm check:pm-settings-deny-roster was also run, because its roster lives under .claude. Exit 0.
  • --ran reconciliation: 20 derived, 20 run, 0 NOT-MEASURED. All 20 recorded an exit code.
  • check:pm-skill-ratchet printed: platform-readings.md is 469 lines (ceiling 469; headroom 0), widest table row 0 bytes (pin 0).
  • Not measured locally: check-required-contexts --verify-required-set and check-half-states --provenance, which read the workflow event, and the four CI type-check lanes. This diff touches no TypeScript.

维护者速读(草稿)

  • 改了什么:PM 协议参考文件 platform-readings.md 第 41-43 行,关于「已入队 PR 转 draft 能否踢出合并队列」的三条平台读数。行数不变。
  • 为什么改:旧文说本仓转 draft 会掉出队列。回查时间线后发现,本仓 4 个已入队后转 draft 的 PR 都没有因此出队。其中 2 个带着 draft 状态被队列直接合入,另外 2 个是在自身队列构建变红之后才被移出。旧说法唯一引用的实例,时间线恰好反向。转 draft 会掉 auto-merge,这一点只在「未入队」时成立。
  • 风险与代价(含回滚):只改文档读数,不改任何规则或代码。补救仍是两手都做。风险在于读者以为有可靠的踢队手段,而实际没有。回滚就是 revert 这一个提交。
  • 席位意见:
  • 你要做的:无需操作,由席位按 Tier S 复核后落地。若要让 AGENTS.md 里的同一旧说法一并修正(Tier H),需要你点头另开 PR。

Generated by Claude Code

… — a queued PR kept its place in every re-read

platform-readings `:41-:43` re-read against the timelines they rest on.
Unqueued and armed, a draft conversion drops auto-merge in the same second
(re-arm after ready). Queued, no draft conversion was seen to dequeue in
this repo: two PRs merged through the queue while in draft, and two others
left only after their own merge-group builds went red. The remedy line keeps
both acts and records that both together were not seen to dequeue either.

Net 0 lines; each rewritten line is at most 120 bytes.

Claude-Session: https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg
Co-authored-by: Claude <[email protected]>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 02ea176a18aabde68f10278d64c00ca851998ca1
Local-runs: none

Inputs: card #20764 (body and all three comments: triage direction 5903760674, claim 5910003827, os-dev-report 5910417690); PR #20845 (body, file list, the net diff against origin/main at the head, its zero comments, its labels); the check-runs on the head; the timelines of #20695, #6732, #20420, #20442, #4745, #6727 and #6829, each read by this reviewer; git log -p on platform-readings.md for the reading's origin. Not fed: the dispatch order, the dispatching seat's conclusions.

The diff. One file, .claude/skills/pm-dispatch/references/platform-readings.md, +3 / -3, lines 41-43 only; the PR's file list and git diff origin/main...02ea176a agree. One commit on the branch (merge-base 93e9e426). File length 469 lines at the head and at origin/main (ratchet row ['.claude/skills/pm-dispatch/references/platform-readings.md', 469], headroom 0). The three rewritten lines measure 120 / 118 / 120 bytes (LC_ALL=C), cap 120; no line in the file exceeds 120 bytes. The file contains no #[0-9]{3,} match.

Check-runs on the head (filter=latest, 30 runs): 18 success, 12 skipped, 0 failure, 0 neutral, 0 cancelled, 0 in progress. Every run not success / skipped: none. Check Changeset is success (11:44:17Z, after the skip-changeset label at 11:40:26Z); Governed Surface Queue Guard, Lint & Repo Gates, all four Type Check lanes, Check Documentation Links and the three single-writer / claim guards are success. The skips are the path-filtered lanes (Build Core, Test Core shards, Console Pin Gate, Temporal Conformance, Dogfood, Build Docs, Packed-tarball) on a diff that touches no source. PR state: draft, auto_merge null, no queue event on its timeline, mergeable_state: clean.

① Derived judgments

The timelines, as this reviewer read them (GET /issues/N/timeline, all seven under the 100-event page; key events only):

Every row of the PR body's two tables matches what this reviewer read. In the four queued cases the draft conversion was followed by no removal event of its own; in the three unqueued cases the conversion was followed by auto_merge_disabled within one second, with the converter as actor.

:41 「转 draft 不是可靠的踢队手段:本仓与姊妹仓均见已入队转 draft 仍保位照合,处置按最坏走。」 — right. The "本仓" half is #6732 and #20695 above, both merged by the queue while in draft. The "姊妹仓" half is carried over from the file's own history (2e9bca270, 2026-08-27: 「objectui 2026-08-25 测得相反 —— 已入队 PR 转 draft 后条目保位、~40 分钟后队列照样合并」) — a pre-existing governed reading, not re-read by the dev and not re-readable from this repo; it is not a new claim. The dropped clause 「两向相反读数并存」 had, as its only "反" direction, the old "本仓" reading, which the next line falsifies; no opposite reading survives in any input. 「处置按最坏走」 is kept.

:42 「本仓转 draft 同秒掉 auto-merge 仅见于未入队时,转正后重挂;已入队者 2026-08-08、09-29 照合。」 — right. Dates verified: 2026-08-08 is #6732 (queued 14:01:50Z, draft 14:04:32Z, nothing between, merged 14:38:56Z); 2026-09-29 is #20695 (queued 23:32:51Z, draft 23:57:02Z, nothing between, merged 2026-09-30T00:04:21Z — the date pins the queue-and-draft day; the merge itself fell seven minutes past midnight UTC). "仅见于未入队时": in the four queued cycles no auto_merge_disabled followed the draft although auto-merge was armed in three of them (#6732, #20695, #20442); in the three unqueued cycles it always did. Precision note, not a defect: 「同秒」 is the observed value on #4745 and #6727; #6829 logs the drop one second later (23:40:25Z → 23:40:26Z), which the PR body reports as "(1 s)". The reading is of a platform-coupled drop, and the cap left no bytes for the caveat. The old "不自动恢复" survives as 「转正后重挂」, which #4745 and #6727 (re-armed only after ready_for_review) support.

:43 「补救:转 draft 与卸载 auto-merge 都做,本仓卸载单独不踢队;两手齐做亦未见踢队(08-08、09-28)。」 — right, and it does not claim more than the evidence holds, on one condition it meets. The remedy 「都做」 is the triage direction's, word for word in substance. 「本仓卸载单独不踢队」 is carried over (its source is PR #6799's text on #6732's reversal, cd704cc4). The new clause says 「未见」 — not seen — and that is the exact strength of the evidence: 08-08 is #6732 (both acts per #6799's text; the queue merged it 34 minutes later, in draft), 09-28 is #20420 and #20442 (both acts per seat comments 5871523278 and 5871530372; the queue held #20442 through a second build and ejected both only after red group builds, by github-merge-queue[bot]). What the line cannot say and does not say: that the disable was sent. On a queued PR the timelines carry no auto_merge_disabled event (verified on all four), so "both acts" rests on the seats' written claims and on #6799 — the PR body states that caveat in its own words, and that body is where the id-lint header places a reading's provenance. Had the line said 「两手齐做亦不踢队」 (does not dequeue) it would overclaim; 「未见踢队」 does not. The cause of #20420's removal (a red build at 14:01:49Z per the seat's comment, before the draft) is inferential in the sense that a timeline records no cause; the inference is well founded by the three sibling cases and the actor.

The departure from the triage direction (:42 "mixed" → "split by queue state"). Traced: the "drops queue membership" reading first appears in db6581a5 (#4893, card #4892, committed 2026-08-03T13:59Z), in the SKILL.md note 「转 draft 会同时掉 auto-merge 与队列成员资格」, citing no PR. #4745, the same day at 01:29Z, logs the same-second auto-merge drop on a PR that was not queued — the queue-membership half had no instance then, and the trace finds none later: ab19075e8 (08-12) restated it and cd704cc4 / #6799 (08-09) cited #6732 for "only draft evicts", whose timeline shows the PR merged in draft 34 minutes after the conversion. No evidence for a draft dequeue exists in any input. A "mixed" line would therefore have asserted a direction with no instance behind it; the direction's assumption (the old half has its own measurement) was falsified by the measurement the direction asked for. "Split by queue state" is what the seven timelines support (unqueued: auto-merge drops; queued: the PR keeps its place), and it stays inside the direction's intent: a reading correction on a governed file, no new rule (the acts, the probe and 「处置按最坏走」 are unchanged), :43's remedy kept. Accepted as flagged.

Citations by date, not PR number. Confirmed: scripts/pm/check-skill-id-lint.mjs scans every .md under SCAN_ROOT = '.claude/skills/pm-dispatch' with ID_PATTERN = /#[0-9]{3,}/g, so #6732 in this file reds the gate; the file cites zero PR numbers today and already pins readings by date (:49 2026-09-17, :51 2026-09-11, :132, :193, :298, :305). The gate's header states the rule: a reading's provenance lives in the PR that landed it. Dates suffice as a re-readable pin because the PR body carries the seven PR numbers with their events and the endpoint to re-read them, reachable from the line by git blame → commit → PR; 08-08 maps to #6732 and 09-28 to #20420 / #20442 without ambiguity in the scanned windows. Within the direction's intent (the pin is the timeline).

Pins. 469 / 469 lines hold (net 0); new lines 120 / 118 / 120 bytes, none over the 120-byte cap; table-row pin 0 unchanged (the file has no table). The dev's check:pm-skill-ratchet and check:pm-skill-id-lint claims are consistent with these measurements and with Lint & Repo Gates = success on the head.

② Semver level

skip-changeset is right and is on the PR (label applied 11:40:26Z; Check Changeset = success). The diff touches .claude/** only, which no package's files[] ships, so nothing publishes from any released package (AGENTS.md §3, review-checklist.md 「本仓库走 skip-changeset 标签」). Clause-②: no is right and matches the claim (5910003827): no published schema, export or docs surface changes. Not a Clause-②: yes surface under contract-review.md's five faces except as governed rule text, which is why this record exists.

③ Boundary flags

Dev deviations (5910417690), each answered:

  1. :42 "mixed" → "split by queue state": accepted on the evidence, see ①. Not a silent choice — flagged in the report and the PR body.
  2. :43 "not seen to dequeue" instead of "not measured": accepted, see ①; the disable half on a queued PR is attested by seat comments and docs(pm-dispatch): ADR merge prohibition in Guardrails + ACCEPT path fork; probe-and-revive as the standing backstop; replay-wake identity check (#6741, #6747) #6799's text, never by a timeline event, and the PR body says so.
  3. Dates instead of PR numbers: accepted, id-lint confirmed, see ①.
  4. :41 rewritten inside its line (86 → 120 bytes): within the cap, net 0 lines; the clause it drops had lost its only support.
  5. git fetch --deepen on the shared clone: adds objects only, changes no tracked file; no action.
  6. Commit trailers: the head carries Claude-Session: and the model-free Co-authored-by: Claude spelling; the card-trailer gate sits inside Lint & Repo Gates = success. No action.

open_questions (the eviction act, A vs B): escalated, not answered here. It is carried verbatim on #20847 ("Open question, for triage (it may need a maintainer)"), and PR #20854 implements option A in AGENTS.md (a queued governed pull-back goes to the maintainer for a manual removal). This PR adds no rule either way; its :43 remains the status quo the question is asked about. The one manual removal the dev names, #20797 removed_from_merge_queue 2026-09-30T07:33:36Z by os-zhuang with no draft conversion, reads as stated.

Out-of-scope findings:

Landing order. PR #20854's new Prime Directive 14 text cites this file's queue-membership section ("platform-readings.md, queue membership") for the reading it stops restating; this PR should land first so the cited section says what #20854 says it says. #20854 does not touch platform-readings.md:41-:43, so no conflict either way.

Landing key. The diff is Tier S (.claude/** only, one file), every check on the head is success or an expected skipped, and this record is a PASS on the current head at CONTRACT_REVIEW_TIER — under AGENTS.md Prime Directive 14 and landing-operations.md:59 that is the key: the owning seat may take the PR ready and through the queue. ⛔ Nothing here was posted, merged, queued, armed or re-run by the reviewer.

Implemented-by: claude/issue-20764-draft-dequeue-reading
Reviewed-by: session_01KTZmMfzVzjNvyaLyQ8mHvg

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 30, 2026 14:01
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 07356a6 Sep 30, 2026
34 of 35 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20764-draft-dequeue-reading branch September 30, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants