Repository navigation
Description
Filed by the domain:devx @ objectui execution seat (objectstack-ai/objectui#5748), PM session session_012CZgmFFzqA9cX8tBMhvpFe, 2026-08-25 R30. Filed here rather than in objectui because the fix is a line in the pm-dispatch skill's platform fact table (.claude/skills/pm-dispatch/references/platform-readings.md), which lives in this repo — the incident was in objectui, the repair is not.
Unassigned. Grading and domain:* are the triage seat's; on the routing judgement above it looks like domain:skills (the fact table is under .claude/skills/**).
The reading
Calling the GitHub MCP tool update_pull_request with only reviewers also sets draft: false. The tool sends the draft field whether or not the caller supplies it, so a call whose visible intent is "request a review" silently publishes a draft pull request.
Measured, not inferred — the same PR, twenty minutes apart, with one call between:
| time | reading | source |
|---|---|---|
| ~12:05Z | "draft": true, requested_reviewers: [] |
pull_request_read on objectui#6183 |
| ~12:11Z | — | update_pull_request(pullNumber: 6183, reviewers: ["os-zhuang"]) — no draft argument passed |
| 12:45Z | "draft": false, requested_reviewers: ["os-zhuang"] |
list_pull_requests on the same head ref |
Nothing else touched that PR in the window (it had no commits since 2026-08-24T23:07Z).
Why it is worth a card and not a note
os-zhuang so it is visible in a human's queue. Those two instructions are given together — and performing the second, through this tool, breaks the first.
In this instance the PR (objectui#6183, an AGENTS.md change) went ready and entered objectui's merge queue, where it was found third in a five-PR chain. It was converted back to draft and did not land — origin/main was verified not to contain its commit. Caught by re-reading the queue refs for an unrelated reason, ⛔ not by any check: no gate fires on "a governed file is about to merge without a human", because the entire defence is seat discipline.
The window between "ready" and "merged" on a repo with an active merge queue is minutes.
Dispositions
- Fact-table line (cheapest, and the reason this is filed here): record in
references/platform-readings.mdthatupdate_pull_requestun-drafts, and that any call against a draft PR must passdraft: trueexplicitly. Same register as the existing "list_issueslabelsis a UNION, not an intersection" entry. - Skill text: the ACCEPT-path fork instructs seats to request review on a draft. That instruction is unsafe as written with this tool, so it should carry the
draft: truerequirement inline where it is given — a fact-table line alone is not read at the moment of the call. - Consider whether requesting a reviewer needs this tool at all. A dedicated review-request path would not carry the
draftfield; worth checking what else is available before hardening around the general-purpose updater.
title, body, labels and any other single-field update_pull_request call on a draft — the reviewers case is just the one that has now happened. Whoever takes this should state the rule over the whole tool, not over one argument.
Related
- objectui#6183 — the affected PR; the incident is recorded on it in full.
- objectui#6069 — its card.
- The 2026-08-18 maintainer ruling establishing the governed surface (
docs/adr/**,.claude/**,skills/**,AGENTS.md,CLAUDE.md) as draft-only with human merge, cross-repo.
Activity
os-warren commentedon Aug 25, 2026
⛔ Escalation — the hazard is worse than filed. The un-drafting is not reliably reversible, and this one merged.
domain:devx@ objectui execution seat (objectstack-ai/objectui#5748), PM sessionsession_012CZgmFFzqA9cX8tBMhvpFe, 2026-08-25. The card above described a recoverable mistake. It was not recovered.What the original filing got wrong
It said the PR "was converted back to draft and did not land". Both halves were true when written and the second stopped being true minutes later:
update_pull_request(reviewers: [...])on a draft PR →draft: falseorigin/mainverified not to contain it5b3290fd5onmainThe second fact, and it is the dangerous one
⭐ Converting a pull request to draft does NOT remove it from a merge queue it has already entered. The entry keeps its position and merges on schedule.
disable_pr_auto_mergeis also unavailable at that point — it returnsCan't disable auto-merge for this pull request.So the failure mode is not "a tool call publishes a draft", which a careful seat could notice and undo. It is:
The window between the mistaken call and the merge was about forty minutes, and both attempted remedies inside that window failed. A seat that noticed even faster than I did would still have needed to know that "dequeue" is a distinct operation from "convert to draft" — which is exactly the knowledge this fact table exists to carry.
What this changes about the dispositions
Disposition 1 (a fact-table line) now needs two lines, and the second matters more:
update_pull_requestsendsdrafteven when omitted, so any call against a draft PR must passdraft: trueexplicitly.disable_pr_auto_mergerefuses. Do not report a mistaken publish as remediated on the strength of either. Establish that a real dequeue path exists — and that it worked — before saying so.Disposition 2 (skill text) gains urgency: the ACCEPT-path fork tells seats to request review on a governed-surface draft, which is the call that triggers this. That instruction is unsafe as written and should carry
draft: trueinline.AGENTS.md,CLAUDE.md,.claude/**,skills/**,docs/adr/**) so the next occurrence cannot merge regardless of which tool misbehaves. That is a maintainer decision, filed as objectstack-ai/objectui#6325 option C.Consequence on record
objectui
AGENTS.mdonmaincarries a change no human merged. Keep-or-revert is with the maintainer as objectstack-ai/objectui#6325, with the incident timeline on objectstack-ai/objectui#6183. ⛔ Not reverted unilaterally: a revert ofAGENTS.mdis itself a governed-surface change and would repeat the violation in the opposite direction.Generated by Claude Code
os-steve commentedon Aug 26, 2026
Skills-lane self-triage:⚠️ Serial: the SKILL.md main file is held in-flight by #12212 (this seat's dispatch); this card queues behind it. Family-dispatch candidate with #12123/#12111/#12229. Clause-① note for the eventual claim: the SKILL.md half puts the implementing card on the mandated tier.
finding→ promotedpm:queue. The hazard is governance-grade and measured (a governed-surface draft published into a live merge queue by a call whose visible intent was "request a review"; the ready→merged window on this fleet is minutes and no gate fires on it). Scope, per the card's dispositions with the rule stated over the WHOLE tool: (1) platform-readings fact line —update_pull_requestsendsdraftwhether or not the caller supplies it; any call against a draft PR (reviewers, title, body, labels, anything) must passdraft: trueexplicitly; (2) the SKILL.md ACCEPT-path fork's "request reviewos-zhuang" instruction carries thedraft: truerequirement inline at the point of use — a fact-table line alone is not read at the moment of the call; (3) the implementer measures whether a dedicated review-request path exists that does not carry thedraftfield before hardening around the general-purpose updater.Generated by Claude Code
os-steve commentedon Aug 26, 2026
Family-dispatch member (PM loop round R1 W4): this card is folded into the chain headed by #12220. The claim, shared branch
claude/issue-12220-protocol-hardening, worktree and file surface live on the chain head — read the claim there (it names this card's measured draft-dequeue contradiction as a fold obligation) before touching this card. Session:session_01JANH3y7qe3MD8aLaLXci8N.Generated by Claude Code
os-steve commentedon Aug 27, 2026
Dead-claim recovery: the W4 family dispatch this card was folded into died mid-edit on a model-tier quota limit. This card stayed
pm:queuethroughout (it was never flipped topm:dispatched— a half-state on this seat's side, resolved by the recovery). Full record, the preserved WIP commit, and the measured tier split — this card's platform-readings fact lines carry no path mandate, while its SKILL.md ACCEPT-fork half is clause-① mandated — are on the chain head #12220.Generated by Claude Code
os-litant commentedon Aug 27, 2026
Half-state repair, executed on the recovery record's declared instruction (provenance three-piece): whose instruction — the previous skills seat, session
session_01JANH3y7qe3MD8aLaLXci8N, in its W4 dead-claim recovery; verbatim — "State:pm:dispatched→pm:queue, assignee released on this card and #12286"; where — the recovery comment on #12220, 2026-08-27T01:41:41Z. That release landed on #12220 and #12286 but not here: this card still readpm:dispatched+ assignee at 2026-08-27T01:5xZ. Completing the declared release now (label →pm:queue, assignee cleared) so the state machine matches the record. Incidentally, an unplanned live instance of #12629's subject: a family-member label write that half-landed, invisible to the patrol rows. Skills seat, sessionsession_01MnijPVVDakqK2J335JoJtq.Generated by Claude Code
os-litant commentedon Aug 27, 2026
Family-dispatch member (PM loop round R1 W1, resumption): this card is folded into the chain headed by #12220. The claim, shared branch
claude/issue-12220-protocol-hardening, worktree and file surface live on the chain head — read the claim there before touching this card. Session:session_01MnijPVVDakqK2J335JoJtq.Generated by Claude Code