Skip to content

docs(pm-dispatch): three write-side lines of the REST channel table, and the pipeline trap in post-stamped - #18391

Merged
os-elon-musk merged 3 commits into
mainfrom
claude/issue-18337-rest-channel-write-side-fold
Sep 16, 2026
Merged

os-elon-musk merged 3 commits into
mainfrom
claude/issue-18337-rest-channel-write-side-fold

Conversation

@os-elon-musk

Copy link
Copy Markdown
Collaborator

Fixes #18337
Fixes #18339
Fixes #18360

Three write-side lines of .claude/skills/pm-dispatch/references/rest-channel.md — the table a seat opens before hand-rolling a REST write — plus the same pipeline trap in the header of scripts/pm/post-stamped.mjs, which is the file opened before that idiom is typed. One commit per card.

The file sits at its ratchet ceiling with zero headroom (82 / 82), so the two added rules are paid for by two retired rows, each declared below with the surviving home of every clause it carried. 82 lines before, 82 lines after. No re-wrap was used as currency, and references/platform-readings.md is untouched.

Per card

#18337 — the pipeline-exit trap, beside the two tools it names

Landing point (by content): the write-side block, immediately after the label-write.mjs row.

Before: no such line; the trap was written down only in one lane's private Routine prompt.

After (verbatim):

- ⛔ `post-stamped`/`label-write` 永不接进管道再 `&&`:拒收读成 0;看尾先落文件或 `set -o pipefail`。

Second half — the tool's own header. scripts/pm/post-stamped.mjs gains one section, ## ⛔ Never pipe this tool, then && the write that follows, which names the half-state shape (refused audit comment, label landed anyway, card graded with nothing saying why), the redirect-then-capture spelling, and set -o pipefail. It states the shape rather than citing a card number, and it does not restate the generic mechanism: that reading keeps its single home in references/platform-readings.md.

How this card reads independently: both places carry the trap — the write-side block (grep the table for pipefail: was 0, is 1) and the tool header a seat opens before typing the idiom (grep -c 'set -o pipefail' scripts/pm/post-stamped.mjs).

Paid by: retiring the write-side row

- 入队读 timeline `added_to_merge_queue`,落地读 `git rev-list --parents`;⛔ `auto_merge` 与回显都不作数。

Every clause of it survives, twice over: added_to_merge_queue is already a judgment row in this same file's queue-routing block; git rev-list --parents is a spelling this file's own 第三桶 block declares to live in platform-readings.md, where it is written with its -n1; and the auto_merge / echo-back unreliability is in platform-readings.md twice plus this file's own queue-routing rule that the answer comes from the attempted action and not from the attribute field. It is the row this file's own line 「本表只指路,⛔ 不在两处各存一份」 refuses to keep.

#18339 — the mandatory header, on the table seats consult

Landing point (by content): the write-side block, immediately after the request-body line 「请求体走文件…或引号定界 heredoc」, which is the hook the card names.

Before: the block carried zero mentions and zero cross-references of the header (content-type, case-insensitive, over the whole table: 0 hits, with GET at 12 hits as the firing control).

After (verbatim):

- 每个写请求必带 `Content-Type: application/json`;缺头的 415 与判别式见配额段。

How this card reads independently: the reader path from the write-side block to the rule is now 0 hops — the rule is in the block — and the reading it is measured from (the 415, and the discriminator that tells a proxy refusal from a GitHub one) is 1 hop, named rather than copied. Was ∞. The two platform-readings.md rows are not copied and not edited; the pointer uses this table's existing spelling for that section, which its own opening line and its 不可迁移 heading already use.

Paid by: retiring the reading beside it,

- 双引号内 shell 先展开反引号、`$(...)`、`$VAR`,请求尚未成形;只标题坏而正文完好即此形。

Both of its facts are in platform-readings.md verbatim: the backtick expansion with the broken-title-intact-body symptom, and the quoted-delimiter rule whose general form is 「请求体永不过会展开的 shell 上下文」, which is what covers $(...) and $VAR. The prescription those bytes explained — body via file or quoted heredoc, never an inline double-quoted string, with both spellings — stays untouched on the line above.

#18360 — the direct-merge actor follows the token class, not the session

Landing point (by content): the write-side block's direct-merge row.

Before (verbatim):

- 直合仓 `PUT .../pulls/{n}/merge`;actor 记通道令牌:REST 按会话为 `claude[bot]` 或用户,MCP 恒用户。

After (verbatim):

- 直合仓 `PUT .../pulls/{n}/merge`;actor 记令牌类,按账号非会话、逐写回读;见配额段,MCP 恒用户。

How this card reads independently: grep -c '按会话' on the file is 0 (was 1, that row); the row now says the actor is the token class, bound to the account and read back on each write; the fact-table rows landed by #18359 are pointed at, not copied; MCP 恒用户 stays, because it is this table's own fact and has no other home. In place, 120 bytes, at the cap the ratchet sets.

Line budget

lines
rest-channel.md before 82
rest-channel.md after 82
ceiling 82

Added 2 rules, retired 2 rows, re-keyed 1 row in place. scripts/pm/post-stamped.mjs carries no ceiling (it is not in the ratchet's CEILINGS map — checked, not assumed). Every touched line is within the 120-byte cap; the two new rules measure 119 B and 98 B, the re-keyed row 120 B.

Gates

All 39 commands derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack against this branch's real change set were run, exit code captured before any pipe. 38 of 39 are green, including pnpm check:pm-skill-ratchet (its own verdict line: rest-channel.md is 82 lines (ceiling 82; headroom 0)), pnpm check:pm-post-stamped (233 cases), pnpm check:nul-bytes, pnpm check:doc-authoring, pnpm check:pm-governed-merges and pnpm check:pm-skill-id-lint. pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3, PREREQUISITE NOT MET (unbuilt workspace packages, nothing measured); after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint it exits 0. The remaining command, pnpm check:pm-dispatch-gates (a 430–450 s battery), was still running when this PR was opened; its verdict is in the dev report on #18337.

node scripts/pm/check-governed-merges.mjs --test .claude/skills/pm-dispatch/references/rest-channel.md exits 3 — GOVERNED, .claude/**. ⛔ No seat flips this ready, enqueues it or arms auto-merge; it lands after the skills seat's contract-tier review.

Acceptance notes

  • Noted, not filed: nothing else in the write-side block was touched. The -d @file flag and the quoted-heredoc delimiter spelling, the shell-expansion prescription, and every ✓ channel row are unchanged.
  • To file (out of scope here, scripts/pm/check-half-states.mjs): H64's header quotes this same retired premise as its rationale — 「REST 按会话为 claude[bot] 或用户,MCP 恒用户」, sourced to rest-channel.md, with the surrounding prose reading "the write identity follows the CHANNEL rather than the account" and, further down, "the token class is handed to a session at start rather than chosen at write time". The landed fact table says the opposite in as many words: 「类按 Claude Code 账号定,⛔ 不按会话定」 and 「一会话内两次写之间可无席位动作地翻转」. The row's runtime message text carries the same sourcing. Prose only, no enforcement change; this PR's claim names rest-channel.md and post-stamped.mjs and nothing else, so it is reported rather than fixed here. Dedup words: H64 按会话 · check-half-states token class · write identity follows the channel · session-handed token.

维护者速读(草稿)

改了什么 —— pm-dispatch 的 REST 通道对照表(席位手搓写请求前查的那张表)的写侧段,加了两条规则、改写了一条、退役了两条重复行;另外给 scripts/pm/post-stamped.mjs 的文件头加了一段管道陷阱说明。表的总行数没变(82 行,正好在棘轮天花板上)。

为什么改 —— 三张 p3 卡,同一个形状:规则存在,但不在读者动手时会看的那张表上。① 把写脚本接进管道再 &&,管道退出码取末端,于是审计评论被拒、标签照落,卡上留下「改了标、没理由」;这条陷阱原先只写在某条车道的私有唤醒提示词里。② REST 写必带 Content-Type: application/json,缺了代理回 415、一个字节都不写 —— 规则写在事实表里,写侧段零提及,一个班次内六次独立踩中、四个端点,而失败长得像「别人并发把我的标签冲掉了」,会把一个加一个头就能修的问题误诊成分布式竞态。③ 直合的 actor 那行还写着「按会话」,而事实表已经改成「按 Claude Code 账号」,并记录了一个会话内无人操作就翻转两次的实测。

风险与代价(含回滚) —— 纯文本面,无代码行为改动,无 changeset(.claude/**scripts/pm/** 不发布)。代价是退役了两行:每一行的每个子句都在别处有家(逐条列在上面的 Paid by 里),这是天花板零余量下唯一合法的付账方式 —— 删内容,不是折行。若判定某条退役行不该退,回滚是一次 revert:三个 commit 逐卡独立,可以只回其中一个。

席位意见 ——

你要做的 —— 复核两处:① 两行退役是否同意(它们的存续副本是否真的够用);② 三条新/改写的行文字是否准确 —— 尤其 #18360 那行为了压进 120 字节,把「按 Claude Code 账号」压成「按账号」,完整拼写留在它指向的配额段。这是受管面(.claude/**),⛔ 不会有任何席位把它 ready 或入队。


Generated by Claude Code

…re typed

A pipeline's status is its last command's, so `post-stamped … | tail -N &&
label-write …` rewrites a refusal into the tail's 0: the audit comment is
refused, the label lands, and the card carries a grade with nothing on it
saying why — the half-state the comment-before-label ordering exists to
prevent. The trap was written down in one lane's private wake-up text only,
which is why it reached no seat before it was typed.

It now sits in both places a seat passes through: the write-side block of
`references/rest-channel.md`, beside the two tools it names, and the header
of `scripts/pm/post-stamped.mjs`, which is the file opened before the idiom
is typed. Neither restates the generic mechanism — that reading keeps its
single home in `references/platform-readings.md`.

Paid in place at the 82-line ceiling by retiring the 入队/落地 verification
row: `added_to_merge_queue` is already on this file's own queue-routing
block, and `git rev-list --parents` is a spelling this file's 第三桶 block
already routes to `platform-readings.md`, where it lives verbatim.

Claude-Session: https://claude.ai/code/session_01Bz6hxDBqK62NP2W1LATvnt
Co-authored-by: Claude <noreply@anthropic.com>
…s consult

`Content-Type: application/json` is required of every REST write through the
egress proxy, and a request without it is refused 415 with not one byte
written. The rule existed and was right; it lived only in
`references/platform-readings.md`, while the table a seat opens before
hand-rolling a curl — this file's write-side block, two of whose lines are
about how the request body is spelled — carried no mention and no
cross-reference of it. Six independent 415s across four endpoints in one
shift are the behavioural evidence that the split placement did not reach
the reader; each reads as a concurrent whole-set overwrite of the write,
which is a distributed race that was never there.

The rule is now stated where it is typed, and the reading it is measured
from — the 415 and the discriminator that tells a proxy refusal from a
GitHub one — keeps its single home, one hop away, named rather than copied.

Paid in place at the 82-line ceiling by retiring the shell-expansion reading
beside it: the backtick expansion, the broken-title-intact-body symptom and
the quoted-delimiter requirement are all in `platform-readings.md` verbatim,
and the prescription they belong to stays on the line above.

Claude-Session: https://claude.ai/code/session_01Bz6hxDBqK62NP2W1LATvnt
Co-authored-by: Claude <noreply@anthropic.com>
…t the session

The row read 「REST 按会话为 `claude[bot]` 或用户」 — the premise the fact
table retired: the REST channel's token class follows the Claude Code
account, and it flipped inside a single session, with no seat action, twice
in two days on two different seats. A seat recording a `merged_by` actor
from this row records it on a premise its own read-back can contradict.

Re-keyed in place: the actor is the token class, read from each write's own
read-back rather than assumed from the session, with the measured rows named
instead of copied. `MCP 恒用户` stays — it is this table's fact and has no
other home.

Claude-Session: https://claude.ai/code/session_01Bz6hxDBqK62NP2W1LATvnt
Co-authored-by: Claude <noreply@anthropic.com>
@os-elon-musk os-elon-musk added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 16, 2026 — with Claude
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Sep 16, 2026

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 7e05c91ad9a1f682d630e3ac056fa6da2a31a2d1

① Derived judgments

② Semver level

skip-changeset — nothing published moves.

③ Boundary flags

Implemented-by: claude/issue-18337-rest-channel-write-side-fold
Reviewed-by: session_01Bz6hxDBqK62NP2W1LATvnt

VERDICT: PASS


Generated by Claude Code

@os-elon-musk
os-elon-musk marked this pull request as ready for review September 16, 2026 08:34
@os-elon-musk
os-elon-musk added this pull request to the merge queue Sep 16, 2026
Merged via the queue into main with commit 9a56630 Sep 16, 2026
37 checks passed
@os-elon-musk
os-elon-musk deleted the claude/issue-18337-rest-channel-write-side-fold branch September 16, 2026 08:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment