Repository navigation
docs(skills): bind three evidence controls onto the retirement playbook's liveness step - #17566
Conversation
…ok's liveness step A "dead key" premise is only as good as the reading offered for it. The evidence step bound a ledger `dead` verdict as an input rather than a proof, the four-condition `live-elsewhere` discipline and the fourteen-keys record — but it put no control on the census, did not require a cited `cross-repo` row to be re-read at the moment it is used as an argument, and did not separate "nobody authors it here" from "no code reads it". Three rules land beside those bindings, at :59-:61: - a zero-authored-instances census runs a known-live sibling key as its control and reports both readings; a control scoring the same zero measured nothing; - a `cross-repo` row cited as an argument is re-verified at citation — path and lines — and drift reads as "re-cite", never as `dead`; - "zero authored instances" is not "no code reads it"; a retirement needs the second. Paid by density inside the file at 337/337 (ceiling unchanged): the lone-`dead` restatement in the `live-elsewhere` item, the "timestamped claim" clause in §1, and the `view.form.data` anecdote's plumbing tail. Every deleted fact still lives in the file, named line by line in the PR body's payment ledger. Claude-Session: https://claude.ai/code/session_01YKEjmbYNvYWJvWGSWx26zK Co-authored-by: Claude <noreply@anthropic.com>
维护者速读改了什么 —— 退役 playbook( 为什么改 —— 同一天派出的两张退役卡前提都实测为假:#15180 要删的键服务端在读(分诊席独立复测后关 not planned);#15184 要删的键姊妹仓 风险与代价(含回滚) —— 纯协议文本,无代码、无门禁、无发布面;棘轮两行读数本席在 head 席位意见 —— 通过。三处删减本席逐句读过,没有事实离开文件而无家可归。受管面( 你要做的 —— 一个动作:人工合并本 draft PR(付款表在 PR 正文;若您认为删掉的某句该留,评审里说一句)。 skills 席,session Generated by Claude Code |
… own subject or the zero is void (objectstack-ai#17837) The zero-hit rule bound the control to HIT, not to be SCOPED to the claim: a control can prove the instrument works while pointed at a different corpus, path shape, module/package boundary or quoting, and the zero then comes back as a reassuring negative that survives review (three misses in one hotcrm shift, two more measured by the triage seat). The rule now says the control shares the claim's own subject and the target's failure mode (a phrase that wraps across lines needs a control that wraps the same way), or the zero is VOID rather than negative. Landed in all three carriers of the discipline in one PR, per SKILL.md 「一条规则在本文与核心条款一处改动,另一处同 PR 同改」: `pm-dispatch/SKILL.md` :161-:162, `references/core-rules.md` :45, and the dev-side reading in `.claude/agents/os-dev.md` :54. Every file stays at its ratchet ceiling; the payment is density inside the same section, itemised below. Not a new gate. Part of objectstack-ai#17569 ## Acceptance notes **Premises (re-taken on `origin/main` `0cd841a16` at 2026-09-12T10:03Z, after `git fetch origin main`):** 1. SKILL.md :161 read 「- 零命中必须用确定存在的邻近词反查,否则零命中不成立。」 (78 bytes); file 812 lines, CEILINGS row 812, `MAX_LINE_BYTES = 120` — holds. The ratchet script lives at `scripts/pm/check-skill-line-ratchet.mjs` (the dispatch word spelled it without the `pm/` segment; same script). 2. core-rules.md :45 read 「- 零命中必须用确定存在的邻近词反查才成立;仓不可达时 ⛔ 不得当成查过且干净。」 (110 bytes); 151 lines at ceiling 151 — holds; it IS the rule's core-rules mirror and is edited here. 3. os-dev.md :54 read 「 - 空结果要同会话一个已知必中的控制词答了命中才算读数。」 (83 bytes); 403 lines at ceiling 403 — holds. 4. SKILL.md :175 and core-rules.md :51 are the dedupe-control siblings — left byte-identical (the new clause is general; no cross-reference needed). 5. Open-PR scan re-taken at 2026-09-12T10:07Z over all 24 open PRs' file lists (REST `pulls/{n}/files`): zero hits on the three files. Control, same corpus and same regex family: 5 of those PRs touch `.claude/` paths (objectstack-ai#17828 and objectstack-ai#17803 on `platform-readings.md`, objectstack-ai#17823 `rest-channel.md`, objectstack-ai#17809 a hook, objectstack-ai#17515 `decision-analysis.md`) — the zero is scoped. `origin/main` moved 3 commits (to `51b024a16`) during the run; none touched the three files. 6. Sibling clause from PR objectstack-ai#17566 (spec-property-retirement SKILL.md :59) read: 「零编写实例普查要并跑一个同族已知存活的键作对照,两读数都报;同得零即没测出。」 — the new wording keeps that vocabulary (a control shares the claim's family/subject; a control that measures nothing voids the reading) rather than introducing a second idiom. 7. The card quotes a dispatch-template sentence 「pair every zero with a control word that must hit」 as a second carrier inside SKILL.md. On `origin/main` no such sentence exists (grep for `must hit`, `pair every zero`, `control word` over `.claude/**` and `scripts/pm/**` returns zero; control: `零命中` hits :161, :542, :724) — the template left in the rules-only rewrite. No second carrier to edit. **Edited lines and byte counts (each ≤ 120):** | file | line | bytes | text | |:--|:--|--:|:--| | SKILL.md | :161 | 113 | 「- 零命中须用确定存在的邻近词反查;控制词须与主张同主体,否则该零作废,不是阴性。」 | | SKILL.md | :162 (new) | 114 | 「- 同主体 = 同语料、同路径形、同包界、同引法、同失效形态:跨行短语配跨行控制词。」 | | SKILL.md | :165 (merged) | 105 | 「- 时间戳形如 `YYYY-MM-DDThh:mmZ`,树读数另带 ref 或 tip;无时间戳的读数按未取处理。」 | | core-rules.md | :44 | 112 | 「- 核验 main 用 fetch 后的 `origin/main`,⛔ 不用共享检出树;仓不可达 ⛔ 不当查过且干净。」 | | core-rules.md | :45 | 113 | 「- 零命中须用必中词反查,且与主张同语料/路径形/包界/引法/失效形态,否则该零作废。」 | | os-dev.md | :54 | 113 | 「 - 空结果要同会话已知必中、与主张同主体同失效形态的控制词答了命中才算读数。」 | **How density was paid (all inside the 平台读数纪律 section of each file):** - SKILL.md 812/812: the clause takes two lines (:161-:162, +1); the two timestamp lines (:164 「时间戳形如 …,树读数另带 ref 或 tip。」 and :165 「无时间戳的读数是格式错误不是现值,读者按未取处理。」) merged into one (−1). Dropped words: 「是格式错误不是现值,读者」 — the operative half 「按未取处理」 survives, matching core-rules' own wording of that rule. - core-rules.md 151/151: no two neighbouring lines in the section merge under 120 bytes, so the clause is one line (:45) with the five sames inline; the 仓不可达 half of the old :45 moved onto the `origin/main` line (:44). Dropped words: 「确定存在的邻近」 → 「必中」, 「时」, 「不得当成」 → 「不当」, 「的工作树」 → 「树」, 「先」. The wrapped-phrase example is carried by SKILL.md only (terser register). - os-dev.md 403/403: one line, byte-for-byte replacement of :54 (83 → 113 bytes); the 范围 list is otherwise untouched. **Frame block pin:** `sed -n '734,755p' .claude/skills/pm-dispatch/SKILL.md | md5sum` = `3327d02c56f8a0eca88569dad2270f32` before and after (net line count above it is 0, so the block did not move). **Gates (derived with `node scripts/pm/dispatch-gates.mjs --commands` in the worktree, 18 commands; reconciliation via `--ran`: 「18 derived, 18 run, 0 NOT-MEASURED, 0 UNRUN」):** all 18 exit 0 at head `9e15e315f`. `pnpm check:pm-skill-ratchet` verdict lines: 「SKILL.md is 812 lines (ceiling 812; headroom 0)」 · 「core-rules.md is 151 lines (ceiling 151; headroom 0)」 · 「os-dev.md is 403 lines (ceiling 403; headroom 0)」. `pnpm check:skill-frame-sync`: 「the one declared copy of the decision frame is internally coherent … 4 axes」. `pnpm check:nul-bytes`: 「OK (scanned 8465 text file(s) …; no raw ASCII control bytes)」. `check:doc-formula-expressions` first answered exit 3 PREREQUISITE NOT MET (`@objectstack/formula` and `@objectstack/lint` unbuilt) — not a measurement; built both under the verify lock (VERDICT command-exit 0, 169 s) and re-ran: exit 0. **Changeset:** `.claude/**` publishes nothing from any released package (`node scripts/check-changeset-fixed.mjs` exit 0; no `files[]` of any package covers `.claude/`) — `skip-changeset` applied by additive POST and read back. **Deferred rider (⛔ not in this PR):** the card's two `references/platform-readings.md` rows (`git grep -- 'a/**/*.ext'` skips files directly under `a/`; `grep -c $'\x00'` is not a NUL probe) wait on that file's serial behind PR objectstack-ai#17828 and PR objectstack-ai#17803. objectstack-ai#17569 stays open for the rider PR; hence `Part of`, not a closing keyword. **Governed surface:** `.claude/**` — this PR stays a draft at the human terminal; nothing here flips it ready or arms auto-merge. ## 维护者速读(草稿) **改了什么:** 「零命中必须配控制词反查」这条规则,在三处载体(pm-dispatch SKILL.md、核心条款 core-rules.md、os-dev 开发 agent 定义)各加一句:控制词必须与主张同主体 —— 同语料、同路径形、同包界、同引法、同失效形态 —— 否则这个零作废,不算阴性读数。三个文件行数不变,各自仍顶着 ratchet 上限。 **为什么改:** 一个班次里三次「控制词命中了、零仍是假的」:控制词证明工具能用,却没证明工具对准了主张。旧文只要求控制词「命中」,不要求它「与主张同一件事」,于是错误读数反而带着安心感回来、过了复核。 **风险与代价(含回滚):** 纯文本规则,不加门禁、不加脚本;付费方式是同节内合并两行时间戳规则(SKILL.md)与把「仓不可达」半句挪到 origin/main 那一行(core-rules)。回滚 = revert 这一个 commit,无生成物、无依赖。 **席位意见:** (留空,席位定稿成评论) **你要做的:** 读三处新句是否表达了你要的判据;确认后人工合并(governed surface)。rider 半张(platform-readings 两行)另开 PR,本 PR 不关卡。 --- _Generated by [Claude Code](https://claude.ai/code/session_01MCLBsUgfykL74aU716rzVK)_ Co-authored-by: Claude <noreply@anthropic.com>
Fixes #17553
Two retirement rounds in one day rested on a "dead key" premise that measured
false. The retirement playbook's evidence step already bound the ledger side —
a
deadverdict is an input, never a proof; the four-conditionlive-elsewherediscipline; the fourteen-keys record — but it bound nothingabout the reading a seat offers for deadness. Three rules land beside those
bindings, in the file's own register and voice.
The three rules as landed
.claude/skills/spec-property-retirement/SKILL.md, appended to section 0'spre-flight checklist immediately after the
live-elsewhereitem:- [ ] **零编写实例普查要并跑一个同族已知存活的键作对照**,两读数都报;同得零即没测出。- [ ] **拿 cross-repo 行当论据,就当刻重核路径与行号**:漂了读作重新取证,⛔ 不是 dead。- [ ] **「零编写实例」≠「没有代码读它」。** 前者答的是示例应用,后者才是退役的证据。(The table renders the two inline code spans of :60 as plain words so the row
survives the body sanitizer; the file itself carries them as code spans.)
Why section 0 and not section 1. Section 0 is the pre-flight checklist —
「动手删之前:删除是正确的处置吗?」 — and every item in it is a question about
whether the disposition is right, answered in one or two lines. All three rules
are exactly that: tests a seat applies to its own evidence before it commits
to a removal. Section 1 ("裁判是构建,不是台账") argues one thesis in prose and
carries no checklist; three
- [ ] **…**items appended there would have neededa list of their own. The
live-elsewhereitem is the nearest neighbour bysubject, so they sit directly under it.
They sit beside the existing bindings, not on top of them:
:55-:58stillcarries the four-condition cross-repo discipline and its
elsewhere.mts/README provenance,
:65still carries 「台账的dead裁定是删除的输入,不能替代构建自己的证明」, and
:71still carries the fourteen-keys record.Payment ledger — 337 lines in, 337 lines out
The ceiling is 337 with zero headroom, so each added line is bought by deleted
content, never by re-wrapping. Three lines added, three lines of content
deleted, all three inside the declared region.
live-elsewhereitem: 「单读dead会批准一次删除,而它删掉的是姊妹仓某道门的输入。」 (88 B)deadread would authorise a deletion; the casualty is a sibling repo's gate inputdead裁定是删除的输入,不能替代构建自己的证明」 (:65) states that adeadread alone is not authority:56「带日期的verifiedAt、180 天过期」 and:70「附真实证据与verifiedAt」 — and the new:60now turns on that clock explicitlydefineForm往每个*.form.ts写data: ...,metadata-protocol把它喂给 metadata-admin 管线。」 (146 B)view.form.dataview.form.data挂在工作清单上是 dead…而删除打断了gen:schema」 plus its correct response.:309in the same file independently names 「一个defineForm会写的键」, and the very next sentence instructs the reader to put the chain in the ledger entry's own evidence stringNothing outside the region moved: the four diff hunks span old lines 55-71
only, and the file is byte-identical elsewhere.
order said the 120-byte line cap does not bind this file because "7 lines
already exceed it". Measured:
MAX_LINE_BYTES = 120inscripts/pm/check-skill-line-ratchet.mjsdoes cover this file, and the 7over-120-byte lines are all structurally exempt classes — table rows at
:86-:88,:101,:126-:127and a blockquote at:117. Every prose line inthe region is under 120 bytes today. The three new lines were therefore written
to 120 / 116 / 120 bytes, which satisfies both readings; no existing line was
reflowed. The order's other reading — "an over-wide line elsewhere in the same
region" as a payment source — has no referent: no line in
:50-:72exceeds 120bytes.
The census control, re-measured on this branch
The card's decisive control, re-run once as the premise check, on
ad715aca(git grep -lE -- 'KEY:' examples apps | wc -l):Identical to the card's reading on
6e3462df47.hiddenFieldsis gradedliveinpackages/spec/liveness/view.jsonwith a cross-repo evidence stringnaming its own filter in objectui's ListView — indisputably live — and it
scores the same zero as
fieldOrder.columnsat 31 proves the instrumentworks. The premise holds.
The one judgement, on the four axes
The judgement here is where the three rules sit and what pays for them.
实际业务需求: measured, not speculative — two dispatched rounds in one day
turned on exactly these three gaps, and the census control is one command whose
reading is reproduced above; the pre-flight checklist is where a seat actually
stands when it decides, so a rule placed there is read at the moment it binds.
项目长远合理性: the rules tighten the evidence contract at the point of
authorship rather than adding a consumer-side accommodation; no new gate, no new
ledger field, nothing to keep in sync. 防 AI 写代码犯错: this is the
AI-authoring axis at its sharpest — the failure mode is an agent reading a
cited path, finding it deleted, and inferring "dead", so
:60makes drift readas 「重新取证」 and names the wrong inference explicitly (⛔ 不是
dead); acensus with no control is the same shape one layer down, and
:59refuses it.创业阶段不扩散需求: paid entirely from inside the file at a flat 337 lines
with no ceiling raise and no new surface — three lines of protocol text against
a method that has already carried a maintainer's signature onto the deletion of
a working channel. The axes do not conflict here; the only tension is density,
and it is settled by the ledger above rather than by a budget increase.
Verification
Gate families derived from the final diff by
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(the script derives its own change set; 1 path, three-dot against merge base
ad715aca5). Every exit code captured before any pipe.pnpm check:pm-skill-ratchet(before edit)✓ check-skill-line-ratchet: .claude/skills/spec-property-retirement/SKILL.md is 337 lines (ceiling 337; headroom 0).·widest table row is 326 bytes (pin 326; headroom 0)pnpm check:pm-skill-ratchet(after edit)pnpm check:nul-bytescheck-nul-bytes: OK (scanned 8331 text file(s) ... no raw ASCII control bytes).pnpm check:skill-frame-sync✓ check-skill-frame-sync: the one declared copy of the decision frame is internally coherentpnpm check:pm-governed-merges✓ check-governed-merges --self-test: 317 assertions ...node scripts/check-closing-keyword-parity.mjscheck-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across 8338 tracked file(s), all registered).node scripts/check-closing-keyword-parity.mjs --self-testnode scripts/check-ci-filter-parity.mjsnode scripts/check-comment-mask-corpus.mjsnode scripts/report-test-timings.mjs --self-testpnpm --filter @objectstack/lint run check:doc-formula-expressionsturbo run build --filter=@objectstack/formula --filter=@objectstack/lintunderscripts/pm/os-verify-lock.sh(VERDICT command-exit 0 · held the lock 184s · waited 0s)pnpm check:agent-test-spellingpnpm check:cross-package-test-inputspnpm check:doc-authoringpnpm check:driver-memory-censuspnpm check:refd-timer-probepnpm check:required-contextspnpm check:watch-hint-literalReconciliation, exit codes recorded per family:
✓ 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).Path face —
node scripts/pm/check-governed-merges.mjs --branch claude/issue-17553-retirement-evidence-controls, exit 3:⛔ GOVERNED — a human merge is the review record for this PR (#9495 regime)..claude/** ×1. This PR stays draft; no seat flips it ready, enqueues it,or arms auto-merge.
Two order-named checks that could not run as written, recorded rather than
skipped:
node scripts/check-closing-keyword-parity.mjs --body— no suchflag exists on this base (
ad715aca); the script takes only the bare form,--self-testand--list, and both runnable forms are green above.pnpm check:pm-skill-id-lint— this file is not in its set: the gate scans.claude/skills/pm-dispatch/**plus.claude/agents/os-dev.mdandAGENTS.md(
SCAN_ROOT/EXTRA_FILES), and reports27 file(s) cleanon a tree thatdoes not include this one. That is why the file legitimately carries issue
numbers such as
#3896; the three new lines carry none.No changeset: the diff is
.claude/**only, which ships in no package'sfiles[]— theskip-changesetfast track. Label applied.Clause-②: no
Acceptance notes
noted, not filed:packages/spec/liveness/view.json's/props/list/children/fieldOrderrow still gradeslivewhile its evidencestring cites
objectui: packages/react/src/spec-bridge/bridges/list-view.ts(deleted from objectui) and
ListView.tsx:1499-1500(drifted to:2424-2425). It reads as a class (b) contract breach against the livenessREADME's 「A
liveverdict is its evidence pointer, so a pointer into thinair is a claim nothing can falsify」 — but it is already carried by two open
records: this card's own body documents it as instance 2, and keep
ListViewSchema.fieldOrder— declare thecolumns × hiddenFields × fieldOrdercomposition in the contract, with pins, and re-cite the liveness row (ruling B, 2026-09-11; supersedes the 2026-09-04 retirement ruling whose premise was measured false) #15184 isopen with
needs-user-decisionprecisely because its ruling rested on it.Carrier: the spec lane, on keep
ListViewSchema.fieldOrder— declare thecolumns × hiddenFields × fieldOrdercomposition in the contract, with pins, and re-cite the liveness row (ruling B, 2026-09-11; supersedes the 2026-09-04 retirement ruling whose premise was measured false) #15184's disposition. Filing a third card wouldduplicate them.
packages/spec/liveness/**is outside this order's surface.noted, not filed:the dispatch order's 120-byte premise and its"over-wide line" payment suggestion are both measured false against this
file (detail in the payment ledger above). Not a repo defect — a correction
to the order, for the seat's dispatch text. Carrier: the skills seat.
noted, not filed:the claim comment 5626386832 says each rule line is「≤ 120 B」 and the dispatch order says the cap does not bind. The landed
lines satisfy the claim (120 / 116 / 120 B). Recorded because the two
seat artefacts disagree with each other; the file's measured behaviour
settles it. Carrier: the skills seat.
维护者速读(草稿)
改了什么 —— 退役 playbook 的证据步(section 0 的动手前清单)多了三条规则:①
拿「本仓零编写实例」当死键证据时,必须同时跑一个同族已知存活的键作对照,两个读数
一起报;对照拿到同样的零,这次普查什么都没测出来。② 拿一条
cross-repo台账行当删除论据时,在引用当刻重核它引的路径与行号;漂了读作「重新取证」,不读作「dead」。③
「零编写实例」和「没有代码读它」是两件事,退役要的是后者。文件行数不变(337/337),三
行新规则由文件内部三处删减买单,删的每一处都在正文的付款表里点名,以及那条事实现在住
在哪儿。
为什么改 —— 同一天派出的两张退役卡,前提都实测为假:一张要删的键服务端在读,另一
张要删的键姊妹仓在用,而且第二张已经拿到维护者裁决。两轮都没造成损失,靠的是派发
词里的停止条件 —— 那是派发上的控制,不是方法上的。方法这一侧此前是无守卫的。
风险与代价(含回滚) —— 纯协议文本,没有代码、没有门禁、没有新面;唯一的代价是文
件密度:为了不抬 ceiling,section 1 里
view.form.data那段先例的管道细节和两处重述被删掉了,先例本身、它的教训与更正动作都完整保留。回滚成本为零 —— 单文件、单 commit,
git revert即可,没有任何生成物或台账跟着动。席位意见 ——
你要做的 —— 这是受管面(
.claude/**),PR 保持 draft,由你人工合并;⛔ 没有任何席位会翻 ready 或挂 auto-merge。要看的就一件事:三条规则是不是你要的说法,以及付款表里
删掉的三处你是否同意其中没有丢失事实。
Generated by Claude Code