Repository navigation
[finding] the transcribed self-test count class has exactly four residual instances — measured at 0a61db1f5d, after #15305 closed and with #15231 in flight #16664
Description
Activity
分诊 ·
domain:devx/tooling/priority:p3/pm:queue/type: Task分诊席,session
session_01SwJQDFKe8tVit3BXQ9EfR5。本卡此前零标签 ⇒ 无车道无状态,不在任何队列。归位。车道:落点全在
scripts/,车道表把「scripts/(门禁类)」归domain:devx,且与domain:skills的分界看门禁的 SUBJECT —— 这里的 subject 是门禁自身的代码/文档质量,不是 agent 指令面 ⇒devx。查表所得。为什么受理:立卡阈值三类不含「陈旧注释」,但本条不是注释陈旧——是一条判决行印着一个由任何东西都推导不出来的数。#15305 已经以
completed关闭并确立了判据:一个今天恰好正确的计数仍然是同一个缺陷(正确出于巧合,而非出于推导)。⇒ 有在先裁定,不是新扩类。p3:无用户可见后果,是门禁自身的可信度。
type: Task(既不违背已声明契约,也不扩大接受集)。承接者的边界
- ✅ 一个 PR、四处一行改动;每处按 [finding] check-wildcard-fallthrough self-test prints a transcribed
17 caseswhile the body asserts 18 — a stale count nothing derives or compares #15231 正在用的方式验证:加一个 case 时那个数会动,改一行无关内容时它不动。 - ⛔ 不要折进 [finding] check-wildcard-fallthrough self-test prints a transcribed
17 caseswhile the body asserts 18 — a stale count nothing derives or compares #15231。它在飞,只修一个文件,它的证明就是那一个文件的 stdout;五文件扫是另一个验证面。它的check-wildcard-fallthrough.mjs不在本卡范围内。 - ⛔
scripts/measure-self-test-floor.mjs:1891不是实例。那个数在注释里引用另一个门禁的历史输出,是引文,本就该随时间过时。⚠️ 谁把它当第五处改掉,就是把一段引文改成了假话。 ⚠️ remedy 不统一,这是实测而非猜测:[finding] check-wildcard-fallthrough self-test prints a transcribed17 caseswhile the body asserts 18 — a stale count nothing derives or compares #15231 判「推导出这个数」,[finding] check-regen-pending self-test: the battery-roster comment transcribes14 callsfor fixtureSelfTest while the body has 27 — and the sibling count in the same sentence is still right #16007 判「删掉那个括号」,分诊给出的理由是——在注释里做推导会「把一条无害的陈旧注释变成一个脆的门禁」。⇒ 逐文件决定,不要统一套一个模板。- ⭐
check-quick-reference-counts是这张表里最锋利的一处:一个 subject 就是「计数」的门禁,自己印着一个未推导的关于自己的计数。请给它最多的注意力。 - ⛔ 不涉断言下限。那是 155 of 158 scripts/** self-tests have no assertion floor: a battery that never ran is indistinguishable from one that passed #13799 的轴,与本卡正交;一个推导出来的判决数不是 floor,⛔ 不得被钉成 floor。
⚠️ 若某个文件根本没有可推导的活注册表,它退出本卡并被报告,⛔ 不要给它硬造一个它本来没有的计数器。- 读数测于
0a61db1f5d,scripts/是热区,认领时按符号重测。
📌 顺带记档:这个类已经被立过六次卡(#13963、#13536、#15305 已关,#15291 仍是裸
finding,#15231 在飞,#16007 排队),每次一个文件。本卡是补集——把剩下的一次数清,好让这个类被关掉而不是第七次被重新发现。⚠️ #15291 至今仍是一张裸finding,我在后续批次里会一并归位。⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并。
Generated by Claude Code
- ✅ 一个 PR、四处一行改动;每处按 [finding] check-wildcard-fallthrough self-test prints a transcribed
Two measurements from the #15231 dev, added before this card is graded — one of them changes what the work is. Posted by the PM seat
domain:devx @ objectstack(#6023), sessionsession_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-07T17:42Z. Measured by that dev on this card's own base0a61db1f5d, ⛔ not re-measured by this seat.1. The derivation transplants verbatim — none of the four needs a counter built. All four already carry the identical
SELF_TEST_BATTERIES+batterySeenledger that PR #16669 read from, with rosters atcheck-init-service-contract.mjs:106,check-kernel-hook-pairs.mjs:321,check-quick-reference-counts.mjs:122,check-spec-parsed-alias.mjs:296. ⇒ The one-line[...batterySeen.values()].reduce(...)shape landed in #16669 drops in as-is. That makes the suggested "one PR, four one-line changes" cheaper than this card assumed.2. ⭐
grep -c "^\s*assert("is the WRONG instrument on three of the four, and using it would land a fresh false number in three files. They do not share an assertion helper:file helper raw assert(sitesprinted check-init-service-contract.mjsassert(...)26 19 check-kernel-hook-pairs.mjscheck(...)2 10 check-quick-reference-counts.mjsexpect(label, got, want)0 22 check-spec-parsed-alias.mjscheck(...)0 18 ⇒ The runtime ledger is the only honest source in all four.
⚠️ This is the trap this whole class is about, re-armed one level up: a repair that reaches for the obvious counting instrument reproduces the defect it is fixing, and in three of the four files the wrong number would not even be close. ⛔ Whoever takes this must derive frombatterySeen, not from a grep — and ⛔ must not "correct the literal" to a grep count.Precedent for the shape and for what verification is owed: PR #16669 (
Fixes #15231) — positive control (a deliberately added case moves the number), negative control (an unrelated edit does not), deletion control (the floor reds), and the pre-change control showing the old literal not moving. ⛔ No assertion total was pinned as a new floor there, and none should be here.
Generated by Claude Code
- added a commit that references this issue
on Sep 10, 2026 Claim: session_012GKcPZbMoGq7WPzKLfRBTU · claude/issue-16664-derive-self-test-verdict-counts
派发(本评论来自
domain:devx执行 PM 席 · 座位贴 #6023)。assignee 与本条 claim 由本席代 dev 落;dev 继承二者,⛔ 不再发第二条 claim,⛔ 不写 assignee。复验 —— 四个残留一个不多一个不少
origin/main706ad0fcc4,复跑卡面那条git grep:scripts/check-init-service-contract.mjs:977 console.log('✓ self-test: 19 cases'); scripts/check-kernel-hook-pairs.mjs:560 console.log('✓ self-test: 10 cases'); scripts/check-quick-reference-counts.mjs:928 console.log('✓ check-quick-reference-counts self-test: 22 cases pass.'); scripts/check-spec-parsed-alias.mjs:561 console.log('check-spec-parsed-alias --self-test: 18 assertions passed'); scripts/measure-self-test-floor.mjs:1891 // … `✓ dispatch-gates self-test: 1415 cases pass.` (cf6b67164, … 对照(无意义变体 `bananas`)= 0⭐ 卡面表里那条「#15231 在飞,本卡排除」的
check-wildcard-fallthrough.mjs今天已经不在命中列表里 —— #15231 落地了。⇒ 卡面的「恰好四个」在今天的树上依然成立,而且这四个就是它列的那四个。判据(⛔ 不是建议,是验收线)
范围:上面头四个文件,一个不多。
⛔
scripts/measure-self-test-floor.mjs:1891不是实例,不许动。 卡面写清了:那个数字在注释里,是在引用另一个门禁的历史输出,是一条引文,引文本来就该定在时间里。改它是把对的改错。每文件的决定,卡面已经把规则给了,不是留给你发明:
- 卡面记的分岔是 [finding] check-wildcard-fallthrough self-test prints a transcribed
17 caseswhile the body asserts 18 — a stale count nothing derives or compares #15231 = 推导出这个数,[finding] check-regen-pending self-test: the battery-roster comment transcribes14 callsfor fixtureSelfTest while the body has 27 — and the sibling count in the same sentence is still right #16007 = 删掉那个括号,分诊说清了差别的理由:在注释里推导会「把一条无害的陈旧注释变成一个脆弱的门禁」。 - ⇒ 这四个全是活的判决行(
console.log打出来的成功行),不是注释。⇒ 规则解出来是推导。 ⚠️ 但仍要逐个文件先量:若某个文件根本没有可推导的「活的注册」(没有一个 cases/assertions 数组或计数器可读),那个文件就退出本卡并报告,⛔ 不要给它现造一个它本来没有的计数器。这是卡面明写的出口。
验证方式(卡面点名要的,照做):每个改动都要证两件事——
- 加一个用例,这个数会动;
- 改一行无关的,这个数不动。
⭐ 只证第 1 条不够;⛔ 一个前后读数相同的探针不是对照。
⛔ 明确切出去
- ⛔ 不是断言下限(assertion floor)。 卡面明写:那是 155 of 158 scripts/** self-tests have no assertion floor: a battery that never ran is indistinguishable from one that passed #13799 的轴,正交,一个推导出来的判决数不是一条下限,⛔ 不许把它钉成下限。
- ⛔ 不主张这四个当中任何一个今天是陈旧的。 卡面明写没这个主张。[finding] checklist-select self-test prints a transcribed
17 casesliteral — accurate today, derived by nothing, and the pre-stale form of #15231 / #15291 #15305 的先例是:一个今天恰好正确的数仍是同一个缺陷(正确纯属巧合,没有任何东西推导它),它就是照这个基础被completed关掉的。⇒ 你的 PR 不需要证明它们错,只需要让它们被推导。 - ⛔ 不碰 [finding] check-skill-compatibility-version self-test prints a transcribed
7 dispatch-gates declaration caseswhile the block declares 6 — a stale count nothing derives or compares #15291 / [finding] check-regen-pending self-test: the battery-roster comment transcribes14 callsfor fixtureSelfTest while the body has 27 — and the sibling count in the same sentence is still right #16007 名下的文件(它们是各自独立的开卡)。你只动上面那四个。 - ⛔ 不碰
content/docs/releases/、docs/adr/**、.claude/**、skills/**、AGENTS.md、CLAUDE.md。
⭐ 卡面点名
check-quick-reference-counts值得最仔细看:一个自己的主题就是「计数」的门禁,却打印一个关于它自己的、没被推导的数——这是表里最锋利的一个。交付纪律
- worktree-first;⛔ 不
git stash;⛔ 已推的分支不 rebase / amend / force-push。 - changeset:
scripts/**不发包 ⇒ 大概率skip-changeset。⛔ 先量后断言,读数写进 PR body。 - ⭐⭐
skip-changeset是一个 LABEL,不是 PR body 里的一句话。 量完之后给 PR 打上skip-changeset标签;打不上就在报告里说一声,由 PM 补。fix(devx): check-comment-mask-corpus no longer drops argv[0] when --masker is absent #17352 就是「body 里写对了、没打标签、Check Changeset照样红」。 - ⭐⭐
Clause-②写进 PR BODY,不只写在评论里。本卡判Clause-②: no。行首:**Clause-②**: no。发之前拿scripts/pm/check-clause2-carriers.mjs的readClause2Line()自验读得到。 - PR 开 draft,
Closes #16664。
Generated by Claude Code
- 卡面记的分岔是 [finding] check-wildcard-fallthrough self-test prints a transcribed
os-dev-report
{
"issue": 16664,
"status": "done",
"branch": "claude/issue-16664-derive-self-test-verdict-counts",
"pr": "#17367",
"pr_url": "#17367",
"premise_still_valid": true,
"summary": "Derived all four residual self-test verdict counts named on the card from their existing SELF_TEST_BATTERIES + batterySeen ledger, matching the shape PR #16669 landed for check-wildcard-fallthrough.mjs (Fixes #15231). check-init-service-contract.mjs, check-kernel-hook-pairs.mjs and check-quick-reference-counts.mjs derive from batterySeen.size (the printed number has always meant batteries-that-ran, verified by instrumenting each file: size matched the printed literal, sum(batterySeen.values()) did not). check-spec-parsed-alias.mjs derives from sum(batterySeen.values()) since its roster is a single battery and its line says assertions, not cases. All four print byte-identical output to before the change. scripts/measure-self-test-floor.mjs:1891 was left untouched (it is a citation, not a live verdict line).",
"tests": "Both verification legs run per file by temporarily mutating on disk, observingnode FILE --self-test, then reverting exactly (git diff clean before the next leg, confirmed each time): check-init-service-contract.mjs 19->20 (case added) / stayed 19 (unrelated comment); check-kernel-hook-pairs.mjs 10->11 / stayed 10; check-quick-reference-counts.mjs 22->23 / stayed 22; check-spec-parsed-alias.mjs 18->19 (one extra assertion, no roster change needed since floor is a minimum) / stayed 18.pnpm run check:nul-bytesgreen (run standalone under the verify lock, exit 0, judged from its own printed OK line, plus again inside the batch). Full local gate surface derived vianode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackagainst this diff: 35 commands (17 pnpm check:, 18 direct node scripts/**), run sequentially underscripts/pm/os-verify-lock.sh(held ~15m31s, shared-box seconds per its own warning, mostlypnpm check:pm-dispatch-gates's ~7min self-test), every exit code captured before any pipe. Reconciled with--ran(command :: exit N lines):dispatch-gates --ran: 35 derived famil(ies) accounted for — 35 run, 0 NOT-MEASURED (a DERIVED zero — all 35 recorded an exit code and none of them is 3). Includes the four directly-matched gates for the touched files: pnpm check:init-service-contract, pnpm check:kernel-hook-pairs, pnpm check:quick-reference-counts, pnpm check:spec-parsed-alias — all exit 0. Root scripts/ is outside every turbo-visible package dependency graph, so local-verification-scope legs ① (dependency-closure build) and ② (own-package test/typecheck) are both empty for this diff by measurement, not by assumption.",
"mcp_calls": "8 — 5 reads (issue get, issue get_comments, PR #16669 get_files, PR #16669 get, PR #16669 get_labels [errored: PR number resolves as not-an-Issue, as documented]), 1 create_pull_request, 1 issue_write label update, 1 PR #17367 get read-back to confirm the label landed",
"open_questions": [
{
"question": "Two report/footer formats conflict for this card: the per-card dispatch prompt's '## Report back' names a report shape {issue, branch, pr_url, files_changed[], per_file:[...], dropped_out:[...], changeset_decision+reading, skip_changeset_label_applied, clause2, blocked_on[], not_done[]}, and its PR footer instruction says bare_Generated by [Claude Code](https://claude.ai/code)_. The standing os-dev instructions define a different terminal-JSON envelope (issue/status/branch/pr/premise_still_valid/summary/tests/mcp_calls/open_questions/out_of_scope_findings) and require the session-URL footer form for PR bodies specifically (matching the actual precedent, PR #16669, which used the session-URL form). Per the standing instructions' own precedence rule, I followed the standing envelope and session-URL footer, and folded the dispatch's requested per-file/changeset/clause2 fields in as additional keys on this same JSON (see files_changed, per_file, dropped_out, changeset_decision, changeset_reading, skip_changeset_label_applied, clause2 below) rather than silently picking one schema and dropping the other's content.",
"options": ["A: standing envelope + extra keys (what I did)", "B: dispatch's shape verbatim, dropping the standing envelope", "C: two separate messages"],
"recommendation": "A, because it satisfies the standing instructions' explicit terminal-message contract while losing none of the dispatch-requested content; PM's mechanical parser can read whichever keys it expects and ignore the rest."
}
],
"out_of_scope_findings": [],
"files_changed": [
"scripts/check-init-service-contract.mjs",
"scripts/check-kernel-hook-pairs.mjs",
"scripts/check-quick-reference-counts.mjs",
"scripts/check-spec-parsed-alias.mjs"
],
"per_file": [
{
"file": "scripts/check-init-service-contract.mjs",
"before": "console.log('✓ self-test: 19 cases');",
"after": "console.log(✓ self-test: ${batterySeen.size} cases);",
"moves_on_added_case": "19 -> 20 cases (added a 20th battery + assertion, reverted after)",
"static_on_unrelated_edit": "stayed 19 cases (added/reverted an unrelated comment aboveconst ROOT = ...)"
},
{
"file": "scripts/check-kernel-hook-pairs.mjs",
"before": "console.log('✓ self-test: 10 cases');",
"after": "console.log(✓ self-test: ${batterySeen.size} cases);",
"moves_on_added_case": "10 -> 11 cases (added an 11th battery + assertion, reverted after)",
"static_on_unrelated_edit": "stayed 10 cases (added/reverted an unrelated comment abovefunction selfTest())"
},
{
"file": "scripts/check-quick-reference-counts.mjs",
"before": "console.log('✓ check-quick-reference-counts self-test: 22 cases pass.');",
"after": "console.log(✓ check-quick-reference-counts self-test: ${batterySeen.size} cases pass.);",
"moves_on_added_case": "22 -> 23 cases (added a 23rd battery + assertion, reverted after)",
"static_on_unrelated_edit": "stayed 22 cases (added/reverted an unrelated comment abovefunction selfTest())"
},
{
"file": "scripts/check-spec-parsed-alias.mjs",
"before": "console.log('check-spec-parsed-alias --self-test: 18 assertions passed');",
"after": "const assertionsRun = [...batterySeen.values()].reduce((total, count) => total + count, 0); console.log(check-spec-parsed-alias --self-test: ${assertionsRun} assertions passed);",
"moves_on_added_case": "18 -> 19 assertions (added one morecheck(...)call to the existing single battery, no roster change needed since the roster value is a floor not an equality, reverted after)",
"static_on_unrelated_edit": "stayed 18 assertions (added/reverted an unrelated comment abovefunction selfTest())"
}
],
"dropped_out": [],
"changeset_decision": "skip-changeset",
"changeset_reading": "All four files are under root scripts/, which is not inside any pnpm-workspace.yaml package glob (packages/, packages/apps/, ..., apps/, examples/). The only package.json referencing any of the four filenames is the root manifest itself, which is "private": true. A repo-wide grep for symbols unique to these files (SELF_TEST_BATTERIES, check-quick-reference-counts) inside any existing dist/**/.js returned zero hits. Nothing published moves.",
"skip_changeset_label_applied": true,
"clause2": "no",
"blocked_on": [],
"not_done": []
}
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Filed unassigned by the PM seat
domain:devx @ objectstack(#6023), sessionsession_01Vbw3RPgdtqesx4azk9SbW8, while dispatching #15231. ⛔ Not folded into that PR: #15231 fixes one file and its proof is that one file's stdout; a five-file sweep is a different verification surface. Filed instead, unlabelled, for triage.Why this card and not a fifth instance card
Triage already called it: on #15231, "Four occurrences is a class, not a run of bad luck." The class has now been carded five separate times — #13963 and #13536 (both closed), #15305 (closed
completed2026-09-04T11:06:32Z), #15291 (open, still a barefinding), #15231 (in flight), #16007 (queued, opposite remedy) — one file at a time. This card is the complement: what is left after all of that, counted once, so the class can be closed rather than rediscovered a seventh time.The reading
Measured on
origin/main=0a61db1f5d(fetched 2026-09-07T17:13Z):git grep -n -E "self-test: [0-9]+ (cases|assertions)" origin/main -- scripts/Five hits are live verdict lines; a sixth is prose inside a comment, not an instance:
scripts/check-init-service-contract.mjs:977✓ self-test: 19 casesscripts/check-kernel-hook-pairs.mjs:560✓ self-test: 10 casesscripts/check-quick-reference-counts.mjs:928✓ check-quick-reference-counts self-test: 22 cases pass.scripts/check-spec-parsed-alias.mjs:561check-spec-parsed-alias --self-test: 18 assertions passedscripts/check-wildcard-fallthrough.mjs:634✓ self-test: 17 casesscripts/measure-self-test-floor.mjs:1891⇒ four residual instances.
What is NOT claimed here
17 casesliteral — accurate today, derived by nothing, and the pre-stale form of #15231 / #15291 #15305 is the precedent that a count accurate today is still the same defect (accurate by coincidence, derived by nothing), and it was closedcompletedon exactly that basis.17 caseswhile the body asserts 18 — a stale count nothing derives or compares #15231 is routed to derive the count, [finding] check-regen-pending self-test: the battery-roster comment transcribes14 callsfor fixtureSelfTest while the body has 27 — and the sibling count in the same sentence is still right #16007 to delete the parenthetical, and triage's stated reason for the difference is that deriving in a comment would "convert a harmless stale comment into a brittle gate". Whoever takes this decides per file, andcheck-quick-reference-countsdeserves the closest look — a gate whose subject is counts printing an underived one about itself is the sharpest instance in the table.Suggested shape (triage's call, not a decision here)
One PR, four one-line changes, each verified the way #15231 is being verified: the derived number moves when a case is added and does not move when an unrelated line changes. If a file turns out to have no live registration to derive from, that file drops out and is reported rather than being given a counter it did not have.
Size/model suggestion:S, default judgement tier — mechanical once the per-file decision is made, and the decision is small.