Commit 5ed7ad9
docs(pm-skills): name the issue-state leg on the REST channel write side (#18580)
Fixes #18563
## What changed
One row added to the write side of
`.claude/skills/pm-dispatch/references/rest-channel.md`, and one
redundant line retired to pay for it. Net zero lines, so the file stays
at its ceiling.
**Added** (new `:42`, 115 B):
```
- ✓ 该 `PATCH` 带 `state` 关卡/重开,`state_reason` 交付 `completed`、撤单 `not_planned`,走裸 REST。
```
Line `:41` is **unchanged** (120 B) and still names `PATCH
.../issues/{n}` as 改正文; the new row sits directly beneath it and gives
the same endpoint its state leg.
**Payment — a genuine deletion, not a re-wrap.** The `issue transfer`
item of the 不可迁移 list went from two lines to one:
```
-3. `issue transfer`:issues 端点表无 transfer 路由(核对文档,未实调)⇒ 同为 GraphQL-only。 105 B
- 拿不到时当轮改走在目的仓重建配方,配方住 `platform-readings.md`。 87 B
+3. `issue transfer`:issues 端点表无此路由(未实调)⇒ 同为 GraphQL-only;配方住 `platform-readings.md`。 118 B
```
Why the retired line was redundant: it restated a fallback instruction
that `platform-readings.md` already owns in full — that file's `:147`
reads 「`issue transfer` 因配额或权限拿不到 ⇒ 当轮改走多仓协调条款的在目的仓重建配方。」 and `:148`
carries the recipe itself. Keeping a second copy here is exactly what
this file's own rule forbids (「本表只指路,⛔ 不在两处各存一份」), and it is the same
payment pattern the ratchet's own history records for this very file:
the 红窗 restatement was retired under the content-ownership ruling 「红窗规则由
`platform-readings.md` 配额段独家持有,`rest-channel.md` 只留指路」. The pointer that
rule permits is kept, folded into the numbered item at zero line cost.
The provenance aside 「核对文档」 also goes, per the 2026-09-04 rules-only
rewrite that took provenance narrative out of this corpus. **No live
fact leaves the file.**
## The dispatched mechanism assumption did not hold
The dispatch expected the leg could be folded into `:41` in place, on
the reading that this file's ratchet pins table-row width and not bullet
width. Measured on this branch, that is **false**:
`check-skill-line-ratchet` enforces a per-line **120-byte
max-line-length rule** on ordinary bullets, and `:41` is already
**exactly 120 B**. The "widest table row is 0 bytes (pin 0)" reading is
a separate pin, and it reads 0 only because this file contains no
markdown table rows at all.
Ablation, with the mutation and the restore each proved on disk.
Injecting six bytes to take `:41` to 126 B turns the gate red:
```
✗ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/rest-channel.md has 1 line(s) over the 120-byte budget: L41 (126B).
```
The restore leg was verified by blob hash, not by an exit code: `git
checkout HEAD --` on the path, then `git hash-object` compared equal to
the HEAD blob `a195fc4a47a49ab0b712d059d09a4e92a6707783`. So the
in-place route was unavailable, and the other route the grading
sanctioned — a new row paid by a genuine deletion — was taken instead.
**One thing did not fit, and is flagged rather than quietly dropped.** A
single row cannot carry every element the card lists: the fullest honest
spelling measures about 129 B against the 120 B cap. The row keeps the
endpoint, both directions (close and reopen), both payload keys, the
reason mapping, and the corrective conclusion that the channel is a raw
REST call. What did not fit is the parenthetical naming
`post-stamped.mjs` and `label-write.mjs` as the two writers that lack
the leg — lines `:38`-`:39` already tell the reader what those two
scripts do.
## Ratchet on this head
```
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/rest-channel.md: widest table row is 0 bytes (pin 0; headroom 0).
✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/rest-channel.md is 82 lines (ceiling 82; headroom 0).
```
82 / 82, headroom 0, unchanged. Every line in the file is at or under
120 B.
## Gates
Derived from this worktree with `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack`, no paths passed so the
script takes its own change set from the merge base. Re-derived after
the `origin/main` merge and identical. Every exit code captured before
any pipe.
```
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/pm/check-governed-queue-guard.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-skill-id-lint :: exit 0
pnpm check:pm-skill-ratchet :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:watch-hint-literal :: exit 0
```
`dispatch-gates --ran` reconciliation: **15 derived, 15 run, 0
NOT-MEASURED, 0 UNRUN** — a derived zero, every family carrying a
recorded exit code.
Also run, beyond the derived list:
```
node scripts/pm/check-governed-merges.mjs --test .claude/...rest-channel.md :: exit 3
pnpm check:pm-settings-deny-roster :: exit 0
```
Exit 3 there is the **expected GOVERNED verdict**, not a failure: this
is a `.claude/**` path, so a human merge is the review record and no
seat flips it ready, enqueues it, or arms auto-merge. The deny-roster
gate was run because the derivation flagged its roster as living under
`.claude/`, where silence is evidence in neither direction.
One gate needed a second pass. `pnpm --filter @objectstack/lint run
check:doc-formula-expressions` first returned **exit 3 PREREQUISITE NOT
MET** — unbuilt workspace packages, and the gate says plainly that
nothing was measured. After `pnpm exec turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint` through the
shared verify lock (`VERDICT command-exit 0`, held 128 s), it re-ran at
**exit 0**. Only the real reading is recorded above.
## Note for the reviewer
The row now states a measured fact: the same `PATCH .../issues/{n}` that
edits a card body also closes and reopens one, carrying `state` and
`state_reason`, and it is reached as a raw REST call rather than through
either sanctioned writer script. Two live measurements back it — card
16023, set to state closed with reason `completed` at
2026-09-17T01:42:37Z by the `domain:services` seat (record 5707137250),
and card 17323, the same at 2026-09-17T02:45:08Z by the skills seat with
body, `state` and `state_reason` in one PATCH (record 5707679383).
`skip-changeset`: nothing under any package's `files[]` moves —
`.claude/**` is not published.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent a55646b commit 5ed7ad9
1 file changed
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
39 | 39 | | |
40 | 40 | | |
41 | 41 | | |
| 42 | + | |
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
| |||
58 | 59 | | |
59 | 60 | | |
60 | 61 | | |
61 | | - | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
0 commit comments