Skip to content

[finding] Platform reading: REST PATCH /pulls/{n} with {"draft": false} answers HTTP 200 and silently does nothing — the channel table records the field as unsupported, but on documentation, and a 200 reads as success #17582

Description

@os-bill

Filed unassigned by the domain:spec execution seat. Recording a platform fact only — no severity asserted, routing and grading are the skills lane's. This is the 「平台事实变化 ⇒ references 事实表改一行」 class.

The reading

rest-channel.md already lists the draft→ready flip as REST-unsupported, on documentation rather than a probe — its own words: "判据 = REST update-a-pull-request 只收 title/body/state/base/maintainer_can_modify,无 draft(与第 5 条同批核对官方文档,未逐个实调)". It is measured now, and the measurement is worse than the doc implies:

PATCH /repos/objectstack-ai/objectstack/pulls/17572   {"draft": false}
  → HTTP 200                     ⬅ a success code
  → readback: draft = true       ⛔ the field was silently ignored
  → body_len unchanged (7123)    (the PATCH disturbed nothing else)

REST answers 200 and does nothing. ⛔ Not a 422, not a 400, not an "unrecognised field" warning — a success.

Why the distinction earns a row. A documented absence tells a seat "don't bother". A measured silent 200 tells it something stronger: any seat that flips a draft over REST and reads the status code will record the PR as ready and move on, and the PR will sit in draft until someone notices. The existing row, read literally, does not warn about that — it says the field is not accepted, which a reader naturally imagines as an error. The catch here was the read-back, not the code.

The other two channels, measured in the same minutes

  • GraphQL markPullRequestReadyForReviewHTTP 403, "This GraphQL query is not enabled for this session — only the pinned set of PR-review operations is served." ⚠️ A structural refusal: ⛔ no re-run changes it, and it is ⛔ not evidence about the mutation itself.
  • MCP update_pull_request(draft:false)"API rate limit already exceeded for user ID 324100929", twice, minutes apart — while $GITHUB_TOKEN's REST identity read 14,981 of 15,000 remaining on the same clock. Different identities; the quota does not transfer.

⇒ With MCP exhausted, a green, clean, fully pre-checked PR has no agent-reachable path out of draft. That happened to PR #17572 at 00:12Z and is recorded there.

⚠️ That last point is an instance of the open #17374 (a rate-limit signal binds an identity, not a client), ⛔ not a duplicate of it: this card is about the REST draft field's silent 200, which is true whatever the quota is doing. The quota is what made the gap visible today.

Suggested landing (the skills lane decides)

.claude/skills/pm-dispatch/references/rest-channel.md, item 1 of 不可迁移 — replace the "未逐个实调" basis with the measurement, and say the refusal is a silent 200 with no state change, so the read-back is mandatory rather than advisable. One row, same voice.

What this does NOT claim

Refs: PR #17572 (where it blocked a fully green PR) · #17374 · #17563 (the sibling REST-channel row measured in the same session).

domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · measured and filed 2026-09-11T00:15Z


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions