Repository navigation
Commit a88a973
docs(pm-dispatch): the ruling procedure writes a banner onto the card body (#19303)
Fixes #19256
Clause-②: no
A ruling that lands as a COMMENT left the card BODY asserting the
opposite, and nothing reconciled the two. The body is what a taker reads
first, so a ruled card went on advertising itself as un-dispatchable —
measured at 11 and 15 days on two live cards.
The director charter's 授权与形态 section already fixes the first line of the
ruling COMMENT. This adds the sibling rule for the first line of the
BODY, in the same stroke that records the ruling.
## What changed
`.claude/skills/pm-dispatch/references/lanes/director.md` — three lines,
inserted directly after the 「裁决评论首行固定一条」 line. Nothing else in the file
moved; no line was deleted or re-wrapped.
Their content, described rather than quoted (the landed bytes carry the
corpus's usual angle-bracket placeholders; this body spells them as
words, per the body-sanitizer rule in AGENTS.md):
1. **The act and its shape** — recording a ruling writes, in the same
stroke, a one-line banner on the body's first line: the literal `Ruled:`
followed by the ruling comment id, the letter, and the UTC stamp,
separated by the middle dot the sibling comment line already uses.
Closes with ⛔ 不新增标签与状态 — both measured instances were in the **correct**
state the whole time, so the clause adds no label and no state.
2. **The strike, the reader and the failure mode** — the body's own 「⛔
不派 / 决策卡」 assertion is struck in that same stroke; skipping it means the
body contradicts a landed ruling, and 接卡者先读正文 sends the next taker back
to the decision box exactly as before.
3. **The channel** — the banner goes through `post-stamped --body`,
whose acknowledgement flag names the newest comment, so that
acknowledgement IS the thread read the charter's 裁前先读线程 line already
requires. No new tool capability: the act is the seat's, spelled in the
procedure.
### Why 授权与形态 and not 职责二
One home, not both. 授权与形态 is the shape section, and the new lines sit
beside the rule that fixes the ruling comment's first line —
body-first-line and comment-first-line are siblings. It also reaches
every path that records a ruling: the 一类自裁 self-ruling that 录裁转工作态
without going to a batch, the 代裁 channel, and the maintainer's 一行回批
alike. Under 职责二 決裁勤务 the same text would read as scoped to the
batch-reply path, which is the one path the two measured instances did
**not** take alone.
## Measurements taken on this branch
- **PM assumption 1 — confirmed.** On the branch base, `grep -nE
'banner|正文|body'` over the charter returns **0 hits**, exit 1; the
positive control `grep -n 'Ruling:'` hits line 11, exit 0. The ruling
procedure had no body-side act.
- **PM assumption 2 — refuted in its present tense, and the refutation
is useful.** objectui#7508 and objectui#7750 no longer read as the card
describes: both bodies now open with a hand-written multi-line
blockquote banner (「⛔⛔ THIS CARD IS RULED…」) naming the ruling date, the
letter, the ruling comment id and the recorded `needs-user-decision` →
`pm:queue` transition, with the stale paragraph left in place below it
and explicitly marked stale. objectui#7750's `updated_at` reads
2026-09-20T05:58Z — the filing round's own remediation of the two
instances, not a mechanism. Nothing in `.claude/skills/**` spells that
shape (`grep -rn 'CARD IS RULED'` over `.claude/` and `scripts/pm/`: 0
hits), so the gap the card names is live and this PR is what makes the
remediation a rule. The landed clause is a floor: a one-line banner,
which the two measured bodies exceed.
- **PM assumption 3 — confirmed.** `scripts/pm/post-stamped.mjs` spells
the flag as an `ack-through` option belonging to a `--body` refresh,
refusing a body write while unacknowledged newer comments exist and
refusing an id that is not the newest. Re-verified against current
`origin/main` after the merge below (17 occurrences), since that file
moved on main while this branch was open.
- **PM assumption 4 — confirmed.** `check:pm-skill-id-lint` exits 0: the
landed lines cite no card, and the two objectui instances appear only in
this PR body.
- **Governed tier.** `node scripts/pm/check-governed-merges.mjs --test
.claude/skills/pm-dispatch/references/lanes/director.md` → GOVERNED,
**Tier S** (`.claude/**`), 1 of 1 path hitting the register. This PR
stays DRAFT; the owning seat lands it on a `## Contract review` record
for the current head.
## ⛔ One gate is RED, and it cannot be greened from this PR's declared
file surface
`pnpm check:pm-skill-ratchet` → **exit 1**, its own verdict line:
> ✗ check-skill-line-ratchet:
.claude/skills/pm-dispatch/references/lanes/director.md is 75 lines; the
ratchet ceiling is 72. … Raising a ceiling requires a maintainer ruling
quoted in the PR.
The arithmetic, in full:
| reading | value |
|---|---|
| file before / after | 72 → 75 lines (+3 added, 0 deleted, 0
re-wrapped) |
| dispatch net-line budget | net ≤ +4 — **satisfied** |
| ratchet ceiling | 72, **headroom 0** |
| new lines, widest to narrowest | 117 B · 105 B · 96 B, all under the
120-byte per-line cap |
| file's widest line | 118 B before and after — unchanged |
| losslessly compressible slack | **none**: of the file's adjacent
bullet pairs the smallest merges to 129 B against the 120-byte cap, so
zero pairs merge |
So the two currencies the ratchet accepts are both unavailable here.
Deleting content is not one: every line in this charter is a live rule
with a reader, and cutting one would be a scope expansion this card does
not authorize. Re-wrap is not one either — there is no soft-break slack
to reclaim, and buying lines for new content with a re-wrap is forbidden
to a dev seat regardless.
That leaves the route the ratchet itself names and the ceiling row's own
history records — the row was raised 75 → 77 once before on exactly this
file at headroom 0, paid for by a maintainer directive that dictated the
lines. **That raise is not in this PR's file surface**
(`scripts/pm/check-skill-line-ratchet.mjs` is not `director.md`), and a
dev seat does not set it. The lines are landed, the ceiling row is
untouched, and the measured count is reported red rather than hidden. To
green this PR the ceiling row needs 72 → 75 with the authorizing ruling
quoted in the raising PR.
## Verification
Gate union derived and run on the final head `af00eb6`, with each exit
code captured before any pipe:
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths) → 16 commands, byte-identical to
the derivation the dispatch carried.
- `node scripts/pm/dispatch-gates.mjs --ran …` → ✓ 16 derived families
accounted for — 16 run, 0 NOT-MEASURED (a DERIVED zero: all 16 recorded
an exit code and none is 3).
- **15 green, 1 red**: `check:pm-skill-ratchet` exit 1, above. Green:
`check-closing-keyword-parity` (and its self-test),
`check-comment-mask-corpus`, `check-harness-current --self-test`,
`check:doc-formula-expressions`, `check:agent-test-spelling`,
`check:cross-package-test-inputs`, `check:doc-authoring`,
`check:driver-memory-census`, `check:nul-bytes`,
`check:pm-governed-merges`, `check:pm-skill-id-lint`,
`check:refd-timer-probe`, `check:skill-frame-sync`,
`check:watch-hint-literal`.
- `check:pm-settings-deny-roster` → exit 0, run on purpose: the
derivation marks it as keeping its roster under `.claude/`, where
silence is evidence in neither direction.
- Control-character self-scan over the changed file beyond
`check:nul-bytes`: `grep -naP` for the C0 set and DEL returns no match.
- `origin/main` was merged into the branch (it had moved 3 commits, one
of them `scripts/pm/post-stamped.mjs`, which the new clause names);
`director.md` was untouched on main and the branch diff is still exactly
+3 lines in that one file. Build state was refreshed for the one package
the union needs compiled (`@objectstack/lint` and its closure) rather
than the whole tree — a declared narrowing, since the diff is three
markdown lines.
No changeset: `.claude/**` publishes nothing from any released package.
Label `skip-changeset` applied.
## Acceptance notes
Noted, not filed — neither is a reproducible defect, a declared-contract
violation, or a metadata-authoring trap:
- The banner actually written onto the two objectui bodies is a
multi-line blockquote carrying the ruling's substance, not the single
line this clause requires. The clause is deliberately a floor and the
richer form satisfies it; whether the charter should fix the richer
shape is a question for whoever next edits this file. 承接者:无 — no queued
PR or card touches this charter.
- The ruling-comment first line spells `Ruling:` with a batch and item
number; the body banner spells `Ruled:` with the comment id. The
asymmetry is intentional — the body must point at a retrievable id,
which the charter's 出决策箱须引可取回的裁决 id rule already requires — but the two
spellings sitting one line apart will invite a future author to unify
them. 承接者:无.
---
_Generated by [Claude
Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 8271c81 commit a88a973
1 file changed
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
12 | 14 | | |
13 | 15 | | |
14 | 16 | | |
| |||
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
22 | | - | |
23 | 24 | | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
29 | | - | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
0 commit comments