Repository navigation
Commit 99364ea
fix(pm): label-write judges a release comment on post-stamped's path and no longer hangs after a comment stroke (#31640)
<!-- claude-projects-attribution: {"github_login":"zhuangjianguo"} -->
_Requested by **Steedos** · [project
thread](https://claude.ai/code/project/chan_018ETKaNwMZCNRYD7D8Q9Ubb?thread=cmsg_018ETKaNwMZCNRYD7D8Q9UbbTjFugUJEMvp4sHgCZNYxdU)_
Fixes #31585
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:`label-write --release` 发出的释放评论,现在和其它席位评论一样先过 post-stamped
的同一个审查(`judgeBody`),没有首行署名就当场拒发;同时修好了 `--comment-file` 发评论后卡死不退出的问题。
- **为什么改**:释放评论是唯一一条不查署名就发出去的席位评论通道;而 `--comment-file`
在中继成功后进程卡死,席位重跑就把认领评论发了两遍(本卡上已发生)。
- **风险与回滚**:只动 `scripts/pm/label-write.mjs` 一个文件,不发布任何包;回滚即 revert 本
PR。没签名的释放文本从此会被拒(这是本意)。
- **先看**:`scripts/pm/label-write.mjs` 的 `composeReleaseBody`(改走
`judgeBody`)、三处 `send(packed.payload, …)`(交入 `judge`)、自测里新增的
`realTransport`。
- **两分钟验证**:`node scripts/pm/label-write.mjs --self-test`,预期最后一行 `203
cases pass across 15 batteries`。
- **需要你做的**:无,席位落地。
## What changes
1. **`--release` judges its comment on post-stamped's path.**
`composeReleaseBody` now returns `judgeBody(raw, { mode: 'comment' },
nowMs, 'label-write')` instead of `renderBody(raw, nowMs)`. The composed
body (operator text, `Resume-from:` line, `{{WAS:…}}` clock provenance,
all unchanged) goes through the stamp contract, the signature first line
and the comment-mode keyed-line readers. An unsigned release text is
exit 2, `stoppedAt: 2`, zero sends and zero writes, and the refusal is
post-stamped's own text naming `label-write`.
2. **The fold hang (claim amendment, Wanted 3).** After a body-bearing
relay run succeeds, `sendFleetWrite` reads the body back. With no
`judge` passed, it loads one with a dynamic
`import('../post-stamped.mjs')`. `label-write.mjs`, `post-stamped.mjs`
and `fleet-write/dispatch.mjs` import one another, so they evaluate as
one cycle, and that cycle only completes when label-write's top-level
`await main(…)` does. The dynamic import waits on that same await, so it
never settles. Node drains the loop and exits 13 ("unsettled top-level
await") with no `④` line. This hit both `--comment-file` and
`--release`. Every `send(packed.payload, …)` in label-write now passes
`judge: readBackJudge()` (post-stamped's `classifyReadBack` and
`sentBodyLanded`, built at call time, never at module scope).
post-stamped is not affected: its entrypoint uses `main(…).then(…)`, not
a top-level await.
3. **Header text** gains a `judged` step under `--release` and a section
on why the read-back judge is handed in.
No `.claude/**` text states the old behaviour. The one hit,
`triage-duties.md` L83 (`label-write.mjs --release` 一笔中继释放), says
nothing about how the comment is judged. Procedure text is unchanged.
## Tests
`node scripts/pm/label-write.mjs --self-test`: 196 cases across 14
batteries before, 203 cases across 15 batteries after (head `72ff13bb`).
- New battery: **the real transport** (5 cases, floor 15 batteries). It
drives a claim fold and a release through fleet-write's real
`sendFleetWrite`: real dispatch, real run poll, real body read-back.
Only `fetch`, the clock, the sleeps and the throttle file are fake, and
the fake answers from the same fake board. Each send is raced against a
15 s ceiling, so a promise that never settles shows up as
`never-settled` and the event loop is not left to drain. Pins: the fold
settles with exit 0 and prints `④ labels/assignees/comment ✓` and `④
MATCHES`; the release settles with exit 0 and prints `④ MATCHES —
released`; and a structural pin checks that all 3 `send(packed.payload,
…)` calls pass `judge: readBackJudge()`.
- Release battery 32 → 34. New pin: an unsigned release text is refused
before the stroke (exit 2, `stoppedAt` 2, 0 dispatches, 0 direct writes,
the `label-write: REFUSED … opens with no signature line` text). New
structural pin: `composeReleaseBody` returns `judgeBody(raw, { mode:
'comment' }, …)`, `runRelease` composes before `packRequest`, no
`renderBody(` call is left, and label-write defines no reader of its
own. The release fixture is now signed, and the signed release still
sends one dispatch and reads back `④ MATCHES — released` as before.
<details><summary>Reverse verification (both legs committed first,
restore proven by hash)</summary>
- Pin before the fix (commit `7d50fb8b`, on main's code): 4 of 200
failed. Both the fold and the release answered `never-settled` right
after `run 42 completed — conclusion success`, which is the seat's live
log shape, reproduced offline with no write.
- Ablation of the fold's `judge: readBackJudge()` on the fixed head: 3
of 203 failed (fold settles ×2, structural send pin). Restored with `git
checkout HEAD --`, hash equal to the HEAD blob.
- Ablation of the judging (pass whatever renders): 2 of 203 failed
(unsigned refusal, structural judge pin). Restored, hash equal.
</details>
## Acceptance notes
- The comment-mode readers pass a legal release body. Probed with
`composeReleaseBody` on the signed fixture, and on a signed release that
also quotes a line-start `Claim:` line: both `ok`. The unsigned one is
refused. No reader was loosened.
- `close-cards.mjs` and `issue-create.mjs` also use a top-level `await
main(…)`, but they are outside the import cycle, so a lazy judge import
from them should settle. Not measured live; noted only.
## Verification
<details><summary>Derived gates on 5938091 (diff is one file; main
merged after, no overlap with it)</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 33. All 33 exited 0, and `--ran`
reconciled: 33 derived, 33 run, 0 NOT-MEASURED, 0 UNRUN. That includes
`pnpm check:pm-label-write`, `pnpm check:pm-post-stamped` (761 cases),
`pnpm check:pm-write-pace`, `pnpm check:refd-timer-probe`, `pnpm
check:nul-bytes`, `node scripts/check-whole-set-label-write.mjs` (+
`--self-test`) and `pnpm check:pm-dispatch-gates` (fast tier, 2205
cases, 491 s). `eslint --no-inline-config scripts/pm/label-write.mjs`
exit 0. After merging `origin/main` (3 commits, none touching
label-write, post-stamped or dispatch), the self-test is green on
`72ff13bb`.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01QsR2jR91pcCzC1k9n3p5ah)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 711c4ec commit 99364ea
1 file changed
Lines changed: 172 additions & 19 deletions
0 commit comments