skills(pm-dispatch): a reading another agent acts on owes its UNIT and a counterfactual — the discipline guarded a ZERO only - #18809
Conversation
… NON-ZERO
The discipline makes exactly one mechanical demand of an instrument
(core-rules :45) and it guards a zero only. Eight measured instances in
one shift -- six on the card, two more the triage seat measured on
itself -- were readings that were NON-ZERO, or zero-and-true, and every
one of them had already reached a card, a handover brief or a dispatch
where another agent acted on it.
New row, beside the zero rule it generalises: a reading another agent
will act on owes its UNIT and an answer to "what would have made it NOT
this value"; a reading handed to a dev as a lead is marked as a lead,
not an answer. Scoped by construction -- a seat's own use-and-discard
probe owes nothing, which is the boundary the card and the triage both
drew.
Paid in file, ratchet 151 -> 151: row :51 is retired. Its third clause
("triage dedupe zero needs a control word") repeated :45's general zero
rule; its two live clauses merge into :80 (the filer/triage division of
labour) and :111 (reading a dead dev before reclaiming a claim).
Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu
Co-authored-by: Claude <noreply@anthropic.com>
Round 1 landed the rule in references/core-rules.md :46 only. The protocol's own text makes core-rules a subset of SKILL.md (:43) and requires a rule changed in one to change in the other in the same PR (:44), so the digest was stating a rule the skill did not. This commit adds the twin to the reading-discipline block, directly under the zero rule it generalises (:163-:164), byte-identical to core-rules :46: a reading another agent will act on carries its unit and answers what would have made it not this value; a reading handed to a dev as a lead is marked a lead, never an answer. A second line under it carries the two clauses round 1's one-row budget cut: the negative boundary (a probe a seat uses and discards owes nothing) and the discharge form of the counter-question (the answer is a verbatim artefact or a named counterexample). It is a refinement of the twin, so it has no core-rules counterpart to owe. Paid in file, ratchet 812 -> 812, no re-wrap, no rule deleted: - the claim-section line "file surface declared to area level, every dispatch; branch name carries the issue number" is retired -- the first clause is the parallel-discipline line verbatim, and the claim template's fixed File surface / Branch lines already spell the other two; - the collect-section line "a replay is not re-accepted; a notification's arrival does not read as alive nor its absence as dead" is retired -- the replay rule above it already ends on the replay being logged, and the probe line already states that a completion notification is unreliable and its absence proves nothing. Neither retired line has a counterpart in core-rules, so the subset relation holds in both directions after this commit. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <noreply@anthropic.com>
维护者速读(终稿)改了什么:读数纪律原先只有一条机械要求,而且只管「零命中」。这个 PR 在它正下方各加一行、两处同改: 为什么改:一个班次里量到八个实例,五个是非零读数,六个已经写进卡、交接简报或派工单并被人据以行动 —— 两条非缺陷被当工作项交接、一次「几乎没变」实际是 46+14 行含一条方向反转的规则、一张卡的方案被低估一个数量级、 风险与代价(含回滚):零代码、零脚本、零发布物;两轮派生门禁 16 + 19 个全绿,仓级 lint 全绿。真实代价是每条进卡、进简报、进派工单的读数多写一句话;明确拒绝扩大到每个数字,以免压死便宜探针。与在飞的 PR #18666 / #18679 在 SKILL.md 上无一行重叠,任意先后都能落。回滚 = revert 本 PR 的两个 commit。 席位意见:通过。规则本身是卡面与分诊都认的边界(只约束「他人据以行动的读数」),两处同改把 :43 的子集关系维持住了,付账是真删重复内容而不是改换行。 你要做的:批准本 PR(规则层,等你的字)。合并后无后续动作;核心条款上排在后面的是 #18489(孪生行清单)。 Generated by Claude Code |
Fixes #18798
Clause-②: no
Governed rules layer, one file, line-neutral:
.claude/skills/pm-dispatch/references/core-rules.md151 → 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):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
startswith("Blocked-by:")over issue bodies**Blocked-by:**lines are invisible to itBlocked-by:in a comment moves the number not at all (cost: two non-defects entered a handover brief as work items)grep -E '^[-+][^-+]'over a charter diff-, so its changed diff lines read--and the pattern excluded thempackage_version_idgrep handed to a dev as a leadgit grep -c … | wc -lto count call sites#18791grep — unit right, control lit, count truefixstring, in the same output)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 #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 #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.
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:devis SKILL.md :174's own word for the subjectSo 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.
git grep -l 'core-rules'overscripts/ .github/ package.jsonreads 2 files —scripts/pm/check-skill-line-ratchet.mjs(counts lines only) andscripts/pm/dispatch-gates.mjs(derives gate families). Lit controls on the same instrument and corpus:platform-readingsreads 7 files,SKILL.mdreads 40 files; absent control (a nonsense token) reads 0, exit 1. A second instrument agrees:git grep -n '核心条款'overscripts/ .github/reads exactly one line — a COMMENT atcheck-skill-line-ratchet.mjs:1126quoting the rule — with 受管面 lit as control in the same corpus.references/core-rules.md,是本文的子集」, SKILL.md :44 「一条规则在本文与核心条款一处改动,另一处同 PR 同改」, andcore-rules.md:3 「本文不新增规则」. A rule that exists in core-rules and not in SKILL.md breaks the declared subset relation.core-rules.mdstates 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-syncwas 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
check-validity-recognisercase) would be inside the demand, while a seat's own discard probe stays outside it by design. The uncovered half is the shape finding(skills): a lit control certifies the INSTRUMENT, not the QUESTION — a live grep, its lit control and its absent control all fired while answering something the tool structurally cannot see #18755 names — a live instrument, every control satisfied, pointed at a question the instrument's DOMAIN cannot answer. That card is not addressed here.platform-readings.mdresting on a falsified rationale; different file, different instrument, nothing to fold. Not addressed here.platform-readings.md:226–:227 are untouched ([finding] a dev container can create a remote branch but cannot delete one (both channels 403), so a "probe before you write" instruction manufactures a permanent stray branch — one is on origin now and defeats the AGENTS.md claim pre-check #18774 is on that file);SKILL.md:163 is untouched (serial, above).Verification, head
46b7bd6a46main(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).git diff --stat 331462d11f HEAD→1 file changed, 3 insertions(+), 3 deletions(-).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree with no hand-fed path list → 16 families. All 16 run in the foreground, each exit code captured by redirect then$?: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-expressionsfirst answered exit 3, PREREQUISITE NOT MET (@objectstack/formulaand@objectstack/lintunbuilt) — not a finding and not a measurement; both packages were built underscripts/pm/os-verify-lock.sh(「VERDICT command-exit 0 · held the lock 1s · waited 0s」) and the gate then answered exit 0.pnpm check:pm-settings-deny-roster(its roster sits under.claude, where this path is) exit 0, andnode scripts/check-skills-token-ratchet.mjsexit 0 (「34 authored bundle file(s) within their ceilings」 — the published catalog is untouched).pnpm lint(eslint . --no-inline-config): exit 0, no output.pnpm check:nul-bytesexit 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.dist. The before/after measurement is the diff plus the ratchet pair above.Acceptance notes
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」.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.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 #18666 / #18679 后面串行,所以这一趟只落了核心条款这一半;另一半由席位排队补上。没有任何门禁会告诉你这件事 —— 这本身也写进了待立卡清单。
席位意见:(留空,席位定稿)
你要做的:按四件套流程批准本 PR(规则层,等你的字)。合并后席位负责把 SKILL.md 那一半排进队列。
Generated by Claude Code