docs(agents): the contract-review carrier is the seat's to hang; --pair PR-NUMBER is the only spelling - #18250
Conversation
…air PR-NUMBER` is the only spelling os-dev.md: the dev never hangs, removes or waits for `needs:contract-review`; it reports the carrier state seen on the PR and the `--pair PR-NUMBER` exit code as a reading. A refused additive label write is reported with endpoint and status for the seat to hang — never `blocked`, never MCP. SKILL.md: the one `--pair N` token becomes `--pair PR-NUMBER`. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
…rrier-is-the-seats-to-hang
…e PR creator SKILL.md :645 now says the seat hangs `needs:contract-review` in the same stroke: on the PR as soon as it exists, on the card first when the report arrives before the PR — the order contract-review.md already states. Equal-line, paid by density. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
…rrier-is-the-seats-to-hang
Contract reviewServed-tier: Reviewing seat: ① Derived judgments
② Semver levelNot applicable — nothing published moves; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
维护者速读(终稿)改了什么:两份席位规则文件各改两行,等行数、每行 ≤ 120 字节。① 为什么改:原文要求 dev「开 PR 同笔挂标签」,而 objectui 的两名 dev 实测被容器的写分类器拒绝——照做的 dev 失败、报告失败的 dev 看起来像抗命;同一行还把 风险与代价(含回滚):纯文本、不碰发布包、不改 CI;行数不变。回滚 = revert 一个 PR。放宽容器写权限(方案 B)是权限面的事,不在本 PR,由你另定。一处已知残留: 席位意见:建议批准。本席在 head 上亲核:四行内容与字节(119/114/101/118)、棘轮 403/403 与 812/812、frame 块 md5 不变、id-lint 与 frame-sync 绿、 你要做的(一个动作):approve 本 PR。approve 后本席翻 ready + 入队。 Generated by Claude Code |
|
Ruling-C landing provenance — skills seat, session Generated by Claude Code |
…quotes the governing line (objectstack-ai#18256) Fixes objectstack-ai#17497 One rule line in 〈分诊座位职责〉 of `.claude/skills/pm-dispatch/SKILL.md`: a triage grading whose direction lands inside an adjudicated area (an ADR, a ruled card, a not-re-adjudicable rule) pastes the governing line — the `Prior rulings read:` line that `check-prior-rulings.mjs` prints — or names no target. Triage keeps writing directions (「写方向」 is charter text); the line binds the direction's evidence, never removes the direction. Governed surface (`.claude/**`, rules layer): draft, no reviewer requested, no ready flip — the skills seat hangs the four-piece and the maintainer lands it. REGION claim :306–:415 only; PR objectstack-ai#18242 holds :172–:185 and PR objectstack-ai#18250 holds :645–:646 on the same file and neither range is touched here (the seat merges `origin/main` at landing). ## The added line (SKILL.md :339 on the head, 120 bytes) ```text - 方向落在 ADR/已裁卡/不可重裁规则:贴 `check-prior-rulings.mjs` 的 `Prior rulings read:` 行,或不点。 ``` Vocabulary is the corpus's own: 「已裁卡」 (SKILL.md 〈家族派发〉), 「不可重裁」 (〈派发词三分区〉), 「落点」 = the named fix target (〈分诊座位职责〉's `pm:queue` definition). The tool is cited by file name and the paste line by its literal prefix — no issue or PR number (`check:pm-skill-id-lint` green). **Placement (P2, chosen by reading the section's order):** directly under the line that mandates the direction — 「裁定写方向、给六态之一」 (:338 on the head, :339 on `origin/main`). That is where 「写方向」 actually lives on this tree: `references/lanes/triage.md` is 7 lines and its :7 is the half-state rule, so the grading's citation of 「写方向」 at `triage.md :7` is stale as a location while its substance holds. The English audit comment line (`Triage: lands in …; rationale: …`, :364 on the head) was the alternative; it names the artifact the direction is written into, but the obligation reads best beside the mandate it qualifies, and 「方向」 is anchored by the preceding line there. **P1 confirmed by a live run** (`node scripts/pm/check-prior-rulings.mjs --card 17497`, exit 0) — the tool printed exactly the shape the line cites: ```text Prior rulings read: triage,gradings,named,target,governing,itself,rejects,grading,quotes,line,adjudication,routes → 61 hits; ADR-0129 D4, ADR-0067 D3, ADR-0076 D11, ADR-0006 D2, ADR-0020 D2, ADR-0021 D1 ``` `formatPasteLine` (`check-prior-rulings.mjs`) prints `Prior rulings read: TERMS → N hits; ADR-xxxx Dn|none` and the whole-line form `Prior rulings read: unresolved` when the search did not run; `check-half-states.mjs` H62 reads the same key (`PRIOR_RULINGS_KEY`), and `references/decision-analysis.md` already binds that line for decision cards. ## Payment (P3, measured) — one adjacent pair inside the region rewritten tighter Before (`origin/main` :311 + :312, 89 B + 50 B): ```text - fire 开局只按名加载互斥检查所需工具,`ToolSearch` 用 `select:` 形式。 - 判定本轮有活之后才加载其余工具。 ``` After (head :311, 116 B): ```text - fire 开局只按名加载互斥检查所需工具,`ToolSearch` 用 `select:`;判定本轮有活才加载其余。 ``` Nothing operative is lost: every instruction token survives — `fire 开局`, `只按名加载`, `互斥检查所需工具`, `ToolSearch`, `select:`, `判定本轮有活`, the ordering `才加载其余` — and the three dropped words are filler (「形式」 names the code span it follows; 「之后才」 → 「才」 keeps the only-after ordering; 「其余工具」 → 「其余」 in a line whose subject is tool loading). The PM's measured pairs (:312+:314, :363+:364, :397+:398) all rewrite past 120 B; this is the pair that fits. Not a re-wrap (no line-joining bought the budget), no rule deleted, ceiling untouched. ## Reverse verification (on head `c96b507d`) - `git diff origin/main -- .claude/skills/pm-dispatch/SKILL.md`: two hunks, `@@ -308,8 +308,7 @@` (the fold) and `@@ -337,6 +336,7 @@` (the insert) — both inside :306–:415; no other line moves. - `wc -l` = 812 (ceiling 812, headroom 0 — the ratchet's own line: `.claude/skills/pm-dispatch/SKILL.md is 812 lines (ceiling 812; headroom 0)`). - `sed -n '734,755p' | md5sum` = `3327d02c56f8a0eca88569dad2270f32` (frame block byte-identical). - an `awk` length scan for lines longer than 120 bytes over :306–:415 prints nothing; touched lines measure 116 B (fold) and 120 B (new). - Positive anchors: `grep -c 'Prior rulings read:'` = 1; the removed :312 text = 0 hits; the fold text = 1 hit. ## Gates (derived, run in the foreground, exits captured before any pipe, reconciled with `--ran`) `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no paths; change set derived off merge base `cb648cb1`) → 16 commands; `--ran` verdict: `16 derived famil(ies) accounted for — 16 run, 0 NOT-MEASURED (a DERIVED zero — all 16 recorded an exit code and none of them is 3)`, exit 0. | command | exit | |---|---| | `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 | | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | first run exit 3 `PREREQUISITE NOT MET` (unbuilt `@objectstack/formula` / `@objectstack/lint`) — built both under `os-verify-lock.sh` (`VERDICT command-exit 0`), re-ran: 0 | | `pnpm check:agent-test-spelling` | 0 | | `pnpm check:doc-authoring` | 0 | | `pnpm check:driver-memory-census` | 0 | | `pnpm check:nul-bytes` | 0 | | `pnpm check:pm-governed-merges` | 0 | | `pnpm check:pm-governed-prose` | 0 (`2 instruction surface(s) name all 5 registered governed surfaces`) | | `pnpm check:pm-skill-id-lint` | 0 (`27 file(s) clean`) | | `pnpm check:pm-skill-ratchet` | 0 (812/812) | | `pnpm check:refd-timer-probe` | 0 | | `pnpm check:skill-frame-sync` | 0 (`the one declared copy of the decision frame is internally coherent`) | | `pnpm check:watch-hint-literal` | 0 | Extra, outside the roster: `node scripts/check-skill-frame-freshness.mjs --self-test` exit 0 and `--no-fetch` exit 0 (`the decision frame in this tree is current with refs/remotes/origin/main`). The roster did not derive `check:pm-dispatch-gates`, so no detached run was owed. Full repo-level scans (`pnpm lint`) belong to CI. `skip-changeset`: `.claude/**` is published by no package's `files[]` (fast track) — nothing released moves. ## Acceptance notes - noted, not filed: the grading's location citation for 「写方向」 (`lanes/triage.md :7`) is stale — that file's :7 is the half-state rule and the charter text lives at SKILL.md :339 on `origin/main`; the ruling's substance is unaffected. 承接者: the skills seat, at landing of this PR. - noted, not filed: the dispatch names a gate `check:pm-skill-frame-sync`; the script's real name is `check:skill-frame-sync` (`scripts/check-skill-frame-sync.mjs`), and it ran green. 承接者: the dispatching PM seat, via this report. - noted, not filed: the ratchet header's reading 「of the file's 601 adjacent bullet pairs ZERO merge under the 120-byte cap」 was a pure-join measurement on an earlier tree; on this tree one pair folds at 116 B as a tighter rewrite. Not a contradiction of that reading and not a defect. 承接者:无. ## 维护者速读(草稿) **改了什么**:分诊座位职责里加一行:分诊的方向若落在 ADR、已裁卡或不可重裁规则内,须贴 `check-prior-rulings.mjs` 印出的 `Prior rulings read:` 行,否则不点落点。为了不突破 812 行上限,把开局工具加载的两行合成一行(116 字节),每条指令原样保留。 **为什么改**:两次分诊给出的落点恰是治理文本已经拒绝的拼写或形状(一次是字段 schema 拒收的扁平拼写,一次是标记为不可重裁的通则),都在执行席的围栏才被拦下,其中一次派发令已写出。分诊的推理没错,错在落点没有引治理行,所以看不见。决策卡那边已有同一行的约束,这次把它也绑到分诊评级上。 **风险与代价(含回滚)**:一行规则、一次同义压缩,不动上限、不删规则、不改工具。风险是新行 120 字节写得紧,读者需要认得 `check-prior-rulings.mjs` 这个工具(它已在仓内、有自检)。回滚 = revert 本 PR 一次提交。 **席位意见**:(留空,席位定稿成评论) **你要做的**:确认这条规则的措辞与落位(放在「裁定写方向」那一行之下);同意即批准本 PR,由席位落地。 --- _Generated by [Claude Code](https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr)_ Co-authored-by: Claude <noreply@anthropic.com>
…bjectstack-ai#18273) Fixes objectstack-ai#18264 The `os-dev-report` contract in `.claude/agents/os-dev.md` (:319 the comment; :360–:377 the JSON shape) gains ONE field, `session`, so every dev report carries in its TEXT the `session_` id that the same file's :51 makes the attribution — 「归属 = 文本里的 session ID,非 `user.login`」 — and that the re-keyed H64 in `scripts/pm/check-half-states.mjs` reads. One governed file, two hunks, both inside the claimed REGION :319–:398 (PR objectstack-ai#18250's :287 / :301 are untouched). `check-half-states.mjs` is not in the diff: P2 below is the measurement that says it does not need to be. Landing: `.claude/**` is the rules layer of the governed surface — this PR stays a DRAFT; the seat hangs the four-piece after the report; an authorized approval lands it. `skip-changeset`: `.claude/**` publishes nothing (os-dev.md :297, the fast lane). ## What changed — 403/403, every edited line at or under 120 bytes Line numbers are on this branch at `f60aba4b`; B = bytes of the line as stored (`LC_ALL=C awk '{print length($0)}'`). The file spells the placeholder inside angle brackets, as the template always has; it is written here as ID. **Added, :366 (117 B)** — the fifth identity field, right after `pr`: "session": "session_ID — this run's harness-stamped id (transcript Claude-Session: line; subagent = parent's)", **Paid, :379 + :380 → :380 (106 B + 66 B → 119 B)** — a tighter rewrite of the adjacent note pair under the JSON block: before - `premise_still_valid: false` = 你的核验证伪了 issue 的前提(规则 6):证据写进 `summary`。 before - 那时 `pr` 为 null 或只圈存活的部分,PM 重新分诊。 after - `premise_still_valid: false` = 核验证伪了前提(规则 6):证据进 `summary`,`pr` null 或只圈存活部分。 Why nothing operative was lost: the words that left are 你的 / issue 的 / 写 / 那时 / 为 / 的 and the clause 「PM 重新分诊」 — the rule-6 cross-reference, the evidence-in-`summary` instruction and the `pr`-null-or-surviving-part rule all survive; 「PM 重新分诊」 is the PM's act, not a dev instruction, and SKILL.md 〈报告契约〉 already states it (「当再分诊输入复核」). `wc -l` = 403 before and after. `pnpm check:pm-skill-ratchet` on the head: `✓ check-skill-line-ratchet: .claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0).` ### The payment deviates from the suggested route, and says so The ruling allowed 「a semantic no-op fold or a tighter rewrite of adjacent lines」. The fold was measured — `open_questions` :372–:374 collapses to one 111 B line, JSON-identical — and NOT taken: os-dev.md :292–:293 (「付行数棘轮的唯一合法货币是删内容:⛔ 不拿 re-wrap(折行合并)当筹行,新增以删减付账」「分界只问折行有没有为新增内容买行」) and the ratchet ledger (「re-wrap funding is refused per the 2026-08-17 rule」) refuse a fold that buys a line for new content, and the file's own conflict clause makes the file win over the dispatch prompt. The tighter rewrite is the route's second option and the file's currency at once. Adjacent-pair measurement of the region, the way the SKILL.md precedent did it: no two adjacent prose lines concatenate under 120 B — :319+:320 = 223, :320+:321 = 200, :321+:322 = 207, :322+:323 = 202, :323+:324 = 210, :324+:325 = 178, :378+:379 = 198, :379+:380 = 172, :380+:381 = 160, :381+:382 = 203, :386+:387 = 231, :387+:388 = 225, :388+:389 = 183, :389+:390 = 171, :390+:391 = 210, :391+:392 = 221, :392+:393 = 195 (pre-edit numbering). So every 2→1 merge deletes words, and :379+:380 is the one pair whose deletable words carry no dev rule. Candidate prose lines for a SECOND added line (the no-MCP route and the subagent case, in Chinese) measured 134–141 B in every spelling tried, over the cap — which is why the whole instruction lives in the one JSON line. ## P1 — how a dev actually obtains its id (measured in this run, `mode:subagent`) | route | reading | |---|---| | the harness attribution stamp in the transcript (the `Claude-Session:` line) | `session_01HZfg2AwVX191qCizp88gQr` | | `get_session` with no argument (the Claude Code Remote MCP — not a GitHub tool) | `session_01HZfg2AwVX191qCizp88gQr`, title `PM dispatch skills` | | env `CLAUDE_CODE_REMOTE_SESSION_ID` | `cse_01HZfg2AwVX191qCizp88gQr` — the same 24-character tail under a `cse_` prefix | | env `CLAUDE_CODE_SESSION_ID` | `d13ed524-f222-55f1-9c04-ff395efe6ed7` — a UUID, not a `session_01` form; H64 cannot read it | | env `CLAUDE_CODE_CHILD_SESSION` | `1` | **P1 is half-falsified.** A subagent has no `session_01…` id of its own: every route the harness offers stamps the PARENT session's id — the same id it already puts on the dev's commit trailer and PR-body footer (os-dev.md :286 / :398). So in `mode:subagent` the only value that can be filled honestly equals the dispatching PM's id by VALUE; what the ruling's ⛔ protects — provenance: read your own stamp, never copy the prompt — still holds, and is what the line says (「this run's harness-stamped id」). The line is followable with no MCP (the transcript's `Claude-Session:` line, the source the footer already draws on) and names the subagent case so the field is fillable in both modes; `get_session` is the MCP-only second route and stays out of the rule line (byte budget; not universal). In `mode:cloud` the same routes return the dev session's own id. This PR's own report carries `"session": "session_01HZfg2AwVX191qCizp88gQr"` — the first live instance of the contract, and the first instance of the subagent case. Premise correction, small: the ruling's 「the way the file already prescribes for the harness-stamped `model` field」 — os-dev.md has no such field; that discipline lives in `references/contract-review.md` :57 and `references/platform-readings.md` :369 (`get_session` → `last_served_model`). The analog inside os-dev.md is the PR-body session-URL footer, which is what the new line is anchored to. ## P2 — the id in a JSON value clears H64; the reader is untouched Replayed through the UNTOUCHED module at `c053f748` (`git diff e592b4b HEAD -- scripts/pm/check-half-states.mjs` is empty): an `os-dev-report` comment, fenced JSON, only the platform's bare footer, `created_at` after the pin. | fixture | `seatSignature` | `seatSessionIdPresent` | `h64SpeaksAbout` | `h64UnattributedSeatContent` | |---|---|---|---|---| | WITH `"session": "session_01HZfg2AwVX191qCizp88gQr"` | `report` | `true` | `false` | `null` | | WITHOUT the field (the control) | `report` | `false` | `true` | 「comment `1` on this card carries an `os-dev-report` marker — a seat/dev artefact — and NO session id appears anywhere in its text…」 | H52's `devReportOpenQuestions` reads `{"marked":true,"parsed":true,"questions":[]}` for BOTH bodies: the reader parses the object and reads `open_questions` alone, so an extra key is neither seen nor judged. `seatSessionIdPresent` tests the WHOLE body with `SEAT_SESSION_ID`, so a JSON value carrying the id attributes the report with no reader change — `check-half-states.mjs` stays out of the surface, as the ruling's measure-first clause asked. ## P3 — one JSON, two copies :319 is unchanged: the comment is 「同一段 JSON」 as the terminal message, so the field reaches both copies through the one payload. No second mechanism. ## Gates — all on head `f60aba4b` Roster derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, NO paths (stderr: change set 1 path vs merge base `c053f748b`; committed 1, working tree 0, untracked 0): 17 commands. Every one ran in the foreground with the exit captured by redirect before any pipe and recorded as `command :: exit N`: - 16 exit 0 on the first pass; `pnpm --filter @objectstack/lint run check:doc-formula-expressions` exit 3 (PREREQUISITE NOT MET — `@objectstack/lint` not built), re-run exit 0 after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2` under `scripts/pm/os-verify-lock.sh` (`VERDICT command-exit 0`). No exit-3 reading is reported here as a measurement. - `--ran` verdict: `✓ dispatch-gates --ran: 17 derived famil(ies) accounted for — 17 run, 0 NOT-MEASURED (a DERIVED zero — all 17 recorded an exit code and none of them is 3).` - Named by the route and not in the roster: `pnpm check:pm-governed-prose` exit 0 (`2 instruction surface(s) name all 5 registered governed surfaces … and claim no others`). `check:pm-dispatch-gates` was not derived for this change set, so it was not run. - Verdict lines: the ratchet line above; `check:pm-skill-id-lint`: `27 file(s) clean (pattern /#[0-9]{3,}/g)`; `check:agent-model-declared`: `os-dev.md → opus`; `check:nul-bytes` exit 0; the pre-push hook's `check:commit-card-trailers`: `1 commit message(s) on this push carry no card relation and no model identifier in the trailer pair`. **Reverse verification of the ratchet (one-off, not landed):** with the fix committed, a 404th line was appended under a `trap … EXIT INT TERM` with an absolute repo root — marker count 0 → 1, mutated blob `6f16705b…` against HEAD blob `7a914c94…` — and the gate went RED (`✗ … os-dev.md is 404 lines; the ratchet ceiling is 403`, exit 1); `git checkout HEAD -- .claude/agents/os-dev.md` restored it: marker count 0, `git diff HEAD` empty, `git status --porcelain` empty, restored blob equal to HEAD's. ## Acceptance notes - noted, not filed: in `mode:subagent` the report's `session` equals the claim's id by value, so H64 clears but a reader cannot tell a subagent's report from its seat's own post by id alone; a per-subagent `session_01…` id would be a harness feature, not a contract line. 承接者:无. - noted, not filed: os-dev.md :318 (outside this region) restates :17 and is the natural payment for the next line this section needs. 承接者:the next PR claiming :316–:318. - noted, not filed: the ruling's `model`-field premise (above) — a wording slip in the dispatch prompt; no rule is affected. ## 维护者速读(草稿) **改了什么**:开发 agent 的终报契约(`.claude/agents/os-dev.md` 的 JSON 模板)新增一个字段 `session`,要求每份报告的正文自带写它的会话 id;同一节的两行说明合并为一行付账,文件仍是 403 行,改动只落在 :319–:398。 **为什么改**:同一文件 :51 规定「归属 = 文本里的 session ID」,而报告模板里没有任何一行能承载这个 id,平台附加的页脚也不带它;刚落地的 H64 巡查按此把每一份 dev 报告都记成「无归属」。补上字段后报告自证归属,巡查行自然消失(P2 实测)。 **风险与代价(含回滚)**:零运行时影响,不发布任何包;唯一代价是每份报告多一行。子代理模式下该 id 与派发席位相同(P1 实测),这是事实而非漏洞。回滚 = revert 这一个 commit。 **席位意见**:(留空) **你要做的**:审阅并批准这张受管面 PR;落地由席位执行。 --- _Generated by [Claude Code](https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr)_ Co-authored-by: claude[bot] <claude[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
Fixes #18181
What changed
Three lines across two governed rules-layer files; line counts unchanged (os-dev.md 403/403, SKILL.md 812/812), every edited line at or under the 120-byte cap, no re-wrap anywhere, and the decision-frame block SKILL.md :734–:755 untouched (md5
3327d02c56f8a0eca88569dad2270f32before and after)..claude/agents/os-dev.md:287 — the line the card names, re-derived onb3b43b6(the card body's:288had drifted; the filer's correction comment 5664488072 gives :287):The dev no longer hangs the carrier. It never hangs, removes or waits for
needs:contract-review; it reports whether the label is present on the PR and the--pair PR-NUMBERexit code — as a reading, not as a gate it must clear..claude/agents/os-dev.md:301 — the neighbouringskip-changesetlabel-write rule (mechanism assumption A2, same file surface, same class — an additive label write the container may refuse):One rule now covers both carriers: a refused additive label write is reported with endpoint and status and the seat hangs the label; the dev never reports
blockedfor it and never switches to an MCP write..claude/skills/pm-dispatch/SKILL.md:646 — the one--pair Ntoken (REGION claim: this line only):--pair PR-NUMBERis now the only spelling in the three governed files (contract-review.md :42 already spelled it so).Why
Direction A of the card's grading (comment 5673619664), executed as ruled: the
needs:contract-reviewcarrier is the PM seat's to hang — on the card at the claim and on the PR when the PR appears — which is what every seat already does; the dev never blocks on a label write;--pair PR-NUMBERbecomes the only spelling. Option B (granting the dev container the label write) is a permissions widening and was ruled not this card.The two defects the card and its correction measured: a dev that obeyed :287 literally was refused the additive label write by its container's write classifier on two independent objectui runs, while an objectstack dev could write it — per container, unknowable in advance; and
--pair NboundNto the nearest referent, the card, while the script takes a PR number and answers a card number with exit 2 (UNJUDGED), which a naive capture reads as a red gate.Mechanism readings
b3b43b6(108 B; the card's :288 is theskills/**line). Replaced as above. Under the byte cap theClause-②: yestrigger did not fit, so the rule is now unconditional: on every PR the dev hangs nothing, removes nothing, waits for nothing, and reports carrier presence plus the--pair PR-NUMBERexit code. That superset is deliberate —--pairalso carries the widening-tell row, which only fires on aClause-②: noclaim, so a reading on every PR is worth more than one onyesclaims alone.被拒 ⇒ 停下报 blockedis the same container-refusal class one line over, and nothing aboutskip-changesetrequires the dev to block on it: CI's changeset gate reads the label, the dev's report says whether it landed, and the seat can hang it on that report. So one rule covers both carriers and :301 changed as above; :299 (the label is your step, hang it as soon as the PR opens) and :300 (additive endpoint) stay — the dev still attempts the write. The live half of the measurement is this PR's ownskip-changesetwrite; its outcome (landed, or the endpoint and status of the refusal) is in theos-dev-reportcomment on the card, not here, because the PR body is written before the label write and is not re-sent.git grep -n -- '--pair N\b' -- '.claude/**' 'scripts/pm/**': before 6 hits (os-dev.md :287, SKILL.md :646, and 4 inscripts/pm/**); after 4 hits, all outside the claimed surface:check-clause2-carriers.mjs:24 and :490 (docblocks), :4947 (a self-test title), andcheck-widening-tells.mjs:492 (docblock). In the three governed files the count is 0. Lit control--pair PR-NUMBER: 1 before (contract-review.md :42), 3 after (:42, os-dev.md :287, SKILL.md :646). The script docblocks bindNto a PR number in their own text (:11 spells--pair 13910 # ONE PR), so the ambiguity is not live there; noted below, not edited.cd /home/user/objectui && PM_SWEEP_REPO=objectstack-ai/objectui node ../objectstack/scripts/pm/check-clause2-carriers.mjs --pair 9552exits 0 with the provenance lineevery row below is read from objectstack-ai/objectui (source: PM_SWEEP_REPO)and the verdictPR #9552 / card #6910 — the clause-② declaration is readable in the fixed spelling and both carriers agree(token present, 3 reads served; the proxy re-exec happened by itself). A control on objectui#9495 (no longer open) exits 2 — UNJUDGED, with the board still retargeted. So the invocation works from a sibling checkout. The byte cap leaves no room on :287 for the invocation (the line stands at 119 B), so the line carries only the flag spelling; the script header (:20–:24) already spells the sibling invocation and every run prints the board it read, which is the remedy text the ruling asks to keep in the script.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no paths; change set from the merge base): 18 families ona2cbbef0, re-derived on the merged head0c934967(merge base68fea8bc) — identical list. All 18 run in the foreground on0c934967, exit codes captured by redirect before any pipe, all 0:check-closing-keyword-parity(+--self-test) ·check-comment-mask-corpus·check-governed-queue-guard --self-test·check:doc-formula-expressions(lint pkg) ·check:agent-model-declared·check:agent-test-spelling·check:commit-card-trailers·check:doc-authoring·check:driver-memory-census·check:nul-bytes·check:pm-governed-merges·check:pm-governed-prose·check:pm-skill-id-lint·check:pm-skill-ratchet·check:refd-timer-probe·check:skill-frame-sync·check:watch-hint-literalReconciliation on
0c934967:✓ 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).Verdict lines:
✓ check-skill-line-ratchet: .claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0)·✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 812 lines (ceiling 812; headroom 0)·✓ check-agent-model-declared: 1 agent definition(s) under .claude/agents/ all declare a model·✓ check-skill-id-lint: 27 file(s) clean·✓ check-skill-frame-sync: the one declared copy of the decision frame is internally coherent.check:doc-formula-expressionsfirst answered exit 3 (PREREQUISITE NOT MET —@objectstack/formulaand@objectstack/lintunbuilt in a fresh worktree); prerequisite built under the verify lock (turbo run build --filter=@objectstack/formula --filter=@objectstack/lint, VERDICT command-exit 0), rebuilt again after the merge, then the gate exits 0. The exit 3 is not a measurement and is not counted as one.Not run locally, by design: the 11 wide-population families and the whole-repo
pnpm lintsweep belong to CI. Control-byte self-scan on both edited files: no hits.Line budget
.claude/agents/os-dev.md.claude/skills/pm-dispatch/SKILL.mdPaid by density in place; no line merged or split.
Deviations, declared
N→PR-NUMBER, +8 B) puts the line at 124 B, over the 120-byte cap. Two characters were dropped on the same line (在,即), content unchanged, landing at 118 B. Still inside the one-line REGION claim.Clause-②: yestrigger is gone for the byte cap; the rule is unconditional (see A1). If the seat wants the trigger back, the price is the作读数tail or the不等limb.skip-changeset: nothing published moves —.claude/**is on the fast path (no packagefiles[]ships it).origin/mainmerged at68fea8bc(one spec commit, nothing on this surface) before opening; pm-dispatch: reconcile the quota rows with the identity-bound rate limit; merged-write rule; account-suspension recovery readings #18242 remains open on SKILL.md :172–:185 — disjoint from :646.Acceptance notes
needs:contract-review,PR 创建者,同笔挂, SKILL.md, direction A): SKILL.md :645 still reads 「needs:contract-review(恒英文)由 PR 创建者随可复审契约增量同笔挂:draft PR,或先到的报告。」 For a dev-created PR the creator is the dev, which direction A says never hangs it. Outside this card's REGION claim (:646 only), so not edited here; it sits on the SKILL.md chain the seat owns.--pair Nspellings remain inscripts/pm/**docblocks and one self-test title (listed under A3); each is next to text that binds N to a PR number. 承接者:无.os-dev-reportcomment with a read-back; under one shared identity the author field says nothing about who hung what.维护者速读(草稿)
改了什么:改了两个受管规则文件里的三行,行数不变。开发 agent 定义(os-dev.md)一行:
needs:contract-review这个标签归席位挂,开发 agent 不挂、不摘、不等,只在报告里写 PR 上有没有它、以及--pair PR-NUMBER的退出码,作读数。另一行:加法写标签被容器拒绝时,报端点与状态码、由席位代挂,不再报blocked、不走 MCP。PM 技能(SKILL.md)一个 token:--pair N改成--pair PR-NUMBER。为什么改:两次独立实测里,开发 agent 的容器拒绝写标签,而规则要求它开 PR 同笔挂——照做就失败、如实报告又像抗命。分诊裁定 A 向:载体由席位挂(认领时挂卡、PR 出现时挂 PR),开发 agent 只报所见。同一行的
N让人绑到卡号,脚本要的是 PR 号,给卡号返回 exit 2(未判),会被当红灯读;PR-NUMBER是唯一拼写。风险与代价(含回滚):行数与上限不变,每行 ≤120 字节,决策框架块未动。风险是开发 agent 不再自己挂载体,若席位漏挂,条款② PR 的载体会缺失——但席位侧已经是现行做法,且开发 agent 报告的
--pair读数会暴露缺失。回滚 = revert 本 PR,无其他副作用。席位意见:
你要做的:审阅上面三行措辞(尤其 :287 去掉了
Clause-②: yes触发词、改为对每个 PR 都成立);同意即给授权批准,由席位落地;不同意请指出要保留的措辞。Generated by Claude Code