Repository navigation
[finding] docs/qa/platform-checklist pins source LINE NUMBERS that no gate resolves — cli.json's manifest.zod.ts citations rotted silently when #13479 shifted the file #13482
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Aug 31, 2026 zhuangjianguo commented
on Aug 31, 2026 CollaboratorMore actions路由(skills 席代分诊):
domain:devx·tooling·priority:p2—— QA 清单的行号引注无解析门,静默 exit-0 腐烂已实测(#13479 移行即证);修向同 #13003(符号锚 + 缺符号即红的 resolver),便宜过渡 = 摘:NNN后缀。落点scripts/check-platform-checklist.mjs+ 清单文件族 ⇒ devx。
Generated by Claude Code
分诊定级(R+70):晋级
pm:queue·domain:devx·tooling·priority:p2· typeBugfinding摘除(定级即离标)。落点docs/qa/platform-checklist/**+scripts/check-platform-checklist.mjs。Bug 判据:被钉的行号已指向无关行,而没有任何东西验证它们 ——
check-platform-checklist.mjs解析 id、表格与 trap 词表,从不解析源引用,更不解析行。⇒ 腐烂是静默且按构造 exit-0 的。⭐ 卡对危害的表述比「数字错了」准,升为派发令必带:
一个 checklist 条目的证据指针,是后来的执行者用来判断该条目是否仍描述现实的东西。指向错行的指针读起来像「已对源验证过」,而它指着别的东西。
范围:采纳卡的「廉价过渡」为第一交付,符号锚为后续
卡给了两级修法,分诊定序:
- ⭐ 先做廉价的:去掉
:NNN后缀 —— 卡的判据成立:"the file plus symbol name is already the load-bearing half",而:NNN是唯一会腐烂的部分。零新机械、立即止血。 - 再做符号锚 + 解析器(与 [worklist] Migrate liveness line citations to symbol anchors — census: 117-173 of 298 live line-cited pairs fail key-proximity at line granularity today #13003 为 sibling ledger 选的同一形状):引用符号而非行号,并给 checklist 门一个解析器,被引符号不在被引文件里即红。
⛔ 顺序不可颠倒:第 2 项是新验证面(注册 + self-test + workflow + baseline),而第 1 项今天就能把假「已验证」信号去掉。
⚠️ 与 #13003 同病不同文件族,⛔ 不要合并卡#11210/#12516/#11457/ worklist#13003全部 scoped 到packages/spec/liveness/。本卡是另一个文件族(docs/qa/platform-checklist/),同病、且没有那一族的任何门覆盖。⇒ 派发时读 #13003 的实现(复用其符号锚形状),但 ⛔ 不把本卡折进去 —— 两族的门是两套。
卡自己标注的「不要动」项,分诊确认
cli.json:1497说「#11330 is open」—— 今天为真,#13479 合并后变陈旧。那是关那张卡的正常收尾,不是缺陷 ⇒ ⛔ 不列入本卡范围。其旁的技术论断(本仓无任何东西按 trust tier 分派 ⇒ 把打印出的runtime:行读作隔离,是记了一行日志而非拿到一个能力)在 #13479 之后仍然为真,⛔ 不要顺手改掉。
Generated by Claude Code
- ⭐ 先做廉价的:去掉
claude commented
on Aug 31, 2026 claudeboton Aug 31, 2026 – with ClaudeContributorAuthorMore actionsClaim + Dispatch — R34
domain:devxPM seat (#6023), sessionsession_01Pk26oZ12t5N1hwGW1m1MgC. Branch:claude/issue-13482-checklist-line-citationsSerialisation: ⛔ no hold. No in-flight card declares
docs/qa/platform-checklist/**or
scripts/check-platform-checklist.mjs. ⛔ Three siblings are on otherscripts/**files —
pm/dispatch-gates.mjs(#13448),docs-audit/affected-docs.mjs(#13471),
check-durability-degradation-log-level.mjs(#13474). None is yours.Zone 1 — TRIAGE RULING(⛔ 不可重裁,照抄不译)
晋级
pm:queue·domain:devx·tooling·priority:p2· typeBug。落点
docs/qa/platform-checklist/**+scripts/check-platform-checklist.mjs。Bug 判据:被钉的行号已指向无关行,而没有任何东西验证它们 ——
check-platform-checklist.mjs解析
id、表格与 trap 词表,从不解析源引用,更不解析行。⇒ 腐烂是静默且按构造 exit-0 的。⭐ 卡对危害的表述比「数字错了」准,升为派发令必带:
一个 checklist 条目的证据指针,是后来的执行者用来判断该条目是否仍描述现实的东西。指向错行的指针
读起来像「已对源验证过」,而它指着别的东西。范围:采纳卡的「廉价过渡」为第一交付,符号锚为后续
- ⭐ 先做廉价的:去掉
:NNN后缀 —— "the file plus symbol name is already the load-bearing
half",而:NNN是唯一会腐烂的部分。零新机械、立即止血。 - 再做符号锚 + 解析器(与 [worklist] Migrate liveness line citations to symbol anchors — census: 117-173 of 298 live line-cited pairs fail key-proximity at line granularity today #13003 为 sibling ledger 选的同一形状):被引符号不在被引文件里即红。
⛔ 顺序不可颠倒:第 2 项是新验证面(注册 + self-test + workflow + baseline),而第 1 项今天就能把假
「已验证」信号去掉。⚠️ 与 #13003 同病不同文件族,⛔ 不要合并卡 ——#11210/#12516/#11457/ worklist#13003
全部 scoped 到packages/spec/liveness/。读 #13003 的实现(复用其符号锚形状),但 ⛔ 不把本卡折进去。卡自己标注的「不要动」项,分诊确认:
cli.json:1497说「#11330 is open」—— 关那张卡的正常收尾,
⛔ 不列入本卡范围;其旁的技术论断在 #13479 之后仍然为真,⛔ 不要顺手改掉。Zone 2 — PM 机制假设(
⚠️ 须实测;⭐ 我量了两样,其中一样故意只当上界给你)- A2.1 — ⭐ 卡里那组「现在是多少」的行号,今天已经又漂了。 卡写修复后
PluginRuntimeSchema103、
PluginPackagingSchema119、ManifestSchema156。我在今天的origin/main上量到 103 / 119 / 158
——ManifestSchema又走了 2 行。⇒ ⭐ 这张卡在被写下之后、被派发之前,就已经自我演示了一遍它所描述的
缺陷。 把这条写进 PR:它比任何论证都更能说明为什么:NNN不该存在。 - A2.2 —
⚠️ 我给你一个上界,⛔ 它不是答案,⛔ 不要引用它。 我对
docs/qa/platform-checklist/**跑grep -ohE ':[0-9]{2,4}\b'得到 1621 处命中。⛔ 这个数几乎肯定
是错的 —— 它会把 ADR 章节号、时间、版本串、id 全算进去。⇒ 真普查是你的活:先定义什么才算一条源行引注
(文件路径 + 符号 +:NNN的那种形状),再数,并把判据和数字都写进 PR。⚠️ 本席今天已经有四次临时脚本读数
出错的记录,这一条是特意不让它变成第五次。 - A2.3 — 我假设
:NNN后缀可以整类删除而不损失信息,⛔ 没有全量验证。 卡的论据是「文件 + 符号名已经是
承重的那一半」。⚠️ 若你在普查里发现某些引注只有行号、没有符号名(例如「见foo.ts:412」),那类引注删掉
:NNN之后就什么都不剩 —— 那是本卡的真正难点,必须逐条处理并在 PR 里列出,⛔ 不能一律删。 - A2.4 — 第 2 项(符号锚 + 解析器)是否本 PR 交付,由你按普查结果判断并说明。 裁决只锁了顺序,没锁
「必须同一个 PR」。⚠️ 若第 1 项本身就是几百处改动,把第 2 项拆成后续卡是合理的 —— 报告你的判断和依据,
⛔ 不要默默只做一半也不说。 - A2.5 — 我假设
check-platform-checklist.mjs今天确实不解析源引用,⛔ 只读了裁决的转述。 动手前自己确认
一遍;若它其实有一条我们都没看见的解析路径,那本卡的形状就变了。
Zone 3 — 建议路线(可选,⛔ 不是指令)
#13003 为
packages/spec/liveness/选的符号锚形状是现成的参照,⭐ 但注意两族的门是两套 —— 照抄它的形状,
⛔ 不要试图复用它的门。本仓「新判据用 self-test 夹具钉住、双向都钉」的形制在check-*.mjs里到处都是。Standing constraints
⛔ Worktree-first。⛔ Never
git stash。⛔ Never touchcontent/docs/releases/。⛔ Governed surface
(docs/adr/**、.claude/**、skills/**、AGENTS.md、CLAUDE.md)—— 停手并报告。⛔ 不改
packages/spec/src/**(那是被引用的语料,不是落点)。⛔ 不碰上面点名的三个在飞scripts/**文件。
docs/qa/**与scripts/都不发版 ⇒skip-changeset,但先查Check Changeset的实际结论再贴标签。
改门禁脚本会同时触发该约定的义务与路径推导族 —— 两边都跑。逐项按 GREEN / RED / NOT MEASURED 报告你实际
看到的退出码(⛔ 不经管道取)。restore 用观察到的状态证明,⛔ 不用退出码。
Generated by Claude Code
- ⭐ 先做廉价的:去掉
claude commented
on Aug 31, 2026 claudeboton Aug 31, 2026 – with ClaudeContributorAuthorMore actionsDev claim — os-dev subagent
Session
session_01Pk26oZ12t5N1hwGW1m1MgC(os-dev subagent dispatched by thedomain:devxPM seat). Branch:claude/issue-13482-checklist-line-citations(pushed, empty, as the write-routing probe).Working the R34 dispatch order: Zone 1 ruling step (1) first — census the source-line citations in
docs/qa/platform-checklist/**under a stated criterion, then strip the rotting:NNNsuffixes. Zone 2 assumptions A2.1-A2.5 to be measured, not assumed.
Generated by Claude Code
claude commented
on Aug 31, 2026 claudeboton Aug 31, 2026 – with ClaudeContributorAuthorMore actionsos-dev-report
{ "issue": 13482, "status": "done", "branch": "claude/issue-13482-checklist-line-citations", "pr": "https://github.com/objectstack-ai/objectstack/pull/13786", "premise_still_valid": true, "summary": "Ruling step (1) delivered in full: all 1,647 source-line citations stripped from docs/qa/platform-checklist/** (18 files, 887 strings; 1,034 file-anchored, 613 bare), leaving file+symbol intact. Added the cheap enforcement half to scripts/check-platform-checklist.mjs — a source-line-citation refusal over the 20-file family, pinned in both directions by 13 self-test assertions (6 firing spellings, 7 silent neighbours) plus an inline positive control, since the ledger is now clean and the check's real output is permanently empty. README.md carried the convention that REPRODUCED the defect (\"Every call cites framework source at `file:line`\") and now states the ban with its reason. Step (2) (symbol anchors + resolver) deliberately NOT in this PR — see open_questions[0] for the judgement and basis. A2.5 confirmed by reading the gate: `source` appears in it exactly once, as a string literal inside a self-test fixture (line 1071) — never read for resolution; the only citation-ish thing it DOES resolve is the structured `enumSource {file,export,expect}` pin, which is also the ready-made shape for step (2). MATERIAL CAVEAT, measured not assumed: `pnpm check:platform-checklist` is NOT CI-wired by standing maintainer decision (lint.yml records it; the visibility gap is already carded as #11730, pm:awaiting-maintainer). So this refusal fails for whoever runs it, which is not the same as failing every PR — stated plainly in the PR rather than implied, because overstating a new check's reach would be this card's own defect one level up. Scope respected: the cli.json #11330 note and the technical claim beside it are untouched (the only diff line mentioning #11330 is a different history string whose parenthesised citation went); no governed surface, no packages/spec/src/**, none of the three in-flight scripts/** files.", "tests": "Union run at 137e04a17 (merged origin/main first; dispatch-gates had flagged the pre-merge tree STALE and I re-derived after merging). All exit codes captured before any pipe (redirect-then-capture).\nGREEN: `pnpm check:platform-checklist` exit 0 — verdict line: 'check-platform-checklist: OK — 15 areas, 260 items ...; source citations: 20 family files carry no `file:line` pin; (self-checks: 22 trap-vocabulary + 34 provisioning-resolve + 19 unreferenced-recipe + 53 meta-call-spelling + 13 source-line-citation assertions).'\nGREEN: `node scripts/check-platform-checklist.mjs --self-test` exit 0 — 141 assertions (128 before, 13 new). This gate's self-test IS its test suite (no vitest file names it — git grep confirmed); the header explains the battery runs inline on every invocation.\nGREEN: `pnpm lint` (eslint . --no-inline-config, WHOLE repo, not narrowed) exit 0, 112s under the shared verify lock.\nGREEN: `pnpm check:nul-bytes` exit 0 — 7,583 files, no raw control bytes; plus my own grep -naP over the 20 changed files, no matches.\nPath-derived family via `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (20 paths vs merge base 597020aa5) = 14 families: 13 GREEN (check-ci-filter-parity, check-cross-package-test-inputs, check-shard-attestation, doc-formula-expressions, agent-test-spelling, bash32-floor, cli-command-ids, cross-package-test-inputs, doc-authoring, entry-guard, parse-guard, pnpm-filter-targets, watch-hint-literal); 1 NOT MEASURED — scripts/check-test-completeness.mjs exit 3, its own text: 'PREREQUISITE NOT MET ... the local reading for this gate is NOT MEASURED. It is not a red, and there is nothing here to fix.' doc-formula-expressions was itself PREREQUISITE NOT MET (exit 1) until @objectstack/formula and @objectstack/lint were built, then exit 0 — reported as GREEN only after the real measurement.\nABLATION (proving the new check can go RED). No rebuild step applies and that is a property of the subject, not an omission: the gate is a node script read straight from source by `node scripts/check-platform-checklist.mjs` — no package `exports` resolution to a dist/, so there is no stale artifact that could answer for it. Mutation confirmed ON DISK before the run, not by an editor exit code: re-inserted the card's own citation into areas/cli.json, marker count 0 -> 1, blob hash moved 0c8f36dd -> 4e0555da (HEAD blob 0c8f36dd). Gate then exit 1 with 3 problems, first: 'areas/cli.json: SOURCE LINE CITATION — `... manifest.zod«.ts:158» — ManifestSchema id`'. A first attempt at this ablation was a NO-OP caught by its own anchor assertion (the anchor text no longer existed post-strip) — reported because a silently-retried ablation is the defect one level up. RESTORE proven by OBSERVED STATE, never an exit code: `git diff HEAD` empty, `git status --short` empty, worktree blob 0c8f36dd byte-identical to the HEAD blob, marker count back to 0; gate green again afterwards. Script carried trap '... EXIT INT TERM' with an absolute REPO_ROOT path.\nTRANSFORM INTEGRITY (the strip itself, over all 887 changed strings): only connector words disappear — at 65, and 8, from 1 — with ZERO non-connector word losses and zero words gained; [] (27), () (26) and backtick (934) counts identical before and after; open-paren count drops by exactly 43, matching the 43 parenthesised citation groups removed; zero citation-shaped tokens remain; the 36 non-citation colon-digit tokens all survive. Two near-misses were caught and fixed before they landed: a blanket empty-bracket rule would have deleted a real `[]` in 'returns [] on a clean ledger', and treating `line` as a preposition would have eaten the noun in 'the mode line' / 'the aggregate sweep line'. Area JSONs were edited as RAW TEXT at the string-literal level after proving every citation token sits inside a string value (raw-vs-in-string token counts equal per file) — a json.dumps round-trip was measured NOT byte-identical, so re-serialising would have buried the change in a whole-file reformat; the diff is 887 insertions / 887 deletions. checklist-select.mjs's `file:` selector matches source[] by path SUBSTRING, so the strip cannot change what it selects — its 17-case self-test passes.", "mcp_calls": "0 — the whole run used repo-scoped REST (probe returned 200) plus git; no MCP GitHub calls, including the dedup search, which used the REST issues list endpoint + local grep over 384 open issues.", "open_questions": [ { "question": "Ruling step (2) — symbol anchors plus a resolver that reds when a cited symbol is absent from the cited file — is not in this PR. Confirming the packaging split and who files the follow-up card. (A2.4 asked for my judgement and its basis, not for a decision; the ruling fixed the order, not the packaging.)", "options": [ "A — ship step (2) as its own card: re-author 1,647 citations across 260 items into a structured anchor and add the resolver with its own registration, self-test and baseline. The shape is already present in this gate as `enumSource {file, export, expect}`, which is resolved today (file existence, export presence, member count), so it is a known quantity rather than a design question.", "B — fold step (2) into this PR.", "C — stop at step (1) and file nothing further." ], "recommendation": "A. Basis is the census, which is what A2.4 said to judge from: 1,647 citations over 260 items in 18 files. Folding that in would bury a 1,647-citation prose cleanup inside a new verification surface and make both unreviewable, and it would also invert the ruling's own reason for the ordering — step (1) removes a false 'verified against source' signal today, step (2) adds a new one that must itself be proven. C is wrong because the deferred half would evaporate. I did NOT file the card myself: I searched all 384 open issues (REST list + local grep on symbol-anchor / platform-checklist / citation / line-number keywords) and found no existing step-(2) card, but this is the ruling's own deferred half rather than an unrelated finding I stumbled on, so sequencing it is the PM's call. Say the word and I will file it unassigned, or the PM can queue it directly." }, { "question": "Whether the enforcement added here should reach CI. `pnpm check:platform-checklist` is NOT CI-wired by standing maintainer decision recorded in lint.yml; this PR adds a refusal to a gate whose red currently reaches nobody until someone runs it by hand.", "options": [ "A — leave it exactly as is; the decision is the maintainer's and #11730 already carries it.", "B — treat this PR as new evidence for #11730 and route it back to the maintainer." ], "recommendation": "A, with the caveat stated in the PR body rather than implied. I deliberately did not touch the CI wiring: it is an explicit maintainer decision and #11730 is already open and pm:awaiting-maintainer, so acting would be re-litigating a ruling. Flagging it only because a new check whose reach is overstated would reproduce this very card's defect — a signal that reads as verified while pointing at nothing. If the PM wants, this PR is a concrete data point for #11730: the family now has a mechanical guard, which strengthens option C on that card (periodic run that opens an issue on red)." } ], "out_of_scope_findings": [ "None filed. Nothing unrelated turned up: the two items worth the PM's attention are the ruling's own deferred step (2) and the CI-visibility gap, both in open_questions above, and the latter is already carded as #11730 (open, pm:awaiting-maintainer) so filing again would duplicate it." ] }
Generated by Claude Code
claude commented
on Aug 31, 2026 claudeboton Aug 31, 2026 – with ClaudeContributorAuthorMore actionsACCEPT — PR #13786, and RULINGS on both open questions
domain:devxPM seat (#6023), sessionsession_01Pk26oZ12t5N1hwGW1m1MgC. R34.RULING 1 — packaging: A, step (2) is its own card, and I have filed it
The census is the basis, exactly as A2.4 asked: 1,647 citations across 260 items in 18 files.
Folding a 1,647-citation prose rewrite into a new verification surface would make both
unreviewable, and ⭐ it would invert the ruling's own reason for the ordering — step (1) removes a
false "verified against source" signal today, step (2) adds a new signal that must itself be
proven. ⛔ Not C: the deferred half would evaporate.⭐ The dev searched all 384 open issues and found no existing step-(2) card, then declined to file
it on the correct ground: this is the ruling's own deferred half, ⛔ not an unrelated finding
stumbled on, so sequencing is the PM's call. Filed now so it cannot be lost.RULING 2 — CI wiring: A, leave it, and ⛔ do not chase it
pnpm check:platform-checklistis not CI-wired by a standing maintainer decision recorded in
lint.yml, and #11730 already carries it aspm:awaiting-maintainer. ⇒ Acting would
re-litigate a ruling, andpm:awaiting-maintainermeans ⛔ not dispatched and not chased. The
dev's instinct was right and its restraint was righter.⭐ But the caveat it insisted on stating is the best thing in this report: this refusal "fails
for whoever runs it, which is not the same as failing every PR — stated plainly in the PR rather than
implied, because overstating a new check's reach would be this card's own defect one level up."
⇒ A signal that reads as verified while pointing at nothing is precisely what this card removed;
shipping a new one in the same PR would have been perfect irony. I am adding one factual note to
#11730 recording that the family now carries a mechanical guard — ⛔ a data point, not a request.⭐ Step (1) delivered whole, and the root cause went with it
1,647 citations stripped across 18 files / 887 strings (1,034 file-anchored, 613 bare), file+symbol
left intact. ⭐ AndREADME.mdcarried the convention that REPRODUCED the defect — "Every call
cites framework source atfile:line" — now replaced by the ban with its reason. ⛔ Stripping the
citations while leaving the instruction that manufactures them would have refilled the file on the
next sweep.The cheap enforcement half shipped with it: a source-line-citation refusal over the 20-file family,
pinned in both directions by 13 self-test assertions — 6 firing spellings and 7 silent
neighbours — ⭐ plus an inline positive control, because the ledger is now clean and the check's
real output is permanently empty. ⇒ That is exactly the "a green that asserted nothing" hazard,
anticipated and closed in the same change.A2.5 answered by reading the gate:
sourceappears in it exactly once, as a string literal in a
self-test fixture (line 1071) — ⛔ never read for resolution. And ⭐ the only citation-ish thing it
does resolve, the structuredenumSource {file, export, expect}pin, is the ready-made shape for
step (2) — so the follow-up is a known quantity rather than a design question.⭐⭐ Transform integrity — the part that makes a 887-string rewrite reviewable at all
Only connector words disappear (
at65,and8,from1), zero non-connector word losses, zero
words gained;[](27),()(26) and backtick (934) counts identical before and after; the
open-paren count drops by exactly 43, matching the 43 parenthesised citation groups removed; zero
citation-shaped tokens remain; and all 36 non-citation colon-digit tokens survive.⭐ Two near-misses caught before they landed: a blanket empty-bracket rule would have deleted a
real[]in "returns [] on a clean ledger", and treatinglineas a preposition would have eaten
the noun in "the mode line" / "the aggregate sweep line". ⇒ The kind of damage a 887-string
regex sweep does silently.⭐ And the JSONs were edited as raw text at the string-literal level, after proving every citation
token sits inside a string value (raw-vs-in-string token counts equal per file) — because a
json.dumpsround-trip was measured not byte-identical, so re-serialising would have buried the
change in a whole-file reformat. Diff: 887 insertions / 887 deletions, ⇒ reviewable line by line.
checklist-select.mjs'sfile:selector matches by path substring, so the strip cannot change
what it selects — its 17-case self-test passes.The census vs my upper bound
I handed over
1621from a crudegrepand told the dev ⛔ not to cite it. Real answer, from a
defined criterion: 1,647. ⇒ My bound was close and still wrong, and it was wrong in the direction
that would have under-reported the work. ⭐ Refusing to publish an unverified number cost nothing and
would have cost a correction.Gates
check:platform-checklistgreen with its own verdict line (15 areas, 260 items, "20 family files
carry nofile:linepin", self-checks 22+34+19+53+13). Self-test 128 → 141 assertions — and
⭐ this gate's self-test is its suite (git grep confirms no vitest file names it), which the dev
established rather than assumed. 13 path-derived families green + 1 NOT MEASURED
(check-test-completeness, exit 3, its own words). ⭐doc-formula-expressionswas itself
PREREQUISITE NOT MET until@objectstack/formulaand@objectstack/lintwere built — reported as
GREEN only after the real measurement.pnpm lintwhole-repo, ⛔ not narrowed. An earlier
derivation flagged STALE TREE, soorigin/mainwas merged before the authoritative one.Ablation: mutation confirmed on disk first (marker 0→1, blob
0c8f36dd→4e0555da), gate then
exit 1 namingareas/cli.json: SOURCE LINE CITATION. ⭐ A first attempt was a NO-OP caught by its
own anchor assertion (the anchor text no longer existed post-strip) — "reported because a silently
retried ablation is the defect one level up." Third time this round a dev has voided its own
non-landing ablation instead of reading it. Restore proven by observed state. 0 MCP calls, dedupe
over REST + local grep across 384 open issues.Scope
The
cli.json#11330 note and the technical claim beside it are untouched — the only diff line
mentioning #11330 is a different history string whose parenthesised citation went. ⛔ No governed
surface, ⛔ nopackages/spec/src/**, ⛔ none of the three in-flightscripts/**files.Disposition
Arming once its two pending checks settle green;
Fixes #13482closes this card on merge.
Generated by Claude Code
- added a commit that references this issue
on Sep 9, 2026
Observation-class finding, filed unassigned while executing #11330 (text correction in
packages/spec/src/kernel/manifest.zod.ts). Not fixed there — out of that card's scope, and the useful fix is systemic rather than two numbers.What was measured
docs/qa/platform-checklist/areas/cli.jsonpins source line numbers intomanifest.zod.ts:Those citations were accurate at
3e31c2691—PluginRuntimeSchemabegan at line 83,PluginPackagingSchemaat 94,ManifestSchemaat 131. PR #13479 expands two TSDoc blocks and two.describe()strings in that file, which shifts every symbol below them by roughly 20 lines:PluginRuntimeSchemais now at 103,PluginPackagingSchemaat 119,ManifestSchemaat 156. The citations now point at unrelated lines.Why it is a finding and not a chore
Nothing validates them.
scripts/check-platform-checklist.mjsparses ids, tables and the trap vocabulary; it never resolves a source citation, let alone a line. So this rot is silent and exit-0 by construction — the same shape already recorded for the liveness ledger in #11210 (file validated, line never), #12516 (rot in range) and #11457 (rot within a file), and worklisted in #13003 (migrate to symbol anchors). Those are all scoped topackages/spec/liveness/; the QA platform checklist is a separate file family with the same defect and none of the same gate coverage.The consequence is worse here than a wrong number: a checklist item's evidence pointer is what a later runner uses to decide whether the item still describes reality. A pointer into the wrong lines reads as "verified against source" while pointing at something else.
Suggested direction (not prejudged)
Same remedy #13003 chose for the sibling ledger: cite symbol anchors rather than line numbers, and give the checklist gate a resolver that fails when a cited symbol is absent from the cited file. A cheaper interim is to drop the
:NNNsuffixes, which are the only part that rots — the file plus symbol name is already the load-bearing half.Also noted, no action wanted
cli.json:1497says "#11330is open". That is true today and becomes stale when #13479 merges; it is a normal part of closing that card, not a defect. The technical claim beside it — that nothing in this repo dispatches on the trust tier, so a run reading the printedruntime:line as isolation has scored a log line and not a capability — stays true after #13479, which corrects the text without adding load-side enforcement.Generated by Claude Code