diff --git a/.claude/skills/pm-dispatch/references/rest-channel.md b/.claude/skills/pm-dispatch/references/rest-channel.md index 82130421bc3..a195fc4a47a 100644 --- a/.claude/skills/pm-dispatch/references/rest-channel.md +++ b/.claude/skills/pm-dispatch/references/rest-channel.md @@ -36,10 +36,11 @@ - ✓ 评论 `POST .../issues/{n}/comments`;改评论 `PATCH .../issues/comments/{id}`。 - ✓ 标签加法 `POST .../issues/{n}/labels`,定向删 `DELETE .../issues/{n}/labels/{name}`;加法优先。 - 标签/assignee 写恒经 `scripts/pm/label-write.mjs`:四步内建、回读、回退整组 PATCH 回传 assignees。 +- ⛔ `post-stamped`/`label-write` 永不接进管道再 `&&`:拒收读成 0;看尾先落文件或 `set -o pipefail`。 - ⛔ 永不 MCP `issue_write`(锁 1 已拒);会话分类器拒改动 ⇒ 无通道,交有通道席位立卡。 - ✓ 建卡带标签 `POST .../issues` · 改正文 `PATCH .../issues/{n}` · 认领 `POST .../issues/{n}/assignees`。 - 请求体走文件(`-d @file`)或引号定界 heredoc(`<<'EOF'`),⛔ 永不内联双引号串。 -- 双引号内 shell 先展开反引号、`$(...)`、`$VAR`,请求尚未成形;只标题坏而正文完好即此形。 +- 每个写请求必带 `Content-Type: application/json`;缺头的 415 与判别式见配额段。 - ✓ 请求复审 `POST .../pulls/{n}/requested_reviewers` · 开 PR `POST .../pulls` 带 `draft=true`。 - ✓ `origin/main` 合进 PR head:`PUT .../pulls/{n}/update-branch`,PM 席位、零文件写、真合并提交。 - `expected_head_sha` 须完整 40 字符 SHA(短 SHA 回 422);base 未动回 422 = 无事可做,不是失败。 @@ -49,9 +50,8 @@ - ✓ `POST .../ccr/comments/{id}/resolve` · `/unresolve`;`{id}` 是评审评论 id,⛔ 只在自己 PR 上探。 - ✓ auto-merge 挂载 `PUT .../pulls/{n}/ccr/auto_merge` 带 `{"merge_method":"SQUASH"}`,`DELETE` 卸载。 - ⛔ `PUT .../ccr/auto_merge` 在 draft 上 422 零存储;`DELETE` 无挂载回 422 = 本就没挂,非失败。 -- 入队读 timeline `added_to_merge_queue`,落地读 `git rev-list --parents`;⛔ `auto_merge` 与回显都不作数。 - ⛔ 永不 MCP `update_pull_request`(锁 1 已拒);ready/draft 翻转只走 ccr 路;auto-merge MCP 锁 1 同拒。 -- 直合仓 `PUT .../pulls/{n}/merge`;actor 记通道令牌:REST 按会话为 `claude[bot]` 或用户,MCP 恒用户。 +- 直合仓 `PUT .../pulls/{n}/merge`;actor 记令牌类,按账号非会话、逐写回读;见配额段,MCP 恒用户。 ## 不可迁移 —— 只有这三件,围着它们排计划;红窗守候规则住 `platform-readings.md` 配额段 diff --git a/scripts/pm/post-stamped.mjs b/scripts/pm/post-stamped.mjs index f5fe528a9f2..9b124d419cf 100644 --- a/scripts/pm/post-stamped.mjs +++ b/scripts/pm/post-stamped.mjs @@ -62,6 +62,24 @@ * `{{NOW}}` is never refused — so mixed alone would not have caught the * recorded failure, whose comments carried no token at all. * + * ## ⛔ Never pipe this tool, then `&&` the write that follows + * + * The exit register above is worth exactly what the caller reads. A pipeline's + * status is its LAST command's, so the habitual seat idiom + * `post-stamped … | tail -3 && label-write …` hands the `&&` tail's 0 and the + * refusal is gone: the audit comment is REFUSED, the label lands anyway, and the + * card is left graded with nothing on it saying why — the half-state the + * comment-before-label ordering exists to prevent, and the direction of it that + * nobody can recover from a later read. Measured on a live card, where the seat + * noticed eight seconds on; a turn that had ended there would have left it. + * + * So read the output without spending the code — redirect first, then capture: + * + * node scripts/pm/post-stamped.mjs … > /tmp/p.log 2>&1; EXIT=$?; tail -3 /tmp/p.log + * + * or arm `set -o pipefail` before the pipeline. The rule is the caller's, not + * this tool's, so it covers every writer beside it — `label-write.mjs` included. + * * ## The quoted route has a DIRECTION, not only a shape (#17763) * * Checking that a `{{WAS:…}}` value is shaped like a stamp leaves the estimate