ci(dx): 两个发现型闸门补「发现数」非空断言 —— 语料/驱动轴静默蒸发即红 (#4932) - #5917
Merged
Conversation
两处都靠「扫描发现目标 → 逐个检查」工作,而空集合天然通过所有检查。#4932 正文点的两处 `catch {}` 在 origin/main 上已经不在了(#4916 / #4930),留下的 是同一族里下限断言这一半:发现环节成功、发现结果为空,仍然报绿。 check-doc-authoring:每个 ROOT 必须至少产出一个 .md/.mdx。#4916 的 assertRootsResolvable 只看得见「根不是目录」;根还在、语料搬走了(子树迁出、 SKIP_PATHS 收得更宽、扩展名换了)时它是满意的,walk 少收一批,打印的计数 静默变小 —— `✓ 362 files clean` 与 `✓ 0 files clean` 对读者是同一句话,对 CI 是同一个退出码。下限按根算而不是按总数:总数会被还有文件的那个根托住 (`.claude` 一个就够),而「语料被读了一部分」正是这道闸不该往语料有利方向 解释的判定。断言放在 collectFiles 里,self-test 因此驱动不变量本身而不是它的 代理。不引入需要维护的高水位棘轮 —— 阈值只有「每个声明的根 ≥ 1 个文件」, 由本次 walk 现算。 check-driver-conformance:DISCOVERED 的零下限本来就在(#4363),补的是它看不见 的那一半 —— 整根蒸发会红,单行蒸发不会。把 packages/drivers/driver-sql 改名成 sql,包照样构建、照样测试、照样发布,只有这道闸丢了它,而且丢成「少一行的 矩阵 + 绿」。所以发现改为**完备**:DRIVERS_DIR 下每个条目要么是发现到的 driver,要么不是目录,要么在这里按名报红(unnamed / manifestless)。今天这 一类改名恰好会被 RECONCILED 抓到,但只在台账非空时成立,而空台账是本闸的 预期稳态(#5590 到 #5701 之间就是空的)—— 那是巧合,不是机制。顺带收掉 #4930 漏下的一处 swallow:manifest 探测的 `catch { return false; }` 会把任何 读取失败答成「那就不是 driver」,现在只有 ENOENT 才是该过滤器要问的问题。 反向验证方向先定后跑,三种方向都实测: - 语料整体消失(四个根都在、都空):旧 `✓ 0 files clean` exit 0 → 新 exit 1。 - 单根蒸发(content 只剩非 markdown):旧 `✓ 3 files clean` exit 0 → 新 exit 1, 只点名 content 并报出总数 3。 - 根被改名(#4916 原案):旧红、新红 —— 方向不变,这一半没有被削弱。 - driver-sql 改名为 sql:今天台账非空,所以**颜色不翻**,变的是诊断 —— 旧只报 RECONCILED(怪台账,点错原因),新多报一条 DISCOVERED 点名 packages/drivers/sql。颜色真正会翻的是空台账稳态,已在 self-test 里按 discoveredErrors 的判定钉死(旧实现在同一份合成树上 discovered=[driver-a]、 DISCOVERED errors=0,绿)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GX3sL71LFq8m2usg6VqTSE
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
os-zhuang
marked this pull request as ready for review
August 6, 2026 11:42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #4932
两个闸门都靠「扫描发现目标 → 逐个检查」工作,而空集合天然通过所有检查。本单补的是这一族里下限断言那一半。
先说前提核对:issue 的两条子断言在 origin/main 上都已不成立
按 origin/main(7357130)逐条实测,#4932 正文点名的两处
catch {}都已经不在了:check-doc-authoring.mjs:45的for (const r of ROOTS) { try { walk(r, files); } catch {} }吞掉 ROOT 缺失assertRootsResolvable()先解析全部 ROOT,死根按名报红;collectFiles里没有任何 catchcheck-driver-conformance.mjs:150的listDir兜底空数组 → 发现 0 个 driver → 无事可做 → 通过listDir现在是裸readdirSync;而且 DISCOVERED 不变量本来就在(discoveredErrors),零 driver 直接报红,模块头也已经把「账本可空 ≠ 发现结果可空」这条区分写清楚了所以本 PR 不是照抄 issue 的修法,而是修它们剩下的那一半——发现环节成功、发现结果为空/偏少,仍然报绿:
check-doc-authoring:全部四个 ROOT 都解析成功、一个文件都没扫到时,旧代码打印✓ 0 files clean并 exit 0。这正是 issue 正文写的「极端情况」,而 check-doc-authoring 的 walk 用catch {}吞掉不存在的 ROOT —— 目录一改名,门禁静默变瞎并继续报绿 #4916 的断言看不见它。check-driver-conformance:DISCOVERED 只在整根蒸发时开火,单行蒸发时沉默。check-doc-authoring:每个 ROOT 至少产出一个 .md/.mdx
assertRootsResolvable只看得见「根不是目录」。根还在、语料搬走了(子树迁出、SKIP_PATHS收得更宽、扩展名换了)时它是满意的:walk 少收一批,打印的计数静默变小,而✓ 362 files clean与✓ 0 files clean对读者是同一句话、对 CI 是同一个退出码 —— 这就是 #4932 说的「计数被打印,但从未被断言」。下限按根算而不是按总数:总数会被还有文件的那个根托住(
.claude一个就够),而「语料只被读了一部分」恰恰是这道闸不该往语料有利方向解释的判定。断言落在collectFiles里(不是main),self-test 因此驱动不变量本身而不是它的代理。没有加棘轮:阈值只有「每个声明的根 ≥ 1 个文件」,由本次 walk 现算。高水位棘轮需要有人维护,还会把每次正当删除变成一场跟数字的争论 —— 派发词倾向不加,这里也确实找不到可测不可拍脑袋的阈值来源。
check-driver-conformance:发现改为「完备」,而不只是「非零」
把
packages/drivers/driver-sql改名成sql,包照样构建、照样测试、照样发布 —— 只有这道闸丢了它,而且丢成「少一行的矩阵 + 绿」。所以发现现在是完备的:DRIVERS_DIR 下每个条目要么是发现到的 driver,要么不是目录,要么在这里按名报红(unnamed/manifestless),没有任何东西被静默过滤掉。一个必须说清的细节:今天这类改名恰好会被 RECONCILED 抓到(台账里有 driver-sql 的条目),但那只在台账非空时成立,而空台账是本闸的预期稳态(#5590 到 #5701 之间就是空的)。模块头自己就写着 RECONCILED 的反向只走 LEDGER —— 所以那是当前 FILTER_TEXT 五行带来的巧合,不是机制。
顺带收掉 #4930 漏下的一处 swallow:manifest 探测的
catch { return false; }会把任何读取失败答成「那就不是 driver」。现在只有 ENOENT(即这个过滤器真正要问的问题)才这样解释,其他 errno 直接抛。反向验证:方向先定后跑,四组,含一组颜色不翻的
✓ 0 files cleanexit 0 → 新 exit 1✓ 3 files cleanexit 0 → 新 exit 1,只点名content并报出总数 3driver-sql改名为sqlRECONCILED: ledger entry for driver-sql, which is not a driver package.(怪台账,点错原因);新多报一条DISCOVERED: packages/drivers/sql is a package … but is not named driver-*。两边都是 2/1 problem(s),都红最后一行是本单唯一「预测就不是 before-green/after-red」的地方,如实记账:今天的台账非空,所以颜色本来就红,新断言改的是把原因点对。颜色真正会翻的是空台账稳态 —— 在同一份合成树上跑 origin/main 的发现实现,得到
discovered=[driver-a]、DISCOVERED errors=0(绿),而sql是个带 package.json 的真包却根本不在矩阵里;这一条已在 self-test 里按discoveredErrors的判定钉死,不依赖台账当时是什么状态。self-test 与门禁实测
两个脚本仓内都已自带
--self-test(package.json的check:*也早已是--self-test &&的形式),所以是补用例,不是新建 self-test。check-doc-authoring新增:单根为空 → 红且只点名该根、并报出这次真扫到的总数 → 恢复后绿;全空 → 红、点名四个根、总数 0。check-driver-conformance新增:两种丢行形状各自报红且点名(即使 driver 已发现非零)、合成树上的三分类(discovered / unnamed / manifestless)、一个 stat 不到的条目是报错而不是更小的轴(dangling symlink,ENOENT)、去掉破坏后判定复原,以及活树上两种丢行数都为 0。实跑(worktree,origin/main 之上):
node scripts/check-nul-bytes.mjs之外另做了越界自扫(grep -naP覆盖0x01–0x1f/0x7f),无命中。发布物
tooling-only,
scripts/**两个文件,不发布任何包 ⇒ 无 changeset,PR 带skip-changeset标签(标签由本座位落,回读结果写在报告里)。CI 挂载点未动(.github/workflows/lint.yml的两处run:原样)。范围与另行立单
scripts/check-doc-authoring.mjs+scripts/check-driver-conformance.mjs。未动 workflows、未动content/docs/releases/**;filterjob 一旦失败,Test Core / Build Core / Dogfood 会全部 skipped 而分支保护判为通过 —— 隐式 success() 今天已第三次咬人 #4928(Actions 层同族)不在本单。scripts/的),没有任何 open PR 在改这两个文件。scripts/check-single-authz-resolver.mjs已补 check-doc-authoring 的 walk 用catch {}吞掉不存在的 ROOT —— 目录一改名,门禁静默变瞎并继续报绿 #4916 那一半,但collectScanFiles()的返回长度从不断言 —— 根解析成功、一个文件都没扫到仍然绿,而它自己的模块头就写着「nobody reads a count that is not printed」。不在本单文件面内,按 Prime Directive chore: version packages #10 立为 observation-class:check-single-authz-resolver 的扫描语料没有下限断言:根解析成功但一个文件都没扫到仍然绿(observation) #5916(finding标签,未入队、未指派)。Generated by Claude Code