Commit 547b9ab
skills(pm-dispatch): hard serial across rounds applies to the same claimed region, not the same file — SKILL.md :441 and its core-rules twin (#19317)
Fixes #18891
Clause-②: no
Ruling-ref: 5727164406 — director seat, batch 157 item 2, letter 甲,
maintainer 「其他同意」 2026-09-18T08:10Z
## What changed — two lines, one word each, net 0 in both files
| File | Line | Before | After | Bytes |
|---|---|---|---|---|
| `.claude/skills/pm-dispatch/SKILL.md` | :441 | 「-
同文件单跨轮硬串行;延后不是搁置,被延后那一刻就把已知的坑记到该 issue 上。」 | 「-
同区域单跨轮硬串行;延后不是搁置,被延后那一刻就把已知的坑记到该 issue 上。」 | 107 → 107 |
| `.claude/skills/pm-dispatch/references/core-rules.md` | :105 | 「-
同批独立性按文件面不相交判,⛔ 不按包;同文件硬串行,冲突交合并队列仲裁 ⛔ 不手排。」 | 「- 同批独立性按文件面不相交判,⛔
不按包;同区域硬串行,冲突交合并队列仲裁 ⛔ 不手排。」 | 119 → 119 |
Line counts: SKILL.md 813 / 813, core-rules.md 151 / 151. `:437` is
untouched; `SINGLE_CLAIM_PATHS` stays the only whole-file single-writer
set; the 「延后不是搁置…」 half stays byte-verbatim; the core-rules twin lands
in the same PR as SKILL.md:44 orders. No script, no gate, no other line
of either file. The commit is `5676515` on
`claude/issue-18891-region-level-serial`, base `801415a`.
## Why this rendering and not the ruling's sentence verbatim — measured,
not assumed
The ruling's :441 text 「同区域(认领申报的文件面重叠)单跨轮硬串行;同文件不同区域是普通并发,后落地方解冲突。」 is
123 bytes as a bullet line, and 198 bytes with the 「延后不是搁置…」 half the
ruling keeps. `scripts/pm/check-skill-line-ratchet.mjs` (`pnpm
check:pm-skill-ratchet`, not `check:pm-governed-prose` as the dispatch
assumed) caps every non-exempt line of this file at `MAX_LINE_BYTES =
120` and holds the file at ceiling 813 with headroom 0, so the ruling's
own sentence cannot land as written under the file's own gate without a
script edit that both the ruling (「⛔ no new script, no gate」) and the
dispatch (net 0, no script) refuse. Readings taken on the real gate,
each mutation restored to the HEAD blob (hash-verified, `git diff HEAD`
empty) before the next:
| Run | :441 rendering | `check:pm-skill-ratchet` verdict |
|---|---|---|
| R0 | unmodified | ✓ SKILL.md is 813 lines (ceiling 813; headroom 0) |
| R1 | ruling sentence + deferral half, ONE physical line (198 B) | ✗ 1
line over the 120-byte budget: L441 (198B) |
| R2 | ruling sentence (123 B) / deferral half (79 B), TWO lines | ✗
L441 (123B) over budget AND ✗ 814 lines; the ratchet ceiling is 813 |
| R3 | ruling sentence with 不同区域→异区域 (120 B) / deferral half, TWO lines
| ✗ 814 lines; the ratchet ceiling is 813 |
| R4 | core-rules :105 同文件硬串行 → 同区域硬串行 (119 B) | ✓ core-rules.md is 151
lines (ceiling 151; headroom 0) |
| landed | :441 同文件 → 同区域 (107 B) plus R4 | ✓ both files at ceiling,
headroom 0 (exit 0) |
The neighbours cannot absorb the 74-byte deferral half either: :436 to
:452 measure 118 / 114 / 112 / 114 / 118 / 107 / 117 / 104 / 67 / 115 /
79 / 111 / 82 / 98 / 120 / 117 / 109 bytes, and the only other line that
speaks of deferral (:452, 「阻塞解除后延后单重定价…」, 109 B) has 11 bytes of slack.
A bigram-Jaccard scan over the file's 627 bullet lines finds no provable
duplicate to retire: the top pairs (J 0.59 down to 0.35) are distinct
pointer lines into `references/dispatch-runbook.md` carrying different
topics.
What the one-word rendering keeps, and what it delegates to lines the
ruling left standing: 「同区域…硬串行」 IS the ruling's narrowing (its facet ①:
one line narrower, a special case removed). The 「同文件不同区域是普通并发,后落地方解冲突」
clause is exactly what :437 already states for every non-single-writer
path (「共享其它路径是普通并发,后落地方解冲突」): once :441 no longer claims the whole file,
the same file in different regions is one of those other paths by
elimination, and the two lines contradict on no path. The parenthetical
definition of 区域 is carried by :449 (「认领申报文件面到区域级,拿不准就串行」, the escape
hatch the ruling names as staying), by :278 (「区域写不清就只能整文件串行」) and by
`references/seat-post-protocol.md` :20 (every serial-queue entry is
「每张卡认领的区域」).
The alternative the seat may prefer at review: land the ruling's
sentence as R3 (120 B, two lines) and raise the SKILL.md ceiling 813 →
814 under the ratchet's own maintainer exit (「Raising a ceiling requires
a maintainer ruling quoted in the PR」). The precedent is the last
landing on this file, e872ef4 (PR #19033, 2026-09-19): 812 → 813 for one
ruled line, with the ratchet comment 「Ruled content is not growth」. That
route is a `scripts/pm/check-skill-line-ratchet.mjs` edit and a net +1,
both outside this dispatch's constraints, so it is stated here and not
taken.
## Tier and landing
- `node scripts/pm/check-governed-merges.mjs --test` with both paths:
exit 3, GOVERNED — Tier S (席内达档复核落地), `.claude/**` ×2; size NOT MEASURED
by `--test` (dispatch-gates' derived count: 4 changed lines, +2 / −2,
under 5000).
- `node scripts/pm/dispatch-gates.mjs --tier` on both paths: MANDATORY
at CONTRACT_REVIEW_TIER (clause ①: the PM dispatch skill MAIN file).
- This PR stays DRAFT; it lands on the owning seat's `## Contract
review` record for head `5676515` (AGENTS.md Prime Directive #14).
Label: `skip-changeset` (`.claude/**` publishes nothing); no changeset
file.
## Gates — derived union on head `5676515`, each exit captured before
any pipe
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` from the worktree with no paths (changeset 2
committed / 0 working tree / 0 untracked vs merge base `801415a`)
derived 20 commands, identical to the dispatch-time lead; `--ran`
reconciles 20 derived / 20 run / 0 UNRUN. Two extras were run because
the derivation flags them: `check:pm-settings-deny-roster` (a roster
under `.claude`, marked silence-is-not-evidence) and
`check:skill-frame-freshness` (pins the four-axis block).
| Command | Exit |
|---|---|
| pnpm check:pm-skill-ratchet | 0 |
| pnpm check:pm-skill-id-lint | 0 (27 files clean) |
| pnpm check:pm-governed-prose | 0 |
| pnpm check:skill-frame-sync | 0 |
| pnpm check:skill-frame-freshness | 0 (current with origin/main) |
| pnpm check:pm-governed-merges | 0 |
| pnpm check:pm-expected-skips | 0 |
| pnpm check:pm-half-states | 0 |
| pnpm check:doc-authoring | 0 |
| pnpm check:nul-bytes | 0 (9034 text files, no raw control bytes) |
| pnpm check:agent-test-spelling | 0 |
| pnpm check:cross-package-test-inputs | 0 |
| pnpm check:driver-memory-census | 0 |
| pnpm check:refd-timer-probe | 0 |
| pnpm check:watch-hint-literal | 0 |
| pnpm check:pm-settings-deny-roster | 0 |
| pnpm --filter @objectstack/lint run check:doc-formula-expressions | 3
then 0 — the first run was PREREQUISITE NOT MET (`@objectstack/formula`
and `@objectstack/lint` not built; the gate says nothing was measured);
after `pnpm exec turbo run build --filter=@objectstack/formula
--filter=@objectstack/lint` under the verify lock (4/4 cached), the
rerun is exit 0: 58 self-test cases, 22 / 9 / 14 examples judged clean |
| node scripts/check-closing-keyword-parity.mjs | 0 |
| node scripts/check-closing-keyword-parity.mjs --self-test | 0 |
| node scripts/check-comment-mask-corpus.mjs | 0 (6920 files, 0
disagree) |
| node scripts/pm/check-governed-queue-guard.mjs --self-test | 0 |
| node scripts/pm/check-harness-current.mjs --self-test | 0 |
| node scripts/pm/check-governed-merges.mjs --test (both paths) | 3 =
GOVERNED, Tier S (the expected code) |
The last commit is `5676515` and every command above ran after it.
`origin/main` moved by one commit since the base (`e3b3cdd`,
metadata-protocol) that touches neither edited file nor the ratchet, so
no merge is owed before review.
## Acceptance notes
- noted, not filed: SKILL.md :120 (the `priority:p0` table row 「⛔
不豁免同文件串行、深度等待与认领协议」), its core-rules twin :36, and
`references/lanes/services.md` :26 (「同文件卡跨轮硬串行」, a lane-specific
stricter rule) still name the serial discipline by FILE. The ruling
scoped :441 and :105 only; these are name references to the discipline,
not a second definition, so they are a naming nit rather than a defect
class. 承接者: the domain:skills seat's next SKILL.md card.
- noted, not filed: `check-closing-keyword-parity` prints an
informational line that
`packages/spec/api-surface-declarations/system.txt` (3,568,357 bytes)
exceeds its 2 MiB cutoff for unregistered files; exit 0 and pre-existing
on `origin/main`. 承接者: none identified.
- The two neighbouring lines the ruling names as staying were read and
left alone: :437 (unchanged by the ruling) and :449 (「拿不准就串行」).
## 维护者速读(草稿)
### 改了什么
派发协议「候选与批次」一节里的一条并发规则改了一个词:原来写「同文件单跨轮硬串行」,现在写「同区域单跨轮硬串行」;核心条款摘要里的同一条规则同步改成「同区域硬串行」。两处各改一个词、各不增减行数;`:437`(single-writer
路径只由 `SINGLE_CLAIM_PATHS` 枚举,其它路径普通并发)原样不动。
### 为什么改
同一节里原有两条互相打架的规则:一条说除 `.objectui-sha`
之外的所有共享文件都是普通并发、后落地的一方解冲突;四行之后另一条说同一文件的卡跨轮必须硬串行。`SINGLE_CLAIM_PATHS`
只有一条,所以对仓里的每一个文件两条规则都给出相反指令;各席位各自选了一条执行,一张停在决策箱里的 PR(25 个 spec 文件)就把
spec
车道大半冻住。裁决(甲)把「硬串行」收窄到「认领申报的文件面重叠的区域」:同文件不同区域是普通并发,后落地方解冲突。改动后,同文件异区域自然落到
`:437` 的「其它路径普通并发」,两条规则在任何路径上都不再冲突。
### 风险与代价(含回滚)
风险:裁决原句(「同区域(认领申报的文件面重叠)单跨轮硬串行;同文件不同区域是普通并发,后落地方解冲突。」)本身 123 字节,超过本文件
120 字节的行宽门禁;加上裁决要求保留的「延后不是搁置…」半句共 198 字节;文件又顶在 813
行的棘轮上限、余量为零,所以裁决原句无法原样落地(门禁实测:一行写法红,两行写法也红)。本 PR
采用最小改法(一个词),把「同文件异区域普通并发」这半句交给紧邻的 `:437` 承担,把「区域」的定义交给 `:449`
与串行队条款承担。若席位认为裁决原句必须逐字落地,替代路线是按棘轮自己的维护者例外把上限抬到 814(先例:2026-09-19 的
e872ef4),那需要改脚本、净增一行,不在本单授权内。回滚:两个文件各回退一个词,零副作用。
### 席位意见
(留空,席位定稿)
### 你要做的
无需你操作:这是 Tier S 受管面,由 skills 席位做契约档复核后经队列落地。只有一处可能需要你一句话:若你希望裁决原句逐字进入
SKILL.md(而不是本 PR 的一词改法),请回「抬上限」,席位据此改走 813 → 814 的路线。
---
_Generated by [Claude
Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 482d584 commit 547b9ab
2 files changed
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
438 | 438 | | |
439 | 439 | | |
440 | 440 | | |
441 | | - | |
| 441 | + | |
442 | 442 | | |
443 | 443 | | |
444 | 444 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
105 | | - | |
| 105 | + | |
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
| |||
0 commit comments