Skip to content

skills(pm-dispatch): off-tier seat discharges clause-② review by spawning an at-tier subagent (ruling C) - #18511

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-18434-clause2-offtier-subagent-route
Sep 17, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/issue-18434-clause2-offtier-subagent-route

Conversation

@os-justin

@os-justin os-justin commented Sep 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #18434

Governed rules-layer re-key carrying the maintainer's ruling 「18434 C」 (director record 5699124096 on the card; the maintainer's confirmation on the ui seat's channel, record 5701005814: 「改规则:允许未达档席起达档子代理」). Three prose files (the third, references/core-rules.md, added in the patch round — D9 below), no code, no script edits, every touched file line-neutral against its ratchet ceiling. Landing is not the author's: this PR stays draft; the skills seat hangs the four-piece and the maintainer's approval lands it.

What changed

.claude/skills/pm-dispatch/SKILL.md — 812 / 812 (two lines re-keyed in place)

line before after
:522 (114 B → 118 B) 「- 条款②复核只在实测达档的席内做,记录写读数;未达档席 ⛔ 不审、不起该档子代理。」 「- 条款②复核按实测档:达档席内审;未达档席 ⛔ 不自审,起隔离达档子代理转录核档采信。」
:640 (117 B → 117 B) 「- 交付后复核由派发席席内完成:达档审,未达档默认档加门禁;记录 = 同形评论落 PR 或卡。」 「- 交付后复核归派发席:达档席内审,未达档循保险丝起子代理;记录 = 同形评论落 PR 或卡。」

:522 is the ruling's line — meaning fixed by the ruling, wording the dev's, 118 B under the 120 B cap. 「记录写读数」 was dropped from it because the record requirement lives in contract-review.md (「复核记录 = 一条评论落 PR 或卡」, 「同形含首行 Served-tier:」).

.claude/skills/pm-dispatch/references/contract-review.md — 60 / 60

line (new numbering) before after
:26 (119 B → 116 B) 「- 按档位:达档席内审契约增量;未达档默认档自审加门禁、挂标;豁免仅独立性件与保险丝。」 「- 按档位:达档席内审契约增量;未达档 ⛔ 不自审,走保险丝路;豁免仅独立性件与保险丝。」
old :39 deleted (97 B — the payment) 「- 随后按 landing-operations.md 走落地前检 → 转 ready → 挂 auto-merge 或入队。」 — (the same sequence is SKILL.md :617 「席位落地 = 过落地前检、清标、ready、auto-merge」 and :641; the three-step pre-landing check that follows at :40–:46 is untouched)
:50, was :51 (105 B → 120 B) 「- 保险丝管每个出条款②裁决的席,每场前必读服役档,读法见 platform-readings.md。」 「- 保险丝管每个出条款②裁决的席:每场前必读服役档(platform-readings.md),未达档 ⛔ 不自审。」
:53, was :54 (108 B → 114 B) 「- 读数不达档 ⇒ 改走转录核验的复核子代理;标签原样留置,队列外等待是安全态。」 「- 读数不达档 ⇒ 改走转录核验的达档复核子代理;标签原样留置,队列外等待是安全态。」
:54, was :55 (108 B → 118 B) 「- 保险丝只测座位自会话:mode:subagent 里 get_session 量的是派发会话,⛔ 不作互证。」 「- 子代理档只取其转录 harness 逐请求 model 盖章;get_session 量的是派发会话,⛔ 不作互证。」
:59 (new, 110 B) — 「- PASS、FAIL 与作废都落 PR 或卡;同 head 再起子代理须引前次作废因,⛔ 不重起求 PASS。」

.claude/skills/pm-dispatch/references/core-rules.md — 151 / 151 (one line re-keyed in place, patch round)

line before after
:112 (119 B → 119 B) 「- 一单一次派发,档位逐卡显式传参;语义面卡恒契约复审档施工,契约卡达档复核归 spec 席。」 「- 一单一次派发,档位逐卡显式传参;语义面卡恒契约复审档施工,契约卡达档复核归派发席。」

The twin probe git grep -n '达档\|子代理' origin/main -- .claude/skills/pm-dispatch/references/core-rules.md returns :51 :112 :113 :122, none of which states the spawn bar — but :112 still named the pre-tier-bound owner (spec seat) of the clause-② at-tier review, while SKILL.md :512 reads 「达档复核归派发席席内」 and contract-review.md :25 「归属该卡派发席」. 「席内」 is not spelled at :112 because the line would be 125 B against the 120 B cap; it is carried by SKILL.md :512.

The three guards, where each now lives

  1. Tier verified from the transcript, not the request — :52 「⛔ 自述档位与传参皆非读数」 (unchanged); :54 (the subagent's tier is taken only from the harness per-request model stamps in its own transcript; get_session measures the dispatching session and is no cross-proof); :57 「产出裁决的每轮都须读到契约复审档位,见回退证据 ⇒ 裁决整体作废」 (unchanged); :60, the quota-exemption bar (unchanged). Before this PR the file said 「转录核验」 but named no source for the subagent's tier — platform-readings.md :384 covers the seat's OWN session transcript, and the old :55 said get_session cannot see the subagent — so the source is added, not merely re-worded (PM assumption A2: substance present, source absent).
  2. Adversarial brief, no contamination — :32–:33 unchanged.
  3. Verbatim or void, every time on the record — :58 unchanged (verbatim adoption or whole voiding for 核验失败 / 越范围 / 格式不完整); the NEW :59 adds the half that was absent: every verdict, PASS, FAIL or voided, is posted on the PR or card, and a second spawn on the same head cites the first's void reason.

Independence pair (:35–:37), --pair (:41–:42, :55) and Served-tier: (:29) are unchanged. No script is edited (PM assumption A3 holds: check-clause2-carriers.mjs --pair already reads Served-tier:; guard 1 is a reading rule).

Deviation, declared: :640 and :26 are in the diff

PM assumption A1 (「line 522 is the only SKILL.md line stating the old bar」) holds for the spawn bar — 不起该档子代理 is only at :522 — and is falsified for the in-person bar. PR #18363 (05f1cdd6) wrote the rule in three places at once (its own file patch: SKILL.md :512 / :522 / :640 and contract-review.md :26 / :41 / :51 / :52), and :640 「未达档默认档加门禁」 and :26 「未达档默认档自审加门禁、挂标」 still described an off-tier seat reviewing IN PERSON at default tier — the half of the bar that ruling C keeps (the ui seat's record: 「the bar on reviewing in person stands; the bar on spawning does not」). Leaving them would re-create the two-texts-disagree shape this card reports, so both are re-keyed in place under the bounded in-place-fix exemption: same defect class; mechanical, with the meaning pinned by the ruling; no other claim holds either file (#18489 is instructed not to touch :523 and targets the triage block, #18469 targets :91–92, and the file lists of all 15 open PRs read at PR time touch neither file); same gate family. If the seat prefers the narrow diff, reverting those two lines is a two-line change and every gate below stays green. Answered by the coordinator in the patch round: A — keep.

D9 — patch round: core-rules.md :112 rides this PR

The out-of-scope finding (b) from the first report was verified by the coordinator on origin/main 8cf527f and ruled to ride this PR under the same bounded in-place-fix exemption (same class as D1 — text still naming the pre-tier-bound owner; mechanical; no other claim holds core-rules.md — #18489 is pm:blocked, #18469 does not touch it; same gate family) instead of a fourth governed four-piece. Executed: origin/main merged first (acc1943, one docs commit touching content/docs/data-modeling/seed-data.mdx only, no regeneration owed); :112 re-keyed in place (af846cf). Probes with controls on core-rules.md: 归 spec 席 1 → 0, 归派发席 0 → 1, control 契约复审档 1 → 1; every other core-rules line byte-identical (git diff -U0 shows the single line).

Verification — round 2 on af846cf (round 1 on 3088a1c read identically)

  • Gate list derived with no paths, off the merge base with origin/main: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack → 17 families (identical to the PM's lead). All 17 run in the foreground, each exit code captured by redirect then $?, every one 0. Reconciliation --ran with COMMAND :: exit CODE lines: 「✓ 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)」.
  • Ratchet: 「✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 812 lines (ceiling 812; headroom 0)」 · 「…contract-review.md is 60 lines (ceiling 60; headroom 0)」 · 「…core-rules.md is 151 lines (ceiling 151; headroom 0)」; widest introduced line 120 B (:50 of contract-review.md); core-rules :112 is 119 B.
  • check:pm-skill-id-lint 「27 file(s) clean」 · check:skill-frame-sync 「the one declared copy of the decision frame is internally coherent」 · check:nul-bytes 「OK (scanned 8738 text file(s) … no raw ASCII control bytes)」.
  • check:doc-formula-expressions needed @objectstack/formula and @objectstack/lint built: built under scripts/pm/os-verify-lock.sh (「VERDICT command-exit 0 · held the lock 141s · waited 0s」), then 「✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 438 files / 1377 TS blocks judged clean」.
  • Probes, origin/main fed4a15 → this head: 不起该档子代理 1 → 0; 起隔离达档子代理 0 → 1; control 达档 6 lines → 6; 默认档加门禁|自审加门禁 1 + 1 → 0 + 0; core-rules.md 归 spec 席 1 → 0, 归派发席 0 → 1, control 契约复审档 1 → 1.
  • No reverse-verification or ablation leg: a prose rule with no runtime or dist; the probe flip above is the before/after measurement.

Acceptance notes

维护者速读(草稿)

改了什么:把条款②契约复核的路线改成你 16 日下午定的 C:达档的席自己审;未达档的席不自己审,起一个隔离的达档复核子代理,按子代理转录里逐请求的档位盖章采信其裁决。SKILL.md 两行、contract-review.md 六行(删一行付账、新增一行记「每份裁决都落 PR 或卡,同 head 再起须引上次作废因」)、core-rules.md 一行(:112 把契约卡达档复核的归属从 spec 席改为派发席,与 SKILL.md :512 一致),行数与上限一致(812 / 812、60 / 60、151 / 151)。

为什么改:今天早上落地的 :523 把「不自审」和「不起子代理」绑在一起,默认档车道的 Clause-②: yes 卡就没有任何合法路径拿到裁决——objectui 三张 PR 停在安全态,第四张(objectui#8167,你批过的 p2)干脆没派出去。你的裁决 C 只放开「谁可以起复核」,不放开「什么算复核」:Served-tier: 首行、子代理必须真的跑在契约复审档、实现者与复核者同会话仍算自审,三条都不变。

风险与代价(含回滚):零代码、零脚本、零发布物,17 个派生门禁全绿。剩下的风险在执行面:平台是否会把父会话逐字转贴的子代理裁决也拒为 [Self-Approval] 尚未实测(裁决记录已写明首次使用时测量并记入 platform-readings.md)。回滚 = revert 本 PR 的一个 commit,文本回到 :523 的旧句,车道回到安全态停靠。

席位意见:(留空,席位定稿)

你要做的:按四件套流程批准本 PR(规则层,等你的字);合并后 domain:ui 席直接按新规则处理停靠的三张 PR,不需要你再动。


Generated by Claude Code


Generated by Claude Code

…ning an at-tier subagent (ruling C)

Re-key the clause-② review route in place, line-neutral (SKILL.md 812/812,
contract-review.md 60/60): an at-tier seat reviews in-seat; an off-tier seat
never self-reviews and instead spawns an isolated review subagent at the
contract-review tier, adopting its verdict on a transcript tier reading.
contract-review.md keeps the fuse route as the rule, names the transcript
source for the subagent's tier, and records that every verdict (PASS, FAIL,
voided) lands on the PR or card and a re-spawn on the same head cites the
prior void reason. Paid inside the 60-line ceiling by deleting the
landing-sequence pointer line that SKILL.md already carries.

Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu
Co-authored-by: Claude <noreply@anthropic.com>
@os-justin os-justin added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 16, 2026 — with Claude
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Sep 16, 2026
…use-② at-tier review owner

Patch round on the same claim: `references/core-rules.md` still named the
pre-tier-bound owner (「契约卡达档复核归 spec 席」) while SKILL.md and
contract-review.md already read the dispatching seat. Re-keyed in place at
120 B, line-neutral (151/151); every other line byte-identical.

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

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿)

席位:domain:skills · session_01Gqi43smmqjJ5sUrhfoPeKu · 2026-09-16T17:36Z · 复核记录在 #18434(ACCEPT)。

改了什么。 把条款②契约复核的路线改成你今天下午定的 C:达档的席自己审;未达档的席不自己审,起一个隔离的达档复核子代理,按子代理转录里逐请求的档位盖章采信它的裁决。三个文件、八行、零代码:SKILL.md 两行(条款②那一句 + 「交付后复核」那一句)、contract-review.md 六行(保险丝三句改写、删一行付账、新增一行「每份裁决都落 PR 或卡,同 head 再起须引上次作废因」)、core-rules.md 一行(「契约卡达档复核归 spec 席」改成「归派发席」——dev 顺手发现的旧归属,本席核实后并入本 PR)。行数与上限一致:812 / 812、60 / 60、151 / 151。

为什么改。 今天早上落地的那一句把「不自审」和「不起子代理」绑在一起,默认档车道的 Clause-②: yes 卡就没有任何合法路径拿到裁决——objectui 三张 PR 停在安全态,第四张(objectui#8167,你批过的 p2)干脆没派出去。你的裁决 C 只放开「谁可以起复核」,不放开「什么算复核」:Served-tier: 首行、子代理必须真的跑在契约复审档、实现者与复核者同会话仍算自审,三条都不变;三道护栏(转录验档、对抗式简报、逐字采纳或整体作废且每份裁决上墙)现在都是承重条款。

风险与代价(含回滚)。 零代码、零脚本、零发布物;17 个派生门禁本地全绿,PR 上 20 绿 12 跳、Lint & Repo Gates 复核时还在跑(落地前本席再读)。执行面的一个未知:平台分类器会不会把父会话逐字转贴的子代理裁决也拒为 [Self-Approval],尚未实测——裁决已写明首次使用时测量并记入 platform-readings.md。回滚 = revert 本 PR(一次 revert 合并即可),文本回到旧句,车道回到安全态停靠。

席位意见。 同意落地。diff 逐行对照过裁决文本与 ui 席记录的边界(放开谁起复核,不放开什么算复核),八行都在这条边界内;dev 多改的三行(SKILL :640、contract-review :26、core-rules :112)是同一缺陷的残留文本——都还在描述「未达档自审」或「归 spec 席」的旧归属,不改它们今天的冲突会换一种拼写再出现。本席已按四件套挂起,并请了 os-zhuang 与 hotlong 复审。

你要做的。 在 PR #18511 上 APPROVE(规则层,等你的字)。批准后本席按裁决 C 落地(记录、--pair 0、检查全绿、清标、ready、auto-merge);合并后 domain:ui 席直接按新规则处理停靠的三张 PR,不需要你再动。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 17, 2026 07:15
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit ab1d359 Sep 17, 2026
42 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-18434-clause2-offtier-subagent-route branch September 17, 2026 07:39
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…d a counterfactual — the discipline guarded a ZERO only (objectstack-ai#18809)

Fixes objectstack-ai#18798

Clause-②: no

Governed rules layer, one file, line-neutral:
`.claude/skills/pm-dispatch/references/core-rules.md` 151 → 151. This PR
**stays draft** — no ready flip, no reviewer request, no arming; the
skills seat hangs the four-piece and the maintainer lands it.
`skip-changeset`: `.claude/**` publishes nothing (fast-track class).

## The gap

The reading discipline makes exactly **one** mechanical demand of an
instrument — core-rules :45 「零命中须配同主体必中词,否则该零作废;同仪器的控制词双零是仪器坏,⛔ 不读作缺席。」
— and it guards a **ZERO**. Nothing in the protocol made a seat prove
that a **non-zero** reading counted the thing it claimed to count, and
the card's measured cost is eight instances in one shift (six on the
card, two the triage seat measured on itself), five of them non-zero and
every one of them already written into a card, a handover brief or a
dispatch where another agent acted on it. The card's own boundary — ⛔
not a blanket "every number needs a control", because that tax falls
hardest on the cheap probes that make the loop affordable — is what
decides the scope: the demand binds a reading **another agent will act
on**, and a seat's own use-and-discard probe owes nothing.

## The row, verbatim

Added at `core-rules.md` :46, directly under the zero rule it
generalises (119 bytes; the file's cap is 120):

```text
- 他人据以行动的读数须带单位并答什么本来会让它不是这个值;递 dev 的恒标线索非答案。
```

Three clauses: ① the reading states its **unit** (files? occurrences?
lines? bytes?); ② it answers 「什么本来会让它不是这个值」 — the triage's second
question, verbatim in substance; ③ a reading handed to a dev as a
**lead** is always marked a lead, not an answer. The scope word
「他人据以行动的」 is the boundary in positive form and is the card's own
criterion (「另一个 agent 会据此行动的地方」); a probe a seat uses and discards is
not a reading this row binds.

## The eight instances, against the row's clauses

| # | instrument | what it actually answered | caught by |
|:--|:--|:--|:--|
| 1 | `startswith("Blocked-by:")` over issue bodies | bodies only,
line-initial, undecorated — the comment channel and `**Blocked-by:**`
lines are invisible to it | ② — the honest answer names the corpus, and
a `Blocked-by:` in a comment moves the number not at all (cost: two
non-defects entered a handover brief as work items) |
| 2 | `grep -E '^[-+][^-+]'` over a charter diff | the document's lines
start with `- `, so its changed diff lines read `--` and the pattern
excluded them | ② — answering it requires a known-changed line as a
positive control (cost: "almost nothing changed", really 46 + 14 lines
including a reversed rule) |
| 3 | a starred control reading "this package's routes do i18n lookups"
| every hit was a comment or a metadata key name | ② — if the routes did
**not** do lookups the grep still reads non-zero, which disproves the
reading; ① alone does not catch it (cost: an option costed an order of
magnitude low) |
| 4 | a `package_version_id` grep handed to a dev as a lead | the zero
was true; the mechanism was elsewhere | ③ — neither ① nor ② catches this
one: the reading is correct and still points the wrong way. This is the
instance the lead clause exists for, and the R39 dispatch that said
"this is a lead, not an answer" is what saved it |
| 5 | `git grep -c … \| wc -l` to count call sites | it counts **FILES**
| ① directly (unit: files, not call sites) and ② as well (a second call
site in the same file moves nothing); reported 5, there are 9 |
| 6 | a **paraphrased** calibration case (cloud#2020, the card's origin)
| it passed for the wrong reason — the paraphrase dropped the sentence
carrying the cue, so the case exercised a path the real corpus never
takes | ② — "what would have made this case NOT pass" is answerable only
against the verbatim excerpt it is not; the dev named the class itself:
the same class as an ablation that passes because nothing was mutated |
| 7 | the triage seat's own three-set endpoint diff, residual **0** |
structurally blind to same-round in-and-out: a card that entered and
left in the same round appears in neither column | ② — "what would have
made the residual non-zero" forces enumerating the transitions the three
sets can represent; ① does not catch it (the unit, cards, is right) |
| 8 | the triage seat's own `objectstack-ai#18791` grep — unit right, control lit,
count true | it answered **the wrong question**: who has already written
the bad value, not who is TEACHING it (the gate's own `fix` string, in
the same output) | **NOT caught** — see below |

Instance 8 is the boundary and it is stated as a measured disagreement
with the triage's expectation, not smoothed over. The triage proposed ②
as the question that catches the zero, the non-zero **and** the
unit-correct-but-wrong-question shape. Measured against this row as
written, it does not: ① is satisfied, ② is answerable ("an authored
block carrying the bad value would have made it non-zero"), and the
reading was true. What fails there is the QUESTION, which is exactly the
shape of sibling card objectstack-ai#18755 (「a lit control certifies the INSTRUMENT,
not the QUESTION」) — a card the triage's own dedupe ruling keeps
separate and this PR does not fold. One wording would reach it — binding
② to the CONCLUSION the reading is carried for ("what reading would have
overturned the call this number is used to make") rather than to the
instrument — and it was refused on the axes below: it costs a
re-derivation of the decision per reading, and it would silently absorb
objectstack-ai#18755 while that card is open and graded on its own.

## ① + ② or ② alone — the four axes

Written: **① + ②**, both, in one row. The card's original candidate (①
alone) is refused outright by instance 8, and was already refused by the
triage.

- **实际业务需求** — measured on the eight instances, not on which question
reads better. ① alone catches 1 of 8 (objectstack-ai#5). ② alone catches 6 of 8 and
misses objectstack-ai#5's cheapest catch only in the sense that it takes a constructed
counterfactual to get there. Neither covers the set; ① costs one word
per reading and buys the one instance whose defect is purely a unit
error, so dropping it saves no budget and loses the cheapest catch in
the corpus.
- **项目长远合理性** — they are different kinds of obligation and collapsing
them hides the cheap one behind the expensive one: ① is a FORMAT demand
that makes a number self-describing when the next seat re-reads the card
weeks later; ② is an EVIDENCE demand about the instrument. A unit-less
number in a landed card cannot be re-checked by anyone at all.
- **防 AI 写代码犯错** — the deciding axis here. ② can be discharged with a
plausible sentence, and an AI seat is very good at plausible sentences;
① is mechanically refusable by a reader (is there a unit word beside the
number, or not?). Keeping the loud, checkable half is the contract-first
choice, exactly as a strict schema beats a tolerant consumer.
- **创业阶段不扩散需求** — the tax is bounded by the scope clause, not by
dropping a question: readings that go into a card, a brief or a dispatch
are a small fraction of the probes a round fires, and the card and the
triage both drew that boundary. ⛔ No blanket demand on every number is
written or implied.

**What the one-row budget cut**, and where it should land: the explicit
negative form of the boundary (「⛔ 自用即弃的探针不欠此税」) and the discharge form
of ② (「答案取逐字工件或具名反例」 — the cloud#2020 rule, an instrument either
measures the real artefact or carries a control that establishes what it
is counting). Both are named here so the seat can queue them; the
natural carrier is the SKILL.md twin this PR owes (below), where the
reading discipline already spends two lines on the zero rule.

## The row paid, in this file

`core-rules.md` :51 is **retired**. It carried three clauses:

| clause | disposition |
|:--|:--|
| 「分诊查重零命中须控制词」 | **the payment** — a near-duplicate: :45 already states
the zero rule generally and unconditionally, so the dedupe instance adds
no mechanical demand. This is the duplication the card itself names |
| 「子代理自死不等于维护者中止,需显式信号」 | **merged into :111**, the claim-reclamation
rule it governs: 「- dev 自死不等于维护者中止,需显式信号;回收前先救工作树,有提交的活分支 ⛔ 永不回收。」 (119
B). `dev` is SKILL.md :174's own word for the subject |
| 「立卡者只附查重词」 | **merged into :80**, the execution-versus-triage division
of labour it belongs to: 「- 执行席 ⛔ 跳过分诊动作,读到标签当既成事实;立卡者不查重、只附查重词。」 (102
B). The added 「不查重」 is SKILL.md :176's own spelling, not new content |

So the diff is three insertions and three deletions in one file: one row
retired, two rows extended, one row added. No live rule was deleted. ⛔
Re-wrapping was not used as currency — the only content dropped is the
duplicated clause.

Two payment shapes were weighed and refused. An adjacent-pair merge: the
ratchet's own comment on this file measures ZERO of its adjacent bullet
pairs merging under the 120-byte cap (smallest 156 B), and re-measuring
by hand reproduced it. A merge of the two preamble lines :2–:3: it frees
a line, but every spelling that keeps 「本文不新增规则」 verbatim lands at 133
bytes or more, so it can only be bought by deleting the file's own
self-description — worse content to spend than a duplicated clause.

## Mirror reading — must SKILL.md :163 move in lockstep?

**By gate: no. By the protocol's own binding text: YES, and this PR does
not carry that half.**

- No gate compares the two documents. Instrument: `git grep -l
'core-rules'` over `scripts/ .github/ package.json` reads **2 files** —
`scripts/pm/check-skill-line-ratchet.mjs` (counts lines only) and
`scripts/pm/dispatch-gates.mjs` (derives gate families). Lit controls on
the same instrument and corpus: `platform-readings` reads 7 files,
`SKILL.md` reads 40 files; absent control (a nonsense token) reads 0,
exit 1. A second instrument agrees: `git grep -n '核心条款'` over `scripts/
.github/` reads exactly **one** line — a COMMENT at
`check-skill-line-ratchet.mjs:1126` quoting the rule — with 受管面 lit as
control in the same corpus.
- The binding text is unambiguous. SKILL.md :43 「核心条款住
`references/core-rules.md`,是本文的子集」, SKILL.md :44 「一条规则在本文与核心条款一处改动,另一处同
PR 同改」, and `core-rules.md` :3 「本文不新增规则」. A rule that exists in
core-rules and not in SKILL.md breaks the declared subset relation.
- Both reference PRs named in the dispatch carried the twin in the same
PR: PR objectstack-ai#18511 re-keyed SKILL.md :522 / :640 **and** core-rules :112; PR
objectstack-ai#18481 re-keyed SKILL.md :390 / :391 / :403 / :404 / :712 **and**
core-rules :95 / :96 / :137, and declared in its own body the one item
that has no core-rules twin. Two of two.
- **⇒ The owed half, for the seat to queue:** SKILL.md's
reading-discipline block (:163–:164) gains the same rule. That half is
not in this diff because SKILL.md is serial behind PR objectstack-ai#18666 / PR
objectstack-ai#18679, which is the seat's ruling, not a reading this PR takes. Until
it lands, `core-rules.md` states one rule SKILL.md does not, and no gate
will say so — which is itself a rule with no paired mechanical action,
in a file about rules with no paired mechanical action. It is in the
report's out-of-scope findings as a class (b) card for the seat to file.

`check:skill-frame-sync` was run and is green, but it judges the
four-axis DECISION FRAME's coherence and scans for undeclared copies of
that frame — it is not a rules-row mirror and its green says nothing
about the twin obligation above.

## Sibling cards, read and not folded

- **objectstack-ai#18755** (p2, 「a lit control certifies the INSTRUMENT, not the
QUESTION」) — read in full. This row narrows its gap but does **not**
close it, and that is the honest reading of instance 8 above: the row
binds readings that reach a card, a brief or a dispatch, so a near-miss
heading into a finding (its `check-validity-recogniser` case) would be
inside the demand, while a seat's own discard probe stays outside it by
design. The uncovered half is the shape objectstack-ai#18755 names — a live
instrument, every control satisfied, pointed at a question the
instrument's DOMAIN cannot answer. That card is not addressed here.
- **objectstack-ai#18744** (p2, HELD) — read. It is three fact rows in
`platform-readings.md` resting on a falsified rationale; different file,
different instrument, nothing to fold. Not addressed here.
- `platform-readings.md` :226–:227 are untouched (objectstack-ai#18774 is on that
file); `SKILL.md` :163 is untouched (serial, above).

## Verification, head `46b7bd6a46`

- **Ratchet before / after.** At `main` (`331462d11f`, the branch base):
「✓ check-skill-line-ratchet:
.claude/skills/pm-dispatch/references/core-rules.md is 151 lines
(ceiling 151; headroom 0).」 At this head: byte-identical line. Widest
introduced row 119 B (:46 and :111); :80 is 102 B; no line in the file
exceeds 120 B (measured over all 151 lines).
- **Diff.** `git diff --stat 331462d HEAD` → `1 file changed, 3
insertions(+), 3 deletions(-)`.
- **Derived gates.** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` from the worktree with no hand-fed
path list → 16 families. All 16 run in the foreground, each exit code
captured by redirect then `$?`:

```text
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/pm/check-governed-queue-guard.mjs --self-test :: exit 0
node scripts/pm/check-harness-current.mjs --self-test :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-skill-id-lint :: exit 0
pnpm check:pm-skill-ratchet :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:watch-hint-literal :: exit 0
```

Reconciliation with `--ran`: 「✓ dispatch-gates --ran: 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)」.
`check:doc-formula-expressions` first answered **exit 3, PREREQUISITE
NOT MET** (`@objectstack/formula` and `@objectstack/lint` unbuilt) — not
a finding and not a measurement; both packages were built under
`scripts/pm/os-verify-lock.sh` (「VERDICT command-exit 0 · held the lock
1s · waited 0s」) and the gate then answered exit 0.
- **Two more, run because the derivation named their rosters rather than
cleared them:** `pnpm check:pm-settings-deny-roster` (its roster sits
under `.claude`, where this path is) exit 0, and `node
scripts/check-skills-token-ratchet.mjs` exit 0 (「34 authored bundle
file(s) within their ceilings」 — the published catalog is untouched).
- **Repo-wide `pnpm lint`** (`eslint . --no-inline-config`): exit 0, no
output.
- **Control characters:** `pnpm check:nul-bytes` exit 0 (「scanned 8850
text file(s) … no raw ASCII control bytes」), plus a direct sweep of the
edited file for the C0 range and DEL: no match, exit 1.
- No ablation or reverse-verification leg: a prose rule with no runtime
and no `dist`. The before/after measurement is the diff plus the ratchet
pair above.

## Acceptance notes

- **To file (class b), handed to the seat, not filed here:** the twin
obligation SKILL.md :44 declares (「一条规则在本文与核心条款一处改动,另一处同 PR 同改」) and the
subset relation SKILL.md :43 / core-rules :3 declare are enforced by
**no gate** — the only occurrence of 核心条款 under `scripts/` is a comment
quoting the rule. Declared coverage, measured false; this PR is itself
the instance. Dedupe words: 「核心条款 同 PR 同改」 · 「core-rules SKILL.md 无镜像门禁」
· 「本文不新增规则」 · 「twin line SKILL.md:44」 · 「digest subset drift」.
- noted, not filed: `core-rules.md` :5 「PM 不写任何文件」 and :23 「PM ⛔
不写文件也不写代码」 state the same prohibition twice, one in 红线 and one in
全体座位的不变量; a future row needing payment in this file can merge :23 with
:24 (whose 「⛔ 不得自审自合」 is already carried by :5) for one line, at 115 B.
Handler: the next card that has to pay a row in this file.
- noted, not filed: `core-rules.md` :43 「不取本地工作树」 and :44 「⛔ 不用共享检出树」
overlap; folding them frees bytes but not a line. Handler: none.

## 维护者速读(草稿)

**改了什么**:读数纪律原来只有一条机械要求,而且只管「零命中」。这个 PR
在它正下方加一行,把要求延伸到**别人会据此行动的非零读数**:写下单位(是文件数?命中数?行数?),并回答「什么本来会让它不是这个值」;另外,递给
dev 当线索的读数一律标明「这是线索不是答案」。自己用完就丢的探针不欠这笔税 ——
卡面和分诊席都明确拒绝「每个数字都要配控制」,这一行也拒绝。付账在本文件内:第 51 行退休(它第三句只是把 :45
的零命中规则在查重场景重说一遍),它另外两句分别并进 :80 和 :111,行数 151 → 151。

**为什么改**:一个班次里量到八个实例,五个是非零读数,其中六个已经写进了卡、交接简报或派工单 ——
两条非缺陷被当工作项交接、一次「几乎没变」实际是 46+14 行含一条方向反转的规则、一张卡的方案被低估一个数量级、一条方向错的线索递给了
dev(只因为派工单写了「这是线索」才没造成损失)、`git grep -c | wc -l` 数的是文件报了 5 实际
9。这些不是「可能会出错」,是已经发生的事故链。

**风险与代价(含回滚)**:零代码、零脚本、零发布物,16 个派生门禁加仓级 lint
全绿。真实代价是每条进卡/进简报/进派工单的读数多写一句话;拒绝扩大到每个数字,就是为了不把便宜探针压死。回滚 = revert 本 PR
的一个 commit,文本回到今天的样子。⚠️ 一个已知缺口请你知情:按 SKILL.md :44 的规定,一条规则改一处、另一处必须同 PR
同改,而 SKILL.md 眼下排在 PR objectstack-ai#18666 / objectstack-ai#18679
后面串行,所以这一趟只落了核心条款这一半;另一半由席位排队补上。没有任何门禁会告诉你这件事 —— 这本身也写进了待立卡清单。

**席位意见**:(留空,席位定稿)

**你要做的**:按四件套流程批准本 PR(规则层,等你的字)。合并后席位负责把 SKILL.md 那一半排进队列。

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…and skills owe it on every round, other lanes owe none (objectstack-ai#18903)

Fixes objectstack-ai#18536

Clause-②: no

## What this lands

The maintainer's lane rule, restated by the director record on the card
(comment 5717169811), quoted verbatim and untranslated:

> 「曾经要求只有 spec 和 skills 需要 fable,其他 opus 就够了,理论上其他车道不需要契约复审」「即使项目经理跑在
opus 上,也可以支持起 fable 子 agent 复审,这样最快。除非子 agent 用 fable 启动失败,也就是没有 fable」

carried into the governed text and the two machine readers:

1. **Spec and skills lanes** — every delivered round gets the contract
review at `CONTRACT_REVIEW_TIER`: in-seat when the seat's served tier is
that tier, otherwise by the at-tier review subagent the seat spawns (the
09-17 route stays). The record is the same-shape comment with
`Served-tier:`, on the PR or the card.
2. **Every other lane** — no contract review. The clause-② limbs (path
`packages/spec/src/**`, declaration `Clause-②: yes`) survive unchanged
and now answer the LANE question: a limb hit is spec-lane work and moves
there; a `Clause-②: no` PR outside the contract surface lands on the
three pre-checks and the gates. No default-tier self-review record is
demanded, and no other lane spawns the at-tier subagent.
3. **Tier unavailable** (the at-tier subagent cannot start) — the review
cannot be produced: the PR stays draft and out of the queue, and the
maintainer's own review is the only bypass, by their word each time.

The lane key is the 2026-09-10 key restored (PR objectstack-ai#17294) with the
2026-09-17 subagent route kept (PR objectstack-ai#18511); the 2026-09-16 tier key (PR
objectstack-ai#18363) is superseded. Not a byte-revert: both spec AND skills owe the
review, and 「余席默认档自审加门禁」 is gone — other lanes owe nothing.

## Charter (commit 1) — net 0 lines per file

| file | before → after | ratchet ceiling |
|:--|:--|:--|
| `.claude/skills/pm-dispatch/SKILL.md` | 812 → 812 | 812 |
| `references/contract-review.md` | 60 → 60 | 60 |
| `references/core-rules.md` | 151 → 151 | 151 |

Every edited line is at most 120 bytes; `check:pm-skill-ratchet` is
green on `bc0c2ec41`. Rule text carries no issue numbers
(`check:pm-skill-id-lint` green); the four-axis frame block is untouched
(`check:skill-frame-sync` / `-freshness` green).

**SKILL.md** — five in-place rewrites, one added line, one retired line:
- :512 强制条款② — 「达档复核归派发席席内」 → 「命中即 spec 车道的活」.
- :522 席位档策略 — 「按实测档:达档席内审;未达档席 ⛔ 不自审,起隔离达档子代理转录核档采信」 → 「按车道:spec 与
skills 席达档席内审;未达档 ⛔ 不自审,起隔离达档子代理」 (the transcript-verified tier of the
subagent stays stated in contract-review.md :54).
- :636 入队闸门 — 「无席内条款②复核 PASS 在案」 → 「无达档条款②复核 PASS 在案」; the limbs at :637
/ :638 are untouched.
- :639 交付后复核 — 「归派发席:达档席内审,未达档循保险丝起子代理;记录 = 同形评论落 PR 或卡」 → 「只 spec 与
skills 车道欠,每轮达档:席内审或起子代理;双肢命中即 spec 车道」 (the record's shape lives in
contract-review.md :27–:29).
- :640 ADDED (rule 3, where the enqueue gate lives) — 「子代理起不来 ⇒ 复核缺席,PR
留 draft 队列外等档;唯一旁路是维护者亲审,逐次为准。」
- :646 pointer — 「席内复核的适用面」 → 「契约复核的适用面」.
- RETIRED, paying for :640 — the former :672 「报告席记条款②默认档 FAIL
率入复审清单;超改制前达档史值 ⇒ 决策卡交维护者定回退。」 Reason: it meters the FAIL rate of
DEFAULT-TIER clause-② reviews, and under rules 1–2 no lane performs one
(spec and skills review at tier; other lanes review nothing), so the
metric's population is empty. It sits outside the claim's declared
SKILL.md bands; it is the one tier-keyed line in the file the ruling
empties, and paying in-file required it. Re-wrap is not currency: no
line was re-flowed.

**contract-review.md** — thirteen in-place rewrites:
- Title and :23 — 「(席内)」 → 「(按车道)」.
- :9, :11, :12, :14 — 「席内契约复核 / 席内复核」 → 「达档契约复核 / 达档复核」: the review is
at tier wherever it happens, and "in-seat" was the 09-16 key.
- :25 — 「交付后收集复核当轮席内完成;借复核不移卡,新 spec 工作恒归 spec 席」 → 「交付后收集复核当轮完成;只 spec
与 skills 车道欠,新 spec 工作恒归 spec 席」. The "borrow the isolated review" route
is what rule 2 closes for other lanes.
- :26 — 「按档位:达档席内审契约增量;未达档 ⛔ 不自审,走保险丝路;豁免仅独立性件与保险丝」 → 「按车道:spec 与 skills
席审契约增量;达档席内审,未达档 ⛔ 不自审,起达档子代理」.
- :27 — 「达档与默认档同形」 → 「席内与子代理同形」: there is no default-tier record any
more; one shape holds between in-seat and subagent (the two scripts'
quotations of this line are updated in the same PR).
- :32 — the independence case → 「独立性件(契约真分叉、dev
挂旗)与保险丝只免席内审,不免复核:起隔离达档子代理」. This is the 「豁免仅独立性件与保险丝」 rewrite the
ruling asked for: the independence case and the fuse exempt the seat
from IN-SEAT review only, never from the review's existence. The former
third trigger 「派发后的跨车道面(含 spec)」 is lane routing now (:25).
- :40 landing pre-check ① — 「席内条款②复核 PASS 在案 …(档位按实测)」 → 「达档条款②复核 PASS
在案 …(spec、skills 每轮)」.
- :50 the fuse — 「管每个出条款②裁决的席 … 未达档 ⛔ 不自审」 → 「只管 spec 与 skills 席的条款②复核」
(the 不自审 clause stays at :26).
- :52 — 「至席内复核完成」 → 「至达档复核完成」.
- :53 — 「标签原样留置,队列外等待是安全态」 → 「起不来即无复核,标签原样、队列外等档」 (rule 3 on the fuse
side).

**core-rules.md** — one rewrite: :112 「契约卡达档复核归派发席」 → 「契约复核只 spec、skills
欠」. Trace by REST `GET /pulls/N/files`: PR objectstack-ai#18363 (09-16) touched
SKILL.md, contract-review.md and platform-readings.md only, so the 09-16
re-key never landed in core-rules.md; :112's tier key came with PR
objectstack-ai#18511 (09-17), replacing PR objectstack-ai#17294's 「归 spec 席」. :122 「`references/`
席内达档复核后入队」 is left as the mirror of SKILL.md :625 (see acceptance
notes).

## Machine side

**commit 2 — `scripts/pm/dispatch-gates.mjs`.** The clause-② note and
the suspect tail that `--tier` prints (quoted into claim comments) said
「spec seat; default-tier build」 and 「in the spec seat」 — the 09-10 seat
key, which PR objectstack-ai#18363 never re-keyed. They now name the spec and skills
lanes, the in-seat-or-subagent route, and 「a hit outside those lanes is
spec-lane work and moves there」; the docblock above
`MANDATORY_TIER_GLOBS` carries the rule. Four self-test pins hold both
renderings to the lane key and refuse the two retired spellings.
`--self-test`: 1852 cases pass (baseline on `0b31d90`: 1848).

**commit 3 — `scripts/pm/check-clause2-carriers.mjs`.**
`needsRecordRead` — C6's population gate and the sweep's read budget —
owed a record only in the completed state (a cleared `yes`), so a
spec-lane `Clause-②: no` round read 0 with no record on its head:
exactly PRs objectstack-ai#18530 / objectstack-ai#18529, the card's measured pair. Now:
- `LANES_OWING_REVIEW` (`domain:spec`, `domain:skills`, frozen) and
`laneOwesReview(pair)`, read off the CARD's `domain:*` labels;
unreadable labels stay UNJUDGED through the existing labels gap.
- Population: the completed state (unchanged) OR a declared `no` on a
spec/skills card (new). A `no` anywhere else still owes nothing —
pinned.
- C6's row on a spec/skills `no` round with no record: exit 4; remedy =
the lane's review at tier (in-seat or by the at-tier subagent), with the
unavailable-tier state and its one bypass named.
- A cleared `yes` OUTSIDE the two lanes keeps its row and its exit 4
(the `yes` is a limb hit, and limb-hit work is owed), but its remedy is
lane ROUTING: re-lane the item to `domain:spec` (`pm:retriage`, or split
the contract work to a spec-lane card or PR per 「新 `packages/spec` 工作恒由
`domain:spec` 席收口」), or correct a false `yes` with a
`Clause-②-correction:` comment — never a default-tier self-review, never
an at-tier subagent from that lane.
- The C6-RECORD note prescribes the clear-citation only where a clear
exists; on a spec/skills `no` round with its record it says the lane
owes the record and it exists.
- New floored battery, 34 cases (floor 30); roster floor 32 → 33.
`--self-test`: 977 cases pass (baseline 941).

Deviation from the dispatch's suggested case (c) — a `yes` pair on a
`domain:cli` card as 「not owed as a record, plus a note」 at exit 0 —
implemented instead as owed at exit 4 with the routing remedy. Reasons:
contract-review.md :42 promises 「0 = … head 上有记录」; a cli seat clearing a
`yes` pair and landing it from that lane is never a legal workflow under
rule 2 (the work 「moves there」), so an exit-0 note would be the
0-with-a-message the file's own header bans; and the row's exit is
unchanged from today (only the remedy text moves), so no legal workflow
is re-blocked. The four-axis reading is in the report's
`open_questions`; the PR is draft for the maintainer's word either way.

## Gates (run on `bc0c2ec41`, the final commit)

`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 46 families. 45 ran with exit 0
(each captured redirect-then-`$?`), among them `check:pm-skill-ratchet`,
`check:pm-skill-id-lint`, `check:skill-frame-sync`,
`check:pm-governed-prose`, `check:pm-clause2-carriers`,
`check:declared-population-live`, `check:pm-half-states`,
`check:nul-bytes`. `check:doc-formula-expressions` first exited 3 —
PREREQUISITE NOT MET (`@objectstack/formula` / `@objectstack/lint` not
built; nothing measured) — and reruns green after `turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint` under the
verify lock (22 + 9 + 14 examples judged clean).
`check:pm-dispatch-gates` (430–450 s) was still running detached when
this body was written; its verdict and the `--ran` reconciliation are in
the `os-dev-report` comment on objectstack-ai#18536. Both edited scripts' own
`--self-test` pass (above). The four package tests that mention
`dispatch-gates.mjs` do so in docblocks only and read nothing from it,
so they are not owed. The derivation printed a STALE TREE warning (the
tree is behind an `origin/main` that moved during the run); the PM's
re-derivation after the report reads the true list.

`skip-changeset`: nothing published moves — `.claude/**` and
`scripts/pm/**` ship in no package's `files[]`.

## Acceptance notes

Lines outside this card's declared file surface that carry seat or tier
wording — reported, not edited (承接者: the skills seat's next SKILL.md
round; the hot-file queue behind this card holds objectstack-ai#18743 · objectstack-ai#18755 ·
objectstack-ai#18665 · objectstack-ai#18469 PR-B · objectstack-ai#18489):
- SKILL.md :231 「派发后发现的跨车道面(含 spec)不移卡,认领席借契约复审档隔离复核」 and core-rules.md
:62 (its mirror). The "borrow the isolated at-tier review" route is what
rule 2 closes for other lanes (no other lane spawns the at-tier
subagent). The ruling's 「moves there」 and SKILL.md :234 「已派发卡 ⛔ 不因触 spec
转席」 reconcile as "the contract WORK moves to the spec lane; the card is
not re-seated", which is how contract-review.md :25 now reads. Suggested
rewrite of :231, same byte budget: 「认领即跟到 MERGED:派发后发现的跨车道面(含
spec)不移卡,契约面工作交 spec 车道达档复核。」
- SKILL.md :608 「技能面 hunk 须由契约复审档的席复核,档外席先交 skills 席」, :623 「由本席按达档自审」,
:625 「经席内达档复核后 ready → 入队」 and core-rules.md :122 「`references/`
席内达档复核后入队」: consistent with rule 1 read as "the skills lane's review at
tier, in-seat or by subagent"; the word 席内 there is the 09-16 spelling
and could be read as in-seat-only.
- `references/lanes/spec.md` :19–:33 and `references/lanes/skills.md`:
no contradiction found; `lanes/skills.md` :13 「契约复核归派发席席内」 is ownership
wording (the seat owns the record it adopts) and stays true.
- The follow-up the ruling assigns to the lane seats after this lands,
not to this card: re-read the `needs:contract-review` carriers hung
outside the spec/skills lanes (the director's ledger ⑫) and re-lane or
strip each.
- Sweep-mode cost: `check-clause2-carriers.mjs` without `--pair` now
buys the PR thread for every spec/skills-lane `no` pair too (one read
per PR, cached per PR); the budget paragraph in the file's header is
unchanged in shape.

## 维护者速读(草稿)

**改了什么**:把契约复核的归属重新按「车道」写回章程:只有 spec 与 skills
两条车道的每一轮交付都要过契约复审档的复核——席位达档就席内审,不达档就起达档子代理;其余车道零契约复核,条款②命中即 spec
车道的活;达档子代理起不来时 PR 留 draft、队列外等档,唯一旁路是您亲审。三份章程文本行数不变(812 / 60 /
151),两个机读脚本(`--tier` 的提示行、`--pair` 的复核记录人口)同步改成按车道判。

**为什么改**:9-16 那次把「只在 spec 席」改成了「按席位实测档」,席位名单没了,于是同一张 `Clause-②: no` 的
spec 车道 PR 在两条细则下答案相反(objectstack-ai#18536 的两种读法),而账号级 429 让「等档位」在两种读法里含义完全不同。您 9-17
的裁决把车道规则说回来了,本 PR 只是把它落到文本和脚本上。

**风险与代价(含回滚)**:`--pair` 从此对 spec/skills 车道的 `no` 轮也要求 head 上有复核记录,没有就退
4——这正是 objectstack-ai#18530 / objectstack-ai#18529 该有的读数,但意味着这两条车道的 `no` 轮在记录落下前都不能入队;其它车道不受影响,`yes`
挂在别的车道上的旧读数(退 4)不变,只是补救措施从「自审」改成「改道 spec」。回滚 = revert 这三个
commit,文本与脚本一起回到 `0b31d90`。

**席位意见**:(留空)

**你要做的**:确认本 PR 是否如实落了您的车道规则,是则合并;合并后各车道席按裁决去清理挂在 spec/skills 之外的
`needs:contract-review` 载体。

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

---------

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/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants