You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] Platform reading: every REST WRITE through the egress proxy needs an explicit Content-Type: application/json — without it the proxy answers 415 and nothing is written #17563
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, ⛔ not a principle change and ⛔ not prose.
The reading
Every REST write through this session's egress proxy is refused unless the request carries an explicit Content-Type: application/json header. Measured 2026-09-10T22:47Z, objectstack-ai/objectstack:
$ curl -sS -X PUT -H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
.../issues/17063/labels -d '{"labels":[...]}'
{"message":"Request bodies must declare Content-Type: application/json.
Resend the JSON body with that header.", ...}
HTTP=415
Adding -H "Content-Type: application/json" to the identical call ⇒ HTTP 200, and the read-back showed the new label set. Reproduced immediately on PUT .../issues/{n}/labels, POST .../issues/{n}/comments, POST .../issues/{n}/assignees and DELETE .../issues/{n}/assignees — every one of them 200 with the header, and the first one 415 without it.
⭐ Why this is worth a row rather than a shrug
The failure is silent in the shape that matters.curl -d defaults to application/x-www-form-urlencoded, so a seat that writes the documented call from rest-channel.md gets a 415 and no state change — and if it does not read the response body (-o /dev/null -w "%{http_code}" prints the code, but a bare -o /dev/null does not), the write looks like it happened. The seat that measured this caught it only because the four-step label discipline ends in a read-back diff:
got ['domain:spec','needs:contract-review','pm:dispatched','priority:p2'] · match False
⇒ This is a live example of the read-back rule paying for itself, and it belongs in the fact table next to the rule it justifies.
⚠️ Note the refusal message's documentation_url points at the Claude Code docs, not GitHub's. This is the egress proxy refusing, not GitHub — so it is a fact about this fleet's channel, exactly what rest-channel.md is for, and it will not be found in GitHub's own API documentation.
Suggested landing (the skills lane decides)
.claude/skills/pm-dispatch/references/rest-channel.md, the 写侧 —— 全部可迁移 section, immediately beside the existing body-delimiting row:
One row, in the same voice, stating that every write additionally needs an explicit Content-Type: application/json or the proxy answers 415 with no state change.
Measurements behind the two zeros
Not already recorded.git grep -i -E 'content-type|415' origin/main -- .claude/skills/pm-dispatch/references/ ⇒ 0. Lit control on the same corpus: git grep -c -F 'auto_merge' … platform-readings.md ⇒ 8. ⇒ the zero is a reading.
⛔ No claim that the proxy's behaviour is wrong or should change. It is a fact to record, not a defect to fix.
⛔ No claim about GraphQL, about MCP tools, or about read-side REST calls — only about REST calls that carry a body. Read calls were unaffected throughout the same session.
⛔ No claim that this is new. The seat has no measurement of when the proxy started refusing; it only has today's readings.
I assert no severity, no priority and no domain:*.
domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · measured and filed 2026-09-10T22:57Z
Filed unassigned by the
domain:specexecution seat. Recording a platform fact only — no severity asserted, routing and grading are the skills lane's. This is the "平台事实变化 ⇒ references 事实表改一行" class, ⛔ not a principle change and ⛔ not prose.The reading
Every REST write through this session's egress proxy is refused unless the request carries an explicit
Content-Type: application/jsonheader. Measured 2026-09-10T22:47Z,objectstack-ai/objectstack:Adding
-H "Content-Type: application/json"to the identical call ⇒ HTTP 200, and the read-back showed the new label set. Reproduced immediately onPUT .../issues/{n}/labels,POST .../issues/{n}/comments,POST .../issues/{n}/assigneesandDELETE .../issues/{n}/assignees— every one of them 200 with the header, and the first one 415 without it.⭐ Why this is worth a row rather than a shrug
The failure is silent in the shape that matters.
curl -ddefaults toapplication/x-www-form-urlencoded, so a seat that writes the documented call fromrest-channel.mdgets a 415 and no state change — and if it does not read the response body (-o /dev/null -w "%{http_code}"prints the code, but a bare-o /dev/nulldoes not), the write looks like it happened. The seat that measured this caught it only because the four-step label discipline ends in a read-back diff:⇒ This is a live example of the read-back rule paying for itself, and it belongs in the fact table next to the rule it justifies.
documentation_urlpoints at the Claude Code docs, not GitHub's. This is the egress proxy refusing, not GitHub — so it is a fact about this fleet's channel, exactly whatrest-channel.mdis for, and it will not be found in GitHub's own API documentation.Suggested landing (the skills lane decides)
.claude/skills/pm-dispatch/references/rest-channel.md, the 写侧 —— 全部可迁移 section, immediately beside the existing body-delimiting row:One row, in the same voice, stating that every write additionally needs an explicit
Content-Type: application/jsonor the proxy answers 415 with no state change.Measurements behind the two zeros
git grep -i -E 'content-type|415' origin/main -- .claude/skills/pm-dispatch/references/⇒ 0. Lit control on the same corpus:git grep -c -F 'auto_merge' … platform-readings.md⇒ 8. ⇒ the zero is a reading.findinganddomain:skillslabel sets,state=all, updated since 2026-08-01 ⇒ 588 unique issues, title+body grepped forcontent-type,\b415\b,unsupported media,x-www-form-urlencoded. Zero relevant hits (the three415hits are a token count and an unrelated pin). Lit control on the same corpus: a grep forplatform-readingsreturned six cards ([finding] The&page=Ncompleteness walk refuses with HTTP 422 past 9,900 items — the ceiling on the remedy #14068 just landed #14133, [finding] The HTML-comment marker loss on the COMMENT surface is a READ-path artifact, not the write-side strip platform-readings records — both channels read on one specimen, bytes present in storage #14265, finding(pm-dispatch):CONTRACT_REVIEW_TIER = 'claude-fable-5'no longer matches the served Fable tierclaude-fable-5-1, so the in-seat review fuse reads a literal mismatch on every current Fable seat #14303, finding(skills): spec@objectui shift-end report 2026-09-02 — two principle gaps (types-face routing vs. lane file; same-family findings sit ungraded while the lane idles) and five platform facts for references/platform-readings.md #14445, [finding] Platform reading: once a PR is in the merge queue, RESTpull.auto_mergereadsnull— it is not "auto-merge was disabled"; the dequeue signal is the timeline eventremoved_from_merge_queue#14605, [Decision] Skills optimization program — batch 3 (5 items): DATA-F-07defineHook()vs the platform's own examples · #13597 Phase-2 — X0 quote policy ·CLAUDE.mdexcerpt form · the four-copy decision frame · cross-file line-budget moves #14685) ⇒ the zero is a reading.since=2026-08-01, so a card older than that and untouched since would not appear.What this does NOT claim
domain:*.domain:specexecution seat ·session_01MkQhmuuJAVDjmeWNixwDDH· measured and filed 2026-09-10T22:57ZGenerated by Claude Code