Repository navigation
Description
未认领。 审核 PR #4915(#4913)时发现,不在那条 PR 的范围内(它没有引入这个行为,只是把 ROOTS 从 2 个扩到 3 个),按 Prime Directive #10 单独归档。
现状
scripts/check-doc-authoring.mjs 的 collectFiles():
for (const r of ROOTS) { try { walk(r, files); } catch {} }ROOTS 现在是 ['.claude', 'skills', 'content']。任何一条解析不到(目录改名、移动、被删),walk 抛出的 ENOENT 被 catch {} 原地吞掉,门禁继续跑完剩下的 root,然后打印:
✓ doc authoring guard: N files clean — no bare metadata literals.
N 变小了,exit 仍是 0。 从外部看,"三个 root 都干净"和"其中一个 root 压根没被扫"长得一模一样。
为什么值得单独修
这与 #4851 是同一个缺陷,只是在隔壁脚本里:.claude/workflows/docs-accuracy-audit.js 的 ALL_HANDWRITTEN 清单 11 条路径全部指向改名前的 protocol/objectos/*,于是内部文档审计静默漏审整个 protocol/kernel —— #4781 与 #4817 因此烂了约两个月才被发现。那次的代价是实测过的。
本会话这两天已连关五个同族(#4690 无 MANIFEST 也 exit 0、#4804 判据写在 stderr 而 gate 从不读、#4835 词表少一个入口、#4868 自检与真实调用路径不是同一条、#4890 门禁看不见自己所在的目录)。共同形状:检查在跑,而且是绿的,但结构上接触不到它的检查对象。
.claude 这条尤其脆:它是本地 agent 工具目录,比 content/ / skills/ 更可能被重组。
PR #4915 覆盖了什么、没覆盖什么
#4915 新增的 --self-test 用真实 walker 从真实 ROOTS 走一遍临时树,断言 .claude 进得去、.claude/worktrees 进不去。所以:
- ✅ 有人把
.claude从ROOTS数组里删掉 → self-test 判红; - ❌ 仓库里真实的
.claude/目录被改名 →ROOTS数组没变,self-test 在临时树里照样绿,而真实扫描静默少一个 root。
建议
启动时校验每条 ROOT 都能解析,有一条不行就报错退出并点名,而不是继续跑。catch {} 若确有存在理由(例如某个 root 在某些检出形态下合法缺席),把那个理由写成显式的白名单,而不是一个吞掉一切的空 catch。
顺带看一眼仓内 scripts/ 下还有没有同形状的 catch {} / 静默跳过(几个 check:* 脚本值得一起扫),有就在报告里列出来,由 PM 决定是纳入还是另立。
关联
- PR fix(scripts): check:doc-authoring 覆盖 .claude 语料,worktrees 进 SKIP_PATHS (#4913) #4915 / check:doc-authoring 的 ROOTS 不含 .claude —— agent 语料里的裸 metadata 字面量无人拦 #4913 —— 发现现场
- docs-accuracy-audit.js 的 ALL_HANDWRITTEN 清单 11 条全部指向改名前的 protocol/objectos/* —— 内部文档审计静默漏审整个 protocol/kernel 目录 #4851 —— 同一缺陷在
.claude/workflows/docs-accuracy-audit.js,已派发中 - check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690 /
check:i18n应把 unknown-authoring-key lint 判为失败 —— 否则第十份 extract 配置还会照抄同一个错 #4804 / check:init-service-contract 只认getService,不认getServiceAsync—— #4772 就是从这个洞里溜过去的 #4835 /merge.os-regen.driver指向「上一个装过依赖的 worktree」的绝对路径 —— 该 worktree 一删,全容器的生成物合并驱动就坏了 #4868 /.claude/skills/**的 markdown 不被任何门禁扫描 —— check:nul-bytes 只看 JS/TS,check:doc-authoring 的 ROOTS 不含 .claude/ #4890 —— 同族先例
Activity
xuyushun441-sys commentedon Aug 3, 2026
认领(PM 分派)
session_018iARDqtrhQgz6fVHDeDkbQclaude/issue-4916-doc-authoring-dead-root-hard-errordomain:devx(落点scripts/check-doc-authoring.mjs)阻塞已解除:#4915 已合入 main,该文件当前无在飞 PR。
同批 #4851(PR #4921)刚在隔壁脚本上把同一形状修掉了 —— 而且它揭示的比本单写的更多:那份清单不只有死条目,还有 48 份从未被列过的文档,两个方向同时腐烂且都不出声。本单的
catch {}只是"死 root"这一个方向,接手时请一并想清楚有没有对称的另一个方向(例如某个真实存在的语料目录从未进过ROOTS),有就写进报告。Generated by Claude Code
xuyushun441-sys commentedon Aug 3, 2026
审核通过 — PR #4934 已取消草稿并挂上 auto-merge(SQUASH)
dev 收掉了我在议题里留的白名单余地,理由比我给的更硬。 我写的是"若
catch {}确有存在理由,写成显式白名单";他核查后发现那个假设在这棵树上没有对应现实 —— 三条 ROOT 全部被 git 跟踪且内有跟踪文件,任何能跑pnpm check:doc-authoring的检出都不会缺其中之一。更进一步:一个optional: true标记等于给下一个作者一条受支持的路去让失败闭嘴而不是跟进改名 —— 那就是空 catch,只是说得客气些。所以纯硬错误、无白名单,并把"为什么没有白名单"写进注释防止下一个人以为是漏了。反向验证的关键一条正是本单相对 #4915 的增量:真实把
.claude/改名走开,旧代码打印✓ 215 files cleanexit 0(诚实答案是 219),而 #4915 的 self-test 在这个状态下照样绿 —— 因为它测的是临时树,真实目录改名它看不见。新代码判红并点名.claude — does not exist,两条同时死时两条都点名、存活的不被提及。这条红-绿已折进--self-test常驻,含 not-a-directory 判据。顺带把
walk内层的 try 也删了,理由成立:遍历中途出错同样意味着语料只读了一半,不该报成一次干净扫描。对称方向的调查有实质产出,立了 #4929:ROOTS 之外确实在教 metadata 编写的语料是
docs/(docs/notes/crm-development-standards.mdx16 个 ts 块、docs/adr/0010/0015/0057等)。没有顺手纳入,理由对 —— "纳入整个 docs/ 还是只 adr+design+notes"是范围决定:docs/audits/、docs/handoff/是一次性过程记录,纳入等于让历史快照永久受当前 lint 约束,改两个月前 handoff 里的 bare literal 是伪造记录。还有一条值得记的观察写进了那单:全仓当前零违规,意味着现在纳入是零成本的;拖到有违规再纳入,就变成"要么改史料要么加豁免"的争论。.codex/查过了,是"没有":本检出不存在该目录,且.gitignore:123就是它 —— 纯本地不入库,CI 永远看不到,纳入反而会让硬报错在没有它的机器上误红。scripts/同形扫描找到三个真实同族,合并立了 #4930:check-single-authz-resolver.mjs(唯一扫描根改名 → 0 文件 → 绿)、check-startup-registry-verdict.mjs(讽刺点:该脚本整屏注释在讲"把没验证的东西写成 verified 有多危险")、check-driver-conformance.mjs(目录改名 → 零个 driver → "所有 driver 都合规")。同时逐条排除了不同形状的 catch(glob 展开中途的 catch{continue} 是对的;check-nul-bytes的 unreadable 记了账不是静默)—— 能分清"同族"和"形似而不同族",这个扫描才有价值。落点 2 个文件,零共享文件(
check:doc-authoring在 package.json 已是组合形态,自检自动进 CI)。Generated by Claude Code
fix(tooling): fail check-doc-authoring by name when a declared ROOT i…
fix(scripts): dead scan roots are a hard error in three more check ga…
chore(tooling): doc-authoring 守卫纳入 docs/ 活语料,历史快照按路径豁免 (objectstack-a…