Skip to content

docs(pm-dispatch): the ruling procedure writes a banner onto the card body - #19303

Merged
os-steve merged 7 commits into
mainfrom
claude/issue-19256-ruling-banner-on-body
Sep 20, 2026
Merged

os-steve merged 7 commits into
mainfrom
claude/issue-19256-ruling-banner-on-body

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

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

… body

A ruling that lands as a comment left the body asserting the opposite, and
nothing reconciled them — the body is what a taker reads first, so a ruled
card kept advertising itself as un-dispatchable.

The director charter's shape section now fixes the BODY's first line the way
it already fixes the ruling COMMENT's first line: the same stroke that records
the ruling writes a `Ruled:` banner and strikes the stale do-not-dispatch
assertion, through post-stamped --body whose --ack-through is the thread read.
No new label and no new state — both measured instances were in the correct
state the whole time.

Claude-Session: https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi
Co-authored-by: Claude <noreply@anthropic.com>
@os-steve os-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 20, 2026 — with Claude
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 20, 2026
…restated clause

The banner act now reads as two lines instead of three: the first fixes the
body's first line and the no-new-label/state guard, the second carries the
strike, the post-stamped route and the failure mode. Both sit under the
120-byte per-line cap the ratchet reads (109 B and 119 B).

Retired the duty-one clause whose substance is already carried one line above
it: an audit seat that is explicitly 非放行链, with clearance standing with the
in-seat review, does not also need to be told not to take the clearance action.

Claude-Session: https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Patch round — the file is at 73, one line above the ceiling

Verdict was REWORK with one item: bring references/lanes/director.md back to 72 / 72. It now reads 73. The compression landed in full; the deletion side could pay only one of the two lines it was asked for, and the second candidate is reported here rather than cut, because cutting it would have dropped a rule with no surviving home.

1. The three added lines are now two

Both sit under the 120-byte per-line cap the ratchet reads. Described rather than quoted — the landed bytes carry the corpus's angle-bracket placeholders, spelled here as words per the body-sanitizer rule:

line bytes carries
L1 109 B 录裁同笔改正文 — the body's first line takes the literal Ruled: plus the ruling comment id, the letter and the UTC stamp; then ⛔ 不新增标签与状态
L2 119 B 划掉原 ⛔ 不派断言 — the strike; the post-stamped --body --ack-through route; 漏此笔 ⇒ 接卡者先读正文退决策箱 — the failure mode and its named reader

⚠️ The element split in the patch order does not fit the cap, and this was measured, not assumed. The order put the strike on L1 beside the act, the spelling and the no-new-label guard; that L1 measures 132 B against the 120 B cap, while its L2 sits at 99 B with 21 B unused. Every spelling of that split was searched — two act phrasings, two strike phrasings, four route phrasings and four failure phrasings, 64 combinations across three element layouts — and zero pairs fit. The one layout that fits moves the strike down to L2. No element the order named was dropped: act, spelling, no-new-label-or-state, strike, route and failure mode are all present, and L1's 录裁同笔改正文 is what binds the strike on L2 into the same stroke.

2. Retired: one line, with the line that now carries its substance

retired, verbatim surviving home, verbatim
- 裁决仍被尊重但非放行必要条件,⛔ 不与席内复核抢同一载体的放行动作。 - 本职是审计位,非放行链:放行常设归派发席席内复核,归属与全链见 ../contract-review.md。 (the line directly above it)

Both halves land there. 「非放行必要条件」 follows from 「非放行链:放行常设归派发席席内复核」 — clearance being the in-seat review's standing duty is exactly what makes a director ruling not a precondition for it; the same fact is stated a second time in 授权与形态 (「复核放行不在其内,常设归派发席席内」) and a third time in the file that line points at, where the director's ruling is declared 非达档裁决. 「⛔ 不与席内复核抢同一载体的放行动作」 follows from 「本职是审计位,非放行链」 — a seat that is not in the clearance chain takes no clearance action. The remaining fragment, 「裁决仍被尊重」, is the concessive half of the sentence and places no obligation on anyone.

Nothing pins the retired text: grep -rn for both of its distinctive phrases across .claude/ and scripts/ returns the charter line itself and nothing else. Its status as a restatement is independently on the record — the ratchet's own ceiling commentary names 非放行必要条件 as a measured restatement in a sibling file, rejected as payment there only because trimming it saved bytes without removing a whole line. Here it is a whole line, so it banks one.

Augmenting the surviving line was considered and rejected on measurement: it stands at 116 B, and appending 「⛔ 不抢放行动作」 would take it to 141 B, past the cap.

3. NOT retired, and why — the second candidate

- 到合并 = 推进到就绪并点名等待,⛔ 不代维护者合并。

The condition for retiring it was that both halves are provably already stated. Only one is.

  • 「⛔ 不代维护者合并」 — yes, stated: 「批准与合并恒是维护者的点击,⛔ 不代。」 in 职责二.
  • 「到合并 = 推进到就绪并点名等待」 — no surviving home. This is the definition of the term the line above it uses (「跟到合并为止」). grep -rn for 推进到就绪 and for 点名等待 across the whole pm-dispatch tree and the dev-agent definition returns this line and nothing else. The nearest candidate, core-rules.md's 「跟到合并为止并每轮读队列成员资格与 origin/main」, defines the follow-through as polling the queue and main each round — not as stopping at ready and naming who is waited on.

Deleting it would leave 「收尾 PASS 且工已完 ⇒ 跟到合并为止」 undefined at the exact point where the misreading is "so merge it" — the reading Prime Directive #14 and #15 exist to prevent. Per 「砍掉内容若在别处无家,砍掉就是丢规则」, it stays.

4. Where that leaves the count

72 ceiling · 73 lines · shortfall exactly 1 line. The ratchet script was not touched and nothing further was deleted, per the patch order. The gate union was re-run on head f411f58: 16 derived, 16 run, 0 NOT-MEASURED, 15 green and check:pm-skill-ratchet exit 1 on that one line. Tier unchanged: GOVERNED, Tier S, this PR stays DRAFT.


Generated by Claude Code

…its ceiling

基本原则's 呈报批序与写法见 ../decision-analysis.md asserted no rule of its own.
Both of its referents survive: the 写法 pointer to the same file is carried by
职责二's 有席内 ACCEPT 者呈一批 ≤5 行 line, and 批序 is that file's own content.

The charter is back at its ratchet ceiling with the banner clause in place.

Claude-Session: https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: daacc874db5582d8bbc750d77cf27fdb803a15ab

① Derived judgments

  • Published accept set / public surface: none moves — one governed prose file (.claude/skills/pm-dispatch/references/lanes/director.md, +2 / −2, 72 / 72 with the ceiling row untouched); no script, no label, no state. check-governed-merges --pr 19303: GOVERNED, Tier S (席内达档复核落地), 4 changed lines. Judged correct.
  • The defect ([finding] a ruling that lands in a COMMENT leaves the card body asserting the opposite, and nothing reconciles them — two cards sat dispatchable for 11 and 15 days telling every reader not to take them #19256): a ruling recorded as a COMMENT left the card BODY asserting the opposite (「⛔ 不派」), and nothing reconciled them — measured at 11 and 15 days on two live cards. The fix is the procedure's missing step, in the 授权与形态 section beside the ruling-comment line it extends: 「录裁同笔改正文:首行加 Ruled: <评论 id> · letter <X> · <UTC>;⛔ 不新增标签与状态。」 (109 B) and 「划掉原 ⛔ 不派断言,走 post-stamped --body --ack-through;漏此笔 ⇒ 接卡者先读正文退决策箱。」 (119 B) — the banner names the comment that rules, the letter and the time; the body's contrary assertion is struck in the same act through the stamped body writer; and the failure mode is closed from the reader's side (a taker reads the body first and returns the card to the decision box). ⛔ No new label, no new state, per the card's own boundary. Judged correct.
  • Payment on a zero-slack file, both lines provable duplicates with surviving homes: round 1 retired :29 「裁决仍被尊重但非放行必要条件,⛔ 不与席内复核抢同一载体的放行动作。」 (home: :27 「本职是审计位,非放行链:放行常设归派发席席内复核」); round 2 — the seat's own decision, ⛔ no ceiling raise — retired :22 「呈报批序与写法见 ../decision-analysis.md。」, a pure pointer whose two referents survive: the 写法 pointer at 职责二 「有席内 ACCEPT 者呈一批 ≤5 行,写法见 ../decision-analysis.md」 (the only other pointer to that file in the charter), and 批序 as that file's own content (decision-analysis.md :13 「批序:在飞被阻塞 > 运营阻塞 > 用户可见 > 结构性」); nothing pins the retired text (grep over .claude/ and scripts/: the line itself only). Judged correct.
  • Evidence, dev-run on this head and seat-read on the diff: check-skill-line-ratchet exit 0 (「director.md is 72 lines (ceiling 72; headroom 0)」, widest line 119 B); check-skill-id-lint / check-governed-prose exit 0; the derived union re-run on daacc87: 17 / 17 exit 0 with --ran reconciled (a DERIVED zero; check:gitlink-declared newly derived and run); the branch is merged up to c334ba0; the three-dot change set is exactly 1 file. CI on daacc87 at the seat's read: 25 check runs, 4 still running, 0 red — the flip waits for them.

② Semver level

None — nothing published; skip-changeset on the PR is the correct declaration. Judged correct.

③ Boundary flags

open_questions empty. Deviations read and accepted: the seat's patch order said 「commit with the card trailer」 and the dev correctly followed AGENTS.md and the pre-push gate instead (a card relation's only carrier is the PR body; the trailer pair is model-free) — the order was the seat's slip, the dev's reading is right; origin/main moved under the shared worktree refs (a two-dot diff shows main's own files; the three-dot set is authoritative); the build refresh stayed narrowed to @objectstack/lint's closure for a two-line markdown change. Two noted, not filed items: 「到合并 = 推进到就绪并点名等待」 is the charter's last pointer-shaped line and is NOT a compression candidate (its definition half has no other home — recorded so no future ceiling round re-measures it; 承接者 PM); the Ruling: (comment) vs Ruled: (body banner) spelling asymmetry is intentional. Seat reading: #19274 (p1) lands in the same charter next, hard-serial behind this PR under 甲; it will need its own retirements and reads this PR's two homes as taken.

Implemented-by: claude/issue-19256-ruling-banner-on-body
Reviewed-by: session_017ETYWqMQD4qMtZzAGovWNi

VERDICT: PASS


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review September 20, 2026 14:49
@os-steve
os-steve added this pull request to the merge queue Sep 20, 2026
Merged via the queue into main with commit a88a973 Sep 20, 2026
28 checks passed
@os-steve
os-steve deleted the claude/issue-19256-ruling-banner-on-body branch September 20, 2026 15:12
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…ly is missing (未回字 = 不在 = 停) (objectstack-ai#19416)

Fixes objectstack-ai#19274

Clause-②: no

The director seat burned the maintainer's tokens while he was away.
Batches 168–178 had drawn no reply since 2026-09-18T15:10Z; the seat
went on presenting batches 179–191 — thirteen batches, sixteen cards,
each with a full four-axis analysis and a reprinted cumulative
awaiting-reply index — and sent an hourly status paragraph besides. The
charter had no sentence saying WHEN the next batch may open, no
definition of "absent", and no word that the pending list is presented
once, so the seat read 「批间新到滚入下批」 as "open the next batch now".

The maintainer ruled twice, verbatim (2026-09-20, the director seat's
chat, quoted untranslated):

> 「你浪费了我很多token,上一批决裁没有回复说我我人不在,你不应该开启下一批决裁。立skills卡」

> 「项目总监由维护者召唤,维护者不在期间什么都不用做。」

The second sentence supersedes the card's rule 3 (a silent patrol still
doing three mechanical things) with 3′: while the maintainer is absent
the director seat does not run at all.

## What changed

Seven in-place line rewrites; net 0 lines in every file — no line added,
deleted or re-wrapped — and every touched line at or under the 120-byte
cap (`wc -c`, newline excluded):

| file:line | before | after | now carries |
|---|---|---|---|
| `references/lanes/director.md:15` | 118 B | 116 B | the definition
「未回字 = 不在 = 停」 and 3′: absent ⇒ the seat does not run — no patrol, no
audit, no snapshot, no chat, no card comment |
| `references/lanes/director.md:16` | 110 B | 116 B | the return: the
audit and the rehang reset are re-run ONCE first, then exactly one line
「批 #N 待字;箱内另有 K 张新到未呈」 |
| `references/lanes/director.md:41` | 77 B | 115 B | receives 「⛔
不复活已退役的汇总 issue」 from :43 — same section, one line down is now the
cadence rule |
| `references/lanes/director.md:43` | 92 B | 113 B | 一次只开一批: batch N+1
is composed from the arrivals only after the maintainer has answered
batch N (one character counts); keep batching until the inbox is empty |
| `references/lanes/director.md:58` | 106 B | 120 B | the 待您清单 and the
awaiting-reply index are presented ONCE, with the batch they belong to,
⛔ never reprinted per round |
| `SKILL.md:766` | 104 B | 118 B | the director entry gains the pointer
未回字 = 不在 = 停 beside ⛔ 无 Routine/cron |
| `references/core-rules.md:147` | 117 B | 119 B | the digest twin of
`SKILL.md:766` |

The landed lines, verbatim:

- director.md:15 — 未回字 = 不在 = 停:维护者不在则本席不运行,⛔ 无巡检、审计、快照、聊天、卡评论。
- director.md:16 — 回来后先补跑审计与重挂复位一次,再只发一行「批 #N 待字;箱内另有 K 张新到未呈」。
- director.md:41 — 决策收件箱 `needs-user-decision` 跨仓勤务,按基本原则批呈;⛔ 不复活已退役的汇总
issue。
- director.md:43 — 一次只开一批:维护者对批 N 回字(一字即可)后,新到才合成批 N+1;续批至清零才收工。
- director.md:58 — 待您清单与待字索引随所属批只呈一次,⛔ 不逐轮重印;座位贴散文降为指针,标签即状态。
- SKILL.md:766 — 项目总监席:维护者在所在仓召唤 `/pm-dispatch director`;⛔ 无
Routine/cron;未回字 = 不在 = 停。
- core-rules.md:147 — 项目总监席由人工召唤,未回字 = 不在 = 停;四职:复核审计、决裁、动作台账、合并审计。

### Where the card's five rules landed

1. 一次只开一批 — director.md:43 (批 N+1 只在维护者对批 N 回字后开, 一字即可).
2. 未回字 = 维护者不在 — director.md:15, the definition; the same literal is the
pointer on SKILL.md:766 and core-rules.md:147.
3′. The seat does not run while absent — director.md:15 (不运行, the list
of what stops); the re-run-once-after-return half is director.md:16.
Self-wake is NOT restated: the standing ⛔ 无 Routine、无 cron at
director.md:7 and SKILL.md:766 already forbids it at every hour, and a
second spelling scoped to the absence could be read as a presence-time
allowance.
4. The index is presented once, never reprinted; one line on return —
director.md:58 and :16.
5. The arrivals are composed into the next batch only after the
maintainer answers — director.md:43 (新到才合成批 N+1); ≤5 per batch keeps its
two existing homes at director.md:23 and :45.

### The payment: every retired clause and its surviving home

Nothing was added, so nothing was retired whole; four clauses left their
lines, each with a home named and grepped (`grep -rn` over `.claude/`
and `scripts/`; nothing pins the retired text — 0 hits for 停放是设计安全态,
滚入下批, 本文不写模型名 outside these files, and the two SKILL.md hits below are
the homes themselves):

| retired from | clause | surviving home |
|---|---|---|
| director.md:15 | 召唤间隔里决策卡与审计窗口停放是设计安全态 | the new :15 itself — 停 IS the
parked state, now defined rather than described (PM assumption 3: one
rule, not two overlapping ones) |
| director.md:15 | 复核放行不在其内,常设归派发席席内 | director.md:28
「本职是审计位,非放行链:放行常设归派发席席内复核」 — verbatim twin |
| director.md:16 | 档位由维护者逐场按项目人工定,⛔ 无档位硬门、无免档整理态 | SKILL.md:769
「总监席档位由维护者按项目人工定,每场记入摘要台账;⛔ 无档位硬门、无免档整理态」 — verbatim twin; SKILL.md is
read in full by every seat session (the ratchet's own header), and
director.md:17 still says the tier is read at session open |
| director.md:16 | 本文不写模型名 | AGENTS.md attribution section: no model
identifier lands in a PR title or body, a comment, a changeset, a doc or
a code comment — and the pre-push hook refuses one in the trailer pair |
| director.md:43 | ⛔ 不复活已退役的汇总 issue | moved verbatim to director.md:41,
same section (职责二), beside the inbox it is about |
| director.md:43 | 批间新到滚入下批,收件箱清零才收工 | the new :43 — 新到才合成批 N+1 (now
conditioned on the reply) and 续批至清零才收工 |
| SKILL.md:766 | the word 入口 | the entry command `/pm-dispatch director`
stays on the line; director.md:14 spells 入口 in full |
| core-rules.md:147 | the full duty names (决裁勤务 / 维护者动作台账 / 受管合并审计) |
SKILL.md:767 and the four director.md section headings carry the full
names; core-rules.md's own header says details live in SKILL.md |

「到合并 = 推进到就绪并点名等待,⛔ 不代维护者合并。」 (director.md:33) was not touched, per the
dispatch.

### Why :15 in place rather than a line beside :7

The dispatch suggested the 不在 = 停 rule beside :7. It went into :15 in
place instead: :15 is the line PM assumption 3 names as the existing
parking rule, in the same 授权与形态 section, and rewriting it is what turns
two overlapping rules into one; :7 stays byte-identical, and :68's
「节奏与停放同授权段」 still points at the section where 停 is now defined. Fewer
lines move, and the no-self-wake rule keeps exactly two homes (:7 here,
:766 in SKILL.md).

## PM mechanism assumptions — measured on this branch

1. **Confirmed.** Branch base `8ddefbc`; the three files are
byte-identical between `0862063` and it (`git diff --stat 0862063
8ddefbc -- ` the three paths: empty). `grep -E '未回字|不在 = 停|一次只开一批|只呈一次'`
over each of the three files at the base: 0 hits, exit 1, three times.
Positive control: `grep -n 'Ruling:'` hits director.md:11, exit 0.
2. **Confirmed, and it shaped the second commit.** The first commit
listed 自唤醒 inside :15's stopped-seat list; the second commit removed it
— a third spelling of the no-self-wake rule, and one an absent-scoped
list could invert. The rule keeps its two homes and :766 now carries the
未回字 = 不在 = 停 pointer beside it.
3. **Confirmed and acted on**, see the payment table: old :15's 停放是设计安全态
became the definition line; :68's pointer is untouched.
4. **Confirmed.** `check:pm-skill-ratchet` prints 72 / 72, 813 / 813,
151 / 151 with `MAX_LINE_BYTES = 120`; `check:pm-skill-id-lint` matches
a hash followed by three or more digits, so the 反例's batch numbers live
only in this body; `check:pm-governed-prose` passes.

## Verification

Gate union derived with `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` (no paths; the tool takes the change
set from the merge base) — 21 commands, byte-identical between the first
head and the final head `33d8403`. Run on `33d8403`, every exit captured
before any pipe (redirect first, then the status): **21 of 21 exit 0** —
`check-closing-keyword-parity` (and `--self-test`),
`check-comment-mask-corpus`, `check-governed-queue-guard --self-test`,
`check-harness-current --self-test`, `@objectstack/lint
check:doc-formula-expressions`, `check:agent-test-spelling`,
`check:cross-package-test-inputs`, `check:doc-authoring`,
`check:driver-memory-census`, `check:gitlink-declared`,
`check:nul-bytes`, `check:pm-expected-skips`,
`check:pm-governed-merges`, `check:pm-governed-prose`,
`check:pm-half-states`, `check:pm-skill-id-lint`,
`check:pm-skill-ratchet`, `check:refd-timer-probe`,
`check:skill-frame-sync`, `check:watch-hint-literal`. `--ran`
reconciliation with the exit codes recorded: 21 derived, 21 run, 0
NOT-MEASURED — a DERIVED zero, none of the 21 is exit 3.

- `check:doc-formula-expressions` first refused with exit 3 PREREQUISITE
NOT MET (`@objectstack/formula` and `@objectstack/lint` not built) —
recorded as NOT MEASURED, not red; the `@objectstack/lint` closure
(spec, formula, sdui-parser, lint) was then built under the shared
verify lock (`VERDICT command-exit 0`, 195 s held) and the gate re-run
green.
- Extra, run on purpose: `check:pm-settings-deny-roster` exit 0 (the
derivation marks its roster as living under `.claude/`, where silence is
evidence in neither direction).
- Ratchet positive control (taken on the first head `5b04dc7`; the file
is 72 lines and the ceiling row untouched on both heads): one bullet
appended to director.md → 73 lines → `check-skill-line-ratchet` exit 1
with its own verdict line 「is 73 lines; the ratchet ceiling is 72」;
restored with `git checkout HEAD -- ` that path, proven by `git
hash-object` equal to the HEAD blob, `git diff HEAD` empty and `git
status --porcelain` empty; the gate exits 0 again after the restore.
- Control-character self-scan (`grep -naP` over the C0 set plus DEL) on
the three files: no match. Bare card ids on the added lines: none.
- `check:pm-dispatch-gates` (the slow whole-tree family the dispatch
named) is running detached on `33d8403` as this body is written; its
exit lands in the `os-dev-report` comment on the card — this body is
written once.
- Governed tier, measured locally: ⛔ GOVERNED — Tier S(席内达档复核落地): every
governed path here lies under a Tier S surface, so the OWNING
(`check-governed-merges.mjs --test` on the three paths with the diff's 7
/ 7 line counts). This PR stays DRAFT; the owning seat lands it on a `##
Contract review` record for the current head.

No changeset: `.claude/**` publishes nothing from any released package.
Label `skip-changeset` applied.

## 维护者速读(草稿)

**改了什么** — 总监席章程里改了七行,每个文件一行不增不减:① 定义句「未回字 = 不在 =
停」——您对上一批没回字就等于您不在,不在期间本席不运行:不巡检、不做合并审计、不给决策箱拍快照、不在聊天里发任何东西、不在任何卡上留评论;②
您回来时,本席先把合并审计与重挂复位补跑一次,然后只发一行「批 #N 待字;箱内另有 K 张新到未呈」;③ 一次只开一批:批 N+1 只在您对批
N 回字(一个字也算)之后才由新到的卡合成;④ 待您清单与待字索引跟着所属批只呈一次,不逐轮重印;⑤ SKILL.md
总监席条目和核心条款摘要各带上「未回字 = 不在 = 停」这一句指针。自唤醒不再重复写:章程原有的「⛔ 无 Routine、无
cron」已经禁了它。

**为什么改** —
您的两句原话:「你浪费了我很多token,上一批决裁没有回复说我我人不在,你不应该开启下一批决裁。立skills卡」与「项目总监由维护者召唤,维护者不在期间什么都不用做。」反例:批
168–178 自 2026-09-18 起无一回字,总监席照样开了批 179–191(13 批 16
张),每批带完整四轴与逐批重印的累计索引,外加每小时一段状态散文,还用 send_later 自唤醒 68 次——这些 token
全烧在您不在的时候。旧章程只写「批间新到滚入下批」,没写下一批何时可开、没定义「不在」、没说清单只呈一次。

**风险与代价(含回滚)** — 行数零增长,每行 ≤120
字节,四条被挤出的旧句各有出处可查(上表)。代价:总监席不在场时完全静默,受管合并审计推迟到您回来后补跑一次;这是您第二句话的直接后果。回滚:`git
revert` 这两个提交即可,不涉及任何脚本或门禁。

**席位意见** — (留空,席位复核时填)

**你要做的** — 无。`.claude/**` 是 Tier S,由席位在复核记录后落地;这份 PR 是草稿,不需要您点击。

## Acceptance notes

Noted, not filed — none is a reproducible defect, a declared-contract
violation, or a metadata-authoring trap:

- `references/decision-analysis.md:12` already says 「呈完即停等回批」 for the
standing batch flow; the director seat did not obey it and the charter
now spells the rule for that seat. Whether decision-analysis.md should
point at director.md:43 is a question for its next editor. 承接者:无.
- `scripts/pm/check-prior-rulings.mjs` header cites
`references/lanes/director.md:45` for the grep step that has sat at :47
since PR objectstack-ai#19303 inserted three lines above it — a comment's line number,
not a pin (the script reads no line numbers). 承接者:无.
- director.md:68 「⛔ 无 cron,节奏与停放同授权段」 now points at a section where 停 is
defined while the batch cadence itself lives at :43; left untouched to
keep this diff at seven lines. 承接者:无.

---
_Generated by [Claude
Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants