Repository navigation
Commit a81a9d6
Fixes #18119
**Governed rules layer** — `.claude/skills/pm-dispatch/SKILL.md` +
`AGENTS.md` + `.claude/skills/checklist-test/SKILL.md`. This PR opens as
DRAFT and draft is its finished state: it waits for an authorized
APPROVED review by an account in `GOVERNED_APPROVERS`, after which the
claiming seat lands it (Prime Directive 14; ruling C, maintainer
verbatim, untranslated: 「C. approve 后不管后续改动都由席位落地:」, recorded on
#17971). Never ready, never queued, never auto-merge, and no seat
approves it under any account.
Base `origin/main` `fffe3e5e7f` (fetched 2026-09-14T11:14Z); this branch
`claude/issue-18119-rules-layer-four-lines` at `6dc9ac3e52`, one commit,
three files, net 0 lines in each (`git diff --numstat`: 1/1 · 3/3 ·
3/3).
## What changed — seven equal-line edits, no other line moves
Every rewritten line stays within the enforced 120-byte cap
(`MAX_LINE_BYTES = 120` in `scripts/pm/check-skill-line-ratchet.mjs`);
byte widths after each row.
| File | Line | Before | After |
|---|---|---|---|
| pm-dispatch `SKILL.md` | 378 | ``- ⛔ `issue_write`
会替换标签集并清空未传字段:写入时必须回传 `assignees`。`` (96 B) | ``- 标签/assignee 写恒经
`scripts/pm/label-write.mjs`(四步、回读);⛔ 永不 MCP `issue_write`(锁 1 已拒)。``
(119 B) |
| pm-dispatch `SKILL.md` | 615 | `- PR 上的标签 =
待维护者审阅,不入六态;与请审同为等人合清单,随合并或撤回判决离开。` (116 B) | `- PR 上的标签 =
待维护者审阅,不入六态;与请审同为等人批清单,随获批或撤回判决离开。` (116 B) |
| pm-dispatch `SKILL.md` | 626 | `- 规则层四件套等人合;事实层 PR(受管路径全在该目录)经席内达档复核后
ready → 入队。` (115 B) | `- 规则层四件套等人批;事实层 PR(受管路径全在该目录)经席内达档复核后 ready →
入队。` (115 B) |
| `AGENTS.md` (PD 14) | 273 | `uncertified recompute, drift or a
hand-authored sibling keeps it governed. Unapproved, the bypass direct
merge` (114 B) | `uncertified recompute, drift or a hand-authored
sibling keeps it governed. Unapproved, no seat lands it: the` (112 B) |
| `AGENTS.md` (PD 14) | 274 | `(人工直合) is the only landing. **Landing is
tiered**: a PR whose governed paths all lie under` (102 B) | `ending is
that approval, then the owning seat. **Landing is tiered**: a PR whose
governed paths all lie under` (113 B) |
| `AGENTS.md` (PD 14) | 284 | `human merge IS the review record, ⛔ not a
relaxation. Behind it: the queue guard refuses an unpinned governed`
(115 B) | `spent approval IS the review record, ⛔ not a relaxation.
Behind it: the queue guard refuses an unpinned governed` (118 B) |
| checklist-test `SKILL.md` | 123 | ``用 `issue_write`(github MCP)立单:``
(36 B) | ``经 REST 代理 `POST .../issues` 立单(`Content-Type:
application/json`;⛔ 永不 MCP `issue_write`,锁 1 已拒):`` (117 B) |
Notes on the wording, each taken from the facts layer rather than
invented:
- :378 uses `rest-channel.md` :38–:39's words
(`scripts/pm/label-write.mjs`, 四步、回读, ⛔ 永不 MCP `issue_write`, 锁 1 已拒);
the full four-step rule already lives at SKILL.md :148, so the
parenthetical is a pointer, not a restatement.
- :615 — 等人合清单 → 等人批清单; the exit clause 随合并…离开 → 随获批…离开 keeps the same
semantics in the ruling-C mechanism: :617 has the seat clear the label
(清标) as the first landing step, on the approval, so the label leaves on
approval or on a withdrawn verdict, not on the merge.
- :626 — 等人合 → 等人批, the operative token of `landing-operations.md` :28
(「四件套留 draft 等人批,⛔ 不翻正式不入队;获授权批准后认领席落地」). The 获授权批准后认领席落地 half already
stands at SKILL.md :616–:617 (「席位落地 = 过落地前检、清标、ready、auto-merge」), and
no spelling that carries both halves fits the 120-byte cap with the 事实层
half unchanged (the shortest measured 131 B), so the line carries the
token and :617 carries the mechanism.
- AGENTS.md :273–:274 — the 人工直合 ending becomes the ending `lanes/ui.md`
:25 states (「⛔ 未获授权批准不 ready 不入队不自合、永不批准,获批后认领席落地」): unapproved, no seat
lands it; the ending is that approval (the authorized APPROVED review by
a `GOVERNED_APPROVERS` account named four lines above), then the owning
seat. The sentence says nothing about what the maintainer may do by
hand, so it does not contradict the queue guard's own refusal text (see
Consistency, item 5).
- AGENTS.md :284 — "a human merge IS the review record" is the phrase
the queue guard's self-test asserts ABSENT from its refusal text
(`check-governed-queue-guard.mjs` :2436, "never … calls that merge the
record"); under ruling C the maintainer's word is spent once, as the
approval, so "a spent approval IS the review record" — same sentence,
same line count.
- checklist-test :123 — the REST channel in `rest-channel.md`'s own
spelling (`POST .../issues`, request body as JSON). The field list that
follows (标题 · 标签 · 正文, :125–:150) is already the shape of a REST issue
body — title, labels, body — so no line below :123 needed to move.
## Premise readings (all against `origin/main` `fffe3e5e7f`)
- **P1 content** (2026-09-14T11:16Z) — all five anchors matched by
content at the named numbers: SKILL.md :378, :615, :626; AGENTS.md :274
(「(人工直合) is the only landing.」 inside PD 14); checklist-test :123. A
sixth line of the same shape sits at SKILL.md :610 (not named by the
card; see Consistency item 1).
- **P2 ratchets** (2026-09-14T11:16Z) — `pnpm check:pm-skill-ratchet`
exit 0 on the tip: SKILL.md 812/812 (widest row 342/342), AGENTS.md
1075/1075 (widest row 768/768), checklist-test 234/238 (widest row
221/221), core-rules 151/151. Frame block :733–:754 md5
`3327d02c56f8a0eca88569dad2270f32` before and after — identical.
- **P3 core-rules.md** — the target grep `issue_write|等人合|人工直合` reads 1
hit, NOT 0: :128 「…代裁清单、等人合项、受管合并审计与五指标。」 — the round-report rule, which
mirrors SKILL.md :672 (「awaiting a human merge 项」), not any of the four
lines. The control `grep -c 'label-write\|四件套'` reads 0 in that file as
well (neither control word is in core-rules today; stated as read). Per
the dispatch's branch, core-rules.md is untouched; the mirrored pair is
listed under Consistency item 2.
- **P4 facts layer** — quoted verbatim: `rest-channel.md` :37 「✓ 标签加法
`POST .../issues/{n}/labels`,定向删 `DELETE
.../issues/{n}/labels/{name}`;加法优先。」 :38 「标签/assignee 写恒经
`scripts/pm/label-write.mjs`:四步内建、回读、回退整组 PATCH 回传 assignees。」 :39 「⛔ 永不
MCP `issue_write`(锁 1 已拒);会话分类器拒改动 ⇒ 无通道,交有通道席位立卡。」; `lanes/ui.md` :25
「⇒ 命中即停 draft;⛔ 未获授权批准不 ready 不入队不自合、永不批准,获批后认领席落地。」;
`landing-operations.md` :27 「受管路径全在本技能 `references/`
者事实层:席内达档复核过落地前检三条即转正式入队。」 :28 「其余为规则层:四件套留 draft 等人批,⛔
不翻正式不入队;获授权批准后认领席落地。」 :29 「⛔ 两层不由席位批准;清标即落地同受此闸,漏判会被队列守卫在 merge group
里拒收。」
- **P5 serial** (2026-09-14T11:16Z) — `GET /pulls?state=open` returns
exactly the six the dispatch named (18176, 18175, 18173, 18131, 18096,
17076); each `/files` list read via REST; zero hits on the three files.
- **P6 lock 1** — `permissions.deny` on the tip carries **14** entries,
not 15, with `mcp__github__issue_write` first among them; the same 14 at
lock 1's own commit `7ef05f997`. The 15 was a miscount; the substance
(the tool is denied) holds.
## Consistency — sentences of the same retired shape this PR does NOT
move (the card's fence: no other line)
1. pm-dispatch `SKILL.md` :610 「② PR 留给维护者看得见地悬着;终局两条:人工直合即审核记录;授权批准 ⇒
席位落地。」 — still two endings, with the human direct merge as the review
record (the exact phrase retired at AGENTS.md :284 here and in the queue
guard). Not named by the card; left as is. An equal-line candidate
within the cap, for the seat to accept or reject: 「- ② PR
留给维护者看得见地悬着;终局一条:授权批准即审核记录 ⇒ 席位落地。」
2. pm-dispatch `SKILL.md` :622 「④ 轮次报告单列 awaiting a human merge。」 and
:672 「…awaiting a human merge 项…」 with its core-rules mirror :128 「等人合项」
— the round-report item still named after the human merge; per 〈优先级〉 :44
the :672 ↔ :128 pair moves together, in one PR.
3. `AGENTS.md` :255 (the PD 14 headline) — "confirmed and merged by the
maintainer, by hand — or confirmed by an authorized approval and then
landed by the owning seat" still names the hand merge as ending one. NOT
changed on purpose: `scripts/pm/check-governed-prose.mjs` :148 anchors
its AGENTS.md region on that exact sentence (`start: 'A governed surface
is confirmed and merged by the maintainer, by hand'`), so the sentence
and the anchor must move in the same PR — outside this card.
4. `AGENTS.md` :799 (Skills section) — "human-merge only, or queued
under Prime Directive #14's pinned-approval path" — outside PD 14,
outside the card.
5. The mechanism layer still names 人工直合 for the unapproved case:
`scripts/pm/check-governed-queue-guard.mjs` :1197 and :1273 print
"Unapproved, the maintainer's own direct merge (人工直合) is the only
landing this pull request has", and its self-test :2441 pins that word
present; `landing-operations.md` :49 keeps 人工直合 as the main-red one-line
exception; `lanes/director.md` :44 says 「等人合清单」. The :274 wording chosen
here is compatible with all of them (it constrains seats, not the
maintainer).
6. Script header comments still carrying the phrase:
`scripts/pm/check-governed-merges.mjs` :140 and
`scripts/check-required-contexts.mjs` :288 ("human merge IS the review
record") — comments, not rules.
## Gates (foreground, exit captured before any pipe, all on
`6dc9ac3e52`)
Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (18 families; the seat's derivation named
the same set). Each ran with stdout and stderr redirected into its own
log file and the exit status captured immediately after, before any
pipe:
| # | Family | Exit | Verdict line |
|---|---|---|---|
| 1 | `node scripts/check-closing-keyword-parity.mjs` | 0 | OK (3
parsers agree on all 9 keywords…) |
| 2 | `… --self-test` | 0 | 30 assertions, 5 mutations each driven to
red |
| 3 | `node scripts/check-comment-mask-corpus.mjs` | 0 | 6752 files, 0
disagree, 0 unparseable |
| 4 | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 |
238 cases pass |
| 5 | `pnpm --filter @objectstack/lint run
check:doc-formula-expressions` | 3 → 0 | first run PREREQUISITE NOT MET
(not a verdict: `@objectstack/formula`, `@objectstack/lint` unbuilt);
built under `scripts/pm/os-verify-lock.sh` (`VERDICT command-exit 0 ·
held the lock 5s · waited 0s`), re-run exit 0: 58 self-test cases, 22
record-scoped examples / 438 files clean |
| 6 | `pnpm check:agent-test-spelling` | 0 | 0 violations — 508 files |
| 7 | `pnpm check:doc-authoring` | 0 | 15340 strings across 978 spec
sources clean |
| 8 | `pnpm check:docs-audit-scope` | 0 | 14 release-owned pages
review-only; scope injection live |
| 9 | `pnpm check:driver-memory-census` | 0 | every declaration ledgered
|
| 10 | `pnpm check:nul-bytes` | 0 | scanned 8655 text files, no raw
ASCII control bytes |
| 11 | `pnpm check:pm-governed-merges` | 0 | 328 assertions; the real
generator declared 9 outputs and certified this tree |
| 12 | `pnpm check:pm-governed-prose` | 0 | 2 instruction surfaces name
all 5 registered governed surfaces and claim no others |
| 13 | `pnpm check:pm-skill-id-lint` | 0 | 27 files clean |
| 14 | `pnpm check:pm-skill-ratchet` | 0 | SKILL.md 812/812 (342/342) ·
AGENTS.md 1075/1075 (768/768) · checklist-test 234/238 (221/221) ·
core-rules 151/151 |
| 15 | `pnpm check:refd-timer-probe` | 0 | 6747 files swept |
| 16 | `pnpm check:required-contexts` | 0 | 7 required contexts pinned;
6 instruction surfaces scanned against 2 retired names |
| 17 | `pnpm check:skill-frame-sync` | 0 | the one declared copy is
internally coherent; 74 markdown files scanned for undeclared copies |
| 18 | `pnpm check:watch-hint-literal` | 0 | 70 declarations across 4
rostered names |
Reconciliation (`--ran`, exit codes recorded per command): `Run
reconciliation — 18 derived, 18 run, 0 NOT-MEASURED, 0 UNRUN.` … `✓
dispatch-gates --ran: 18 derived famil(ies) accounted for — 18 run, 0
NOT-MEASURED (a DERIVED zero — all 18 recorded an exit code and none of
them is 3).` Also outside the derivation: the pre-push hook
`check:commit-card-trailers` on the push (1 commit, no card relation, no
model identifier in the trailer pair); the control-byte self-scan `grep
-naP` over the three files reads none.
Changeset: none owed. The three paths are `.claude/**` and `AGENTS.md` —
nothing any package's `files[]` ships. The `changeset-check` job in
`pr-automation.yml` has two exemptions (the `skip-changeset` label and
the release PR) and no path exemption, so the label is applied through
the additive endpoint `POST /issues/{n}/labels` right after this PR
opens and read back; the read-back is recorded in the os-dev-report
comment on the card (this body is not re-sent).
## 维护者速读(草稿)
- 改了什么:四行规则文本(加同段两句)追上已落地的锁 1、两级落地与裁决 C —— `issue_write`
已被拒、规则层等的是批准而不是人合、批准后由认领席落地。
- 为什么改:规则层与它自己的 references 说法相反,会把席位训练回已退役的机制;文档以实际实现为准。
- 风险与代价(含回滚):零机制变化,纯文案,等行数;回滚即 revert 本 PR。
- 席位意见:(留空)
- 你要做的:一次授权批准(os-zhuang / hotlong 任一账号 APPROVE);之后由认领席落地,不需要你再点合并。
## Acceptance notes
- noted, not filed: Consistency items 1–6 above — same retired-shape
residue in lines the card's fence excludes (SKILL.md :610/:622/:672,
core-rules :128, AGENTS.md :255/:799, the guard's refusal text and two
script comments). 承接者: the `domain:skills` seat (owner of SKILL.md,
`references/**` and `scripts/pm/**`); items 3 and 5 need a gate/anchor
edit in the same PR as the prose.
- noted, not filed: the dispatch's P6 count (15) versus the measured 14
— a miscount in the dispatch text, no file to fix. 承接者: 无.
- Deviation, declared: the dispatch asked for a three-line 速读;
`.claude/agents/os-dev.md` fixes five segments, and that file wins on
conflict — five compact bullets above.
- No footer block was sent with this body (the platform appends one on
create per `platform-readings.md` :338); the body was read back after
creation.
Clause-②: no
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_
Co-authored-by: Claude <noreply@anthropic.com>
1 parent ba9b498 commit a81a9d6
3 files changed
Lines changed: 7 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
120 | 120 | | |
121 | 121 | | |
122 | 122 | | |
123 | | - | |
| 123 | + | |
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
375 | 375 | | |
376 | 376 | | |
377 | 377 | | |
378 | | - | |
| 378 | + | |
379 | 379 | | |
380 | 380 | | |
381 | 381 | | |
| |||
612 | 612 | | |
613 | 613 | | |
614 | 614 | | |
615 | | - | |
| 615 | + | |
616 | 616 | | |
617 | 617 | | |
618 | 618 | | |
| |||
623 | 623 | | |
624 | 624 | | |
625 | 625 | | |
626 | | - | |
| 626 | + | |
627 | 627 | | |
628 | 628 | | |
629 | 629 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
270 | 270 | | |
271 | 271 | | |
272 | 272 | | |
273 | | - | |
274 | | - | |
| 273 | + | |
| 274 | + | |
275 | 275 | | |
276 | 276 | | |
277 | 277 | | |
| |||
281 | 281 | | |
282 | 282 | | |
283 | 283 | | |
284 | | - | |
| 284 | + | |
285 | 285 | | |
286 | 286 | | |
287 | 287 | | |
| |||
0 commit comments