Repository navigation
Description
范围外发现,记录于 #5873 的重锚复验过程中(该单前提已被证伪 —— 其正文指认的 authorable-surface.json 无保护 JSON.parse 已随 #5837 分片重做整体消失,详见其评论)。观察类:不构成绕过,门禁照样红、--check 照样不写盘,只是这一条错误分支的诊断质量掉回了「裸 JS 报错」。
事实
packages/spec/scripts/lib/sharded-artifacts.ts:95-104 的 categoryOfDefKey(key: string) 直接调 key.indexOf('/')。参数类型写的是 string,但它读的是磁盘上的 JSON 数组条目 —— 一个被手编成非字符串的条目(数字、null、对象)在运行时就会让它抛裸 TypeError。
它自己对「字符串但没有 category 段」这一类是会说话的:
cannot shard "foo": every ratcheted key is "category/Def[:prop]" and this one has no category segment (#5837)
缺的只是「根本不是字符串」这一格。
实测(本轮,worktree @ origin/main 252f71bd6,build-schemas.ts @ 747d2e451)
往 packages/spec/authorable-surface/ui.json 的 keys[0] 注入数字 12345,跑 pnpm --filter @objectstack/spec check:authorable-surface:
EXIT=1
❌ Failed to read authorable-surface/: key.indexOf is not a function
退出码对、无栈,但这条消息不报是哪个分片文件、不报是哪个条目、无 issue 锚点、无处方。读者拿到的信息量约等于零 —— 14 个分片,他得自己挨个找。
对照:同一文件同一轮,其它缺陷类都说话
同一 worktree、同一 gate,另外三种破坏方式的实测输出:
| 破坏方式 | 实测输出 |
|---|---|
删掉 ui.json 末尾 } |
❌ Failed to read authorable-surface/: authorable-surface/ui.json is not valid JSON (#5837): SyntaxError: ... |
keys 改成非数组 |
❌ Failed to read authorable-surface/: authorable-surface/ui.json has no "keys" array (#5837). |
破坏姊妹 authorable-surface.base.json |
❌ authorable-surface.base.json is not valid JSON (#5235): SyntaxError: ... |
keys 内注入非字符串条目 |
❌ Failed to read authorable-surface/: key.indexOf is not a function |
前三行都报了文件名 + issue 锚点;只有第四行退化。
影响面
categoryOfDefKey 是三个分片产物的共用路径 —— authorable-surface/、schema-manifest/、authorable-defaults/ 的读取都经 aggregateCategoryShards 走到它(build-schemas.ts 的三个 try/catch 分别在 :503 / :733 / :2324),所以同一条哑消息会以三种前缀出现。落点是 lib 一处,不是三处。
为什么归为观察类
- 不是绕过:三个调用点的外层 try/catch 都是
console.error+process.exit(1),退出码正确;--check在读之前不写任何文件(check:authorable-surface在 --check 模式下仍会写json-schema.manifest.json—— 一个「检查」在改工作区 #4711 纪律未退步)。 - 触发前提是「有人手工把生成物里的条目编成生成器从不写出的类型」—— 今天没有用户路径会命中。
- 真实代价只有一条:同一个 reader 里,四类缺陷有三类会说话,这一类不会。
建议修法(窄)
两个落点二选一,都不新增语义:
- A(更靠近根因):
categoryOfDefKey在indexOf之前加一格typeof key !== 'string',复用它已有的那句 message 形状。缺点是它拿不到分片文件名。 - B(信息更全):
aggregateCategoryShards遍历list时顺手判类型 —— 它手里正好有shard.name,能报出「哪个文件的哪个条目」,与相邻那句has no "keys" array (#5837)同族。
倾向 B:这个 reader 的既有惯例就是「报文件名 + 报条目 + 带 issue 锚点」,B 能把这一格补齐到同一水平,A 只能补到「不是裸报错」。
关联:#5873(本发现的来源单,其自身前提已被证伪)、#5837(分片重做)、#5235(姊妹 reader,对照实现)。
Activity
claude commentedon Aug 8, 2026
Findings-round grading: held (
finding+domain:spec-toolingstay).Why still held: not a bypass (all three call sites exit 1 correctly;
--checkwrites nothing), and the trigger premise is a hand-mangled generated artifact of a type the generator never writes — no user path reaches it today. The cost is one dumb error message out of four defect classes that otherwise speak. Restart condition: promote if any real corruption event lands on a shard file (making the message quality matter), or fold it into the nextspec-toolingsweep card as a member line — it is exactly sweep-sized (fix A or B in the card's own words, one lib landing site).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commentedon Aug 9, 2026
Triage (maintainer-authorized one-off pass, 2026-08-09, registered on #6015): promoted
finding→pm:queue(tooling/domain:spec-toolingkept). S-class diagnostics fix: the reader already speaks properly for the "string without category" case — the non-string case gets the same treatment (file name, entry index, issue anchor) instead of a barekey.indexOf is not a function. Gate behaviour unchanged; one branch plus a fixture.Generated by Claude Code
os-project-manager commentedon Aug 9, 2026
认领 ·
domain:spec-tooling座位派单 — 会话session_01AZgRyPVwi1jLb1mNNuQ9o更正:session_01AZgRyPVwi1jLb1mNNuUQ9o(座位贴 #6018),分支claude/issue-6751-shard-reader-named-error,pm:queue→pm:dispatched。三查(本轮实测):① ㉔ 落点
packages/spec/scripts/lib/sharded-artifacts.ts最新提交8d86f8d44(#4666 via PR #6360,08-07)——自本单立单以来零改动,前提就位;② 竞态:线程为一次 hold、一次晋级,均非认领;③ 不相交:同批 #6967(scripts/check-adr-0087-registration.mjs)、#6833(packages/lint/**),零重叠。按分诊口径:S 级诊断修复,门禁行为不变,一个分支 + 一个夹具。Generated by Claude Code