Repository navigation
Commit aea3443
skills(os-dev, pm-dispatch): every PR opens with a six-line 维护者速读; the seat's 席位核对 precedes pr_ready/enqueue; H69 patrols a summons that ran ahead of it (#26327)
Fixes #26155
Clause-②: no
Metadata-protocol: none
## 维护者速读
改了什么:每个 PR
正文现在都以这块六行速读开头(受管与否都带),其后英文节序固定、门禁日志折进可展开块;席位在你被请审之前先把自己的核对贴到当前
head;巡查多一行报告态 H69,点名「已请审、席位核对却没跟上 head」的 Tier H PR。
为什么改:你的原话「看一下现在的pr写的内容,我总感觉对我审核的人帮助不大,是否需要更新skills」→「立卡」;立卡实测 35 个 open
PR 首节名不统一、中文只在 6 个受管草稿里、其中 4 个没有席位终稿。
风险与回滚:只改两份规则文本与一行报告态巡查,不改任何门禁判定、不动复核清单;出错时你看到的是 PR 正文形状不对或 H69
多报一行,不阻塞任何落地。回滚 = revert 本 PR 的一个 commit。
先看:`.claude/agents/os-dev.md`(新五行是模板本体;退掉的三行去向见 Acceptance notes)→
`.claude/skills/pm-dispatch/SKILL.md`(① 行:席位核对先于 `pr_ready`/入队)→
`scripts/pm/check-half-states.mjs`(风险 hunk = `h69SeatRecordBehindHead` 里
head 日期与记录时间的比较)。
两分钟验证:`node scripts/pm/check-half-states.mjs --self-test`,预期末行含 `H69
seat record before governed review 66/40`;`pnpm
check:pm-skill-ratchet`,预期 `os-dev.md is 404 lines (ceiling 404;
headroom 0)`。
需要你做的:确认或改这六个标签——这块就是模板本体,它的形状在本 PR 上由你定;落地由席位走 Tier S 契约复核,不需要你点合并。
## What changes
**`.claude/agents/os-dev.md` — 404 → 404 lines (ceiling 404).** Lines
288–289 (the governed-only `## 维护者速读(草稿)` with 五段 including 席位意见) become
five rule lines, now 285–289: the block on every PR right after the two
declaration lines; the six labels verbatim and in order; the `先看` and
`两分钟验证` sub-rules; `需要你做的` = exactly one action, `无,席位落地` on a
non-governed PR; and the fixed English section order (What changes /
Tests / Acceptance notes / Verification) with every log reading folded
into a details/summary block. Three lines retired to pay for them, each
to a home it already had:
- old 273 (push with `-u`, back off on network failure, pre-push refuses
card trailers) → rule 1 lines 30 and 32, and base line 285 (now 282: no
card trailer on a commit);
- old 275 (after the PR opens, merge `main` only on a conflict, a
main-red or a dequeue, then the scoped re-check) → AGENTS.md Multi-agent
discipline §10, which states it verbatim;
- old 284 (the three safe spellings beside a card number: `is not
addressed here`, `out of scope:`, `remains open`) → the keyword rule
directly above it (base 282–283, now 280–281, 「让它们远离其它卡号」) and
review-checklist.md:10 安全拼法 (卡号旁零动词).
**`.claude/skills/pm-dispatch/SKILL.md` — 319 → 319 lines (ceiling 319);
four lines rewritten in place, no new line.** ① (188): the seat's record
is on the PR before `pr_ready` (Tier H) and before enqueue (Tier S),
pinned to the head — the single home of the Wanted-2 precondition;
`两层同欠` is carried by naming both triggers, `卡只留指针行` by
execution-duties.md:184 and the pointer spelling on 190. 192: the six
labels. 193: the dev's block on every PR, no 席位意见 line. 194: the seat
corrects the six lines and adds the 席位意见 line.
**`scripts/pm/check-half-states.mjs` — H69, report-only (35,243 → 35,593
lines).** Population = H48's (governed, Tier H, open, drafts in)
narrowed to a pending request from a `GOVERNED_APPROVERS` account; it
fires when no comment whose line begins `## 席位核对` is newer than the
head's committer date. It reuses the thread H48 buys and adds ONE commit
read per PR that carries a record at all — a PR with no record is judged
without that read, an unread head date is UNJUDGED, never clean. A
sibling of H43, not a widening: H43 asks who was asked, H69 whether the
record preceded the asking, and the two remedies differ. Coverage pair
`seatRecordCandidates`/`seatRecordJudged`, summary clause `Seat records
(H69)`, band `state`, a 66-case battery pinned at 40. H48's hint text
and fixture follow the renamed dev heading: the body section is now `##
维护者速读`, the same heading as the comment marker, H48 still reads comments
only, and a new case proves the fixture carries that heading so the pin
is not vacuous.
**Not touched.** `references/review-checklist.md` (card ⛔ 3).
`references/landing-operations.md`: its Tier S enqueue line — the
order's candidate home — no longer exists on `origin/main` (#26210
retired it), and the surviving line 60 sits at 115 bytes with no room
for a fold, so the precondition has one home. No open PR body was
rewritten. AGENTS.md untouched.
## Tests
- `node scripts/pm/check-half-states.mjs --self-test` on `b04d9371`:
exit 0 — `✓ check-half-states self-test: 5030 cases pass. Batteries: …
H69 seat record before governed review 66/40`. The pair the card pins is
`H69: approver requested, record OLDER than the head -> finding` and
`H69: approver requested, record NEWER than the head -> clean`, with the
controls beside them: no record needs no head read; an unread head date
is UNJUDGED; a non-approver or assign-only request does not fire; Tier S
stands down; a new push after a fresh record re-opens the state; H43/H48
adjacency.
- No ablation: the diff changes rule text and a patrol script, not a
tested runtime behaviour (os-dev.md: 配置、脚本、workflow、文档 ⛔ 不消融).
## Acceptance notes
- **Premise — relay request timing (measured; it shapes the wording).**
`fleet-write/execute.mjs` requests `GOVERNED_APPROVERS` at `pr_create`
AND at `pr_ready` on a Tier H hit (its battery name at execute.mjs:1046;
AGENTS.md Prime Directive 14 calls the draft-time request a summons). So
the precondition cannot bind the create-time request; SKILL.md ① binds
`pr_ready` and enqueue, and H69 reads the pending request as the summons
it is — a fresh Tier H draft fires until the seat's record lands on its
head, which is the measured shape (4 of 6 governed drafts on the filing
day).
- **Premise — the details/summary fold (unmeasured until this PR).** 0
of 28 open and 0 of 100 recently closed PR bodies carried a details tag
(REST `GET /pulls`, read 2026-10-26T20:25Z); platform-readings.md
records the write-side sanitizer deleting unknown tag shapes and says
nothing about this element. This PR's own `## Verification` is the
measurement: if the folds below render, the rule line stands; if they
were stripped, the seat has the reading and the fold needs a different
spelling.
- **Ruling A on #25919 (comment 6386217274) answers 404** — NOT
MEASURED, evidence destroyed. The card's quotation of it (「规范核心与事故史分家」)
and the surviving ruling 6407900763 on that card point the same way, and
nothing here depends on it.
- **Recognisers re-grepped before and after** (`速读|五段|席位意见|Acceptance
notes|维护者速读|席位核对` over `.claude/**` and `scripts/pm/*.mjs`): none is
keyed on `(草稿)` or `五段`. `MAINTAINER_BRIEF_MARKER` (H48) reads comments
only and is unchanged; `fleet-roster.mjs` reads `## 席位核对` plus ACCEPT,
unchanged; `check-governed-merges.mjs`, `check-governed-queue-guard.mjs`
and `dispatch-gates.mjs` say "a final 维护者速读" in prose, still true;
`post-stamped.mjs`'s `席位意见` opener belongs to the decision-analysis
frame, unrelated; `references/decision-analysis.md:13` keeps its
one-line governed-draft summary — the seat's decision-box line, not the
PR brief.
- **Tier.** The only governed paths are `.claude/**` → Tier S: this PR
stays draft; the seat's independent `CONTRACT_REVIEW_TIER` review and
the queue are the landing. The dev did not ready, arm or enqueue it.
`skip-changeset` rides `pr_create`'s labels: `.claude/**` and
`scripts/pm/**` publish nothing.
- **Out of scope, not filed:** none. The `os-dev.md:292` token-count
clause (「姊妹门禁定义 token 计数后同报 token」) names a gate that does not exist;
noted as a candidate for the next compression, not retired here.
## Verification
<details><summary>Required gates — all green on b04d937, exit codes
captured before any pipe</summary>
| command | exit | verdict line |
|:--|:--|:--|
| `node scripts/pm/check-half-states.mjs --self-test` | 0 | `✓
check-half-states self-test: 5030 cases pass. Batteries: … H69 seat
record before governed review 66/40.` |
| `pnpm check:pm-skill-ratchet` | 0 | `✓ check-skill-line-ratchet:
.claude/agents/os-dev.md is 404 lines (ceiling 404; headroom 0).` ·
`.claude/skills/pm-dispatch/SKILL.md is 319 lines (ceiling 319; headroom
0).` |
| `pnpm check:pm-skill-id-lint` | 0 | `✓ check-skill-id-lint: 104
file(s) clean (pattern /#[0-9]{3,}/g).` |
| `pnpm check:skill-frame-sync` | 0 | `✓ check-skill-frame-sync: the one
declared copy of the decision frame is internally coherent` |
| `pnpm check:skill-frame-freshness` | 0 | `✓
check-skill-frame-freshness: the decision frame in this tree is current
with origin/main (fetched just now).` |
</details>
<details><summary>Derived families — `dispatch-gates --commands --repo
objectstack-ai/objectstack` on b04d937: 52 commands, 51 exit 0 on the
first pass, the one exit 3 reran green after a build</summary>
Derivation header: `gate list derived from the tree of
'objectstack-ai/objectstack' at commit b04d937`. Runner: each command
via `bash -c`, exit code captured before any pipe.
| command | exit | wall |
|:--|:--|:--|
| `node scripts/check-ci-filter-parity.mjs` | 0 | 0s |
| `node scripts/check-closing-keyword-parity.mjs` | 0 | 3s |
| `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | 5s |
| `node scripts/check-comment-mask-corpus.mjs` | 0 | 185s |
| `node scripts/check-declaration-mirrors.mjs` | 0 | 0s |
| `node scripts/check-declaration-mirrors.mjs --self-test` | 0 | 0s |
| `node scripts/check-issue-citations.mjs` | 0 | 1s |
| `node scripts/check-scripts-symbol-anchors.mjs` | 0 | 4s |
| `node scripts/check-scripts-symbol-anchors.mjs --self-test` | 0 | 4s |
| `node scripts/check-self-test-wired.mjs` | 0 | 2s |
| `node scripts/check-self-test-wired.mjs --self-test` | 0 | 5s |
| `node scripts/check-self-test-workflow-commands.mjs` | 0 | 121s |
| `node scripts/check-self-test-workflow-commands.mjs --self-test` | 0 |
4s |
| `node scripts/check-whole-set-label-write.mjs` | 0 | 2s |
| `node scripts/check-whole-set-label-write.mjs --self-test` | 0 | 0s |
| `node scripts/ci/scheduled-full-run.mjs --self-test` | 0 | 1s |
| `node scripts/pm/bare-root-worklist.mjs --self-test` | 0 | 32s |
| `node scripts/pm/board-snapshot.mjs --self-test` | 0 | 0s |
| `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | 0s
|
| `node scripts/pm/check-harness-current.mjs --self-test` | 0 | 8s |
| `node scripts/pm/sweep-closed-cards.mjs --self-test` | 0 | 0s |
| `pnpm --filter @objectstack/lint run check:doc-formula-expressions` |
3 | 2s |
| `pnpm check:agent-model-declared` | 0 | 1s |
| `pnpm check:agent-test-spelling` | 0 | 3s |
| `pnpm check:bash32-floor` | 0 | 2s |
| `pnpm check:cli-command-ids` | 0 | 18s |
| `pnpm check:closing-target-claim` | 0 | 1s |
| `pnpm check:commit-card-trailers` | 0 | 1s |
| `pnpm check:cross-package-test-inputs` | 0 | 35s |
| `pnpm check:doc-authoring` | 0 | 7s |
| `pnpm check:driver-memory-census` | 0 | 5s |
| `pnpm check:entry-guard` | 0 | 40s |
| `pnpm check:gitlink-declared` | 0 | 2s |
| `pnpm check:issue-citations` | 0 | 7s |
| `pnpm check:nul-bytes` | 0 | 5s |
| `pnpm check:parse-guard` | 0 | 3s |
| `pnpm check:partof-closing-keyword` | 0 | 1s |
| `pnpm check:pm-dispatch-gates` | 0 | 413s |
| `pnpm check:pm-expected-skips` | 0 | 6s |
| `pnpm check:pm-governed-merges` | 0 | 10s |
| `pnpm check:pm-governed-prose` | 0 | 1s |
| `pnpm check:pm-half-states` | 0 | 3s |
| `pnpm check:pm-post-stamped` | 0 | 1s |
| `pnpm check:pm-skill-id-lint` | 0 | 1s |
| `pnpm check:pm-skill-ratchet` | 0 | 1s |
| `pnpm check:pnpm-filter-targets` | 0 | 3s |
| `pnpm check:pnpm-flag-spellings` | 0 | 5s |
| `pnpm check:ratchet-remedy-authority` | 0 | 4s |
| `pnpm check:refd-timer-probe` | 0 | 24s |
| `pnpm check:single-claim-paths` | 0 | 1s |
| `pnpm check:skill-frame-sync` | 0 | 1s |
| `pnpm check:watch-hint-literal` | 0 | 6s |
`pnpm --filter @objectstack/lint run check:doc-formula-expressions` exit
3 on the first pass = the gate's own PREREQUISITE refusal
(`@objectstack/formula` and `@objectstack/lint` unbuilt; "Nothing was
measured"). Rerun after `pnpm exec turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint` under the
verify lock: exit 0.
`--ran` reconciliation: ✓ dispatch-gates --ran: 52 derived famil(ies)
accounted for — 52 run, 0 NOT-MEASURED (a DERIVED zero — all 52 recorded
an exit code and none of them is 3).
The derivation before the runs was clean; the `--ran` reconciliation run
printed a STALE TREE warning: the branch base is `f00cbe36` and
`origin/main` had moved 5 commits by then; the two files the tool names
as stale are the `scripts/sdui-manifest.sources/core.json` and
`react.json` hash sentinels for `ui/packages/core` and
`ui/packages/react`, which no changed path touches, and the derived set
was 52 commands both times. `main` is not merged before the PR opens
(AGENTS.md: merge `main` only on a conflict, a main-red or a dequeue).
</details>
<details><summary>Hook self-tests and the local-only freshness gate
(outside the derivation, run on b04d937)</summary>
| command | exit | wall |
|:--|:--|:--|
| `bash .claude/hooks/guard-main-checkout-bash.selftest.sh` | 0 | 7s |
| `bash .claude/hooks/guard-main-checkout.selftest.sh` | 0 | 5s |
| `bash .claude/hooks/guard-process-kill.selftest.sh` | 0 | 1s |
| `bash .claude/hooks/guard-shared-stash.selftest.sh` | 0 | 2s |
| `bash .claude/hooks/guard-tree-enum.selftest.sh` | 0 | 1s |
| `bash .claude/hooks/session-start-fleet.selftest.sh` | 0 | 1s |
| `pnpm check:skill-frame-freshness` | 0 | 3s |
</details>
<details><summary>Line budget — bytes of every touched rule line (cap
120)</summary>
| file:line | before | after |
|:--|:--|:--|
| os-dev.md:273 (retired) | 115 B | — |
| os-dev.md:275 (retired) | 87 B | — |
| os-dev.md:284 (retired) | 84 B | — |
| os-dev.md:288 → 285 | 114 B | 108 B |
| os-dev.md:289 → 286 | 118 B | 98 B |
| os-dev.md (new) 287 | — | 115 B |
| os-dev.md (new) 288 | — | 95 B |
| os-dev.md (new) 289 | — | 114 B |
| SKILL.md:188 | 116 B | 114 B |
| SKILL.md:192 | 116 B | 104 B |
| SKILL.md:193 | 111 B | 107 B |
| SKILL.md:194 | 115 B | 118 B |
os-dev.md 404 → 404 lines; SKILL.md 319 → 319 lines;
check-half-states.mjs 35,243 → 35,593 lines (no ceiling).
</details>
Co-authored-by: Claude <noreply@anthropic.com>1 parent 583b024 commit aea3443
3 files changed
Lines changed: 370 additions & 20 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
270 | 270 | | |
271 | 271 | | |
272 | 272 | | |
273 | | - | |
274 | 273 | | |
275 | | - | |
276 | 274 | | |
277 | 275 | | |
278 | 276 | | |
| |||
281 | 279 | | |
282 | 280 | | |
283 | 281 | | |
284 | | - | |
285 | 282 | | |
286 | 283 | | |
287 | 284 | | |
288 | | - | |
289 | | - | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
290 | 290 | | |
291 | 291 | | |
292 | 292 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
185 | 185 | | |
186 | 186 | | |
187 | 187 | | |
188 | | - | |
| 188 | + | |
189 | 189 | | |
190 | 190 | | |
191 | 191 | | |
192 | | - | |
193 | | - | |
194 | | - | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
0 commit comments