Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

examples/schema-catalog 的 5 个测试文件没有任何 tsc 编译过,而 check-type-check-coverage 的 countTestFiles 只走 src/ —— 看不见,于是报绿 #3968

Closed

Description

@yinlianghui

发现于 #3900 的实现(在 examples/schema-catalog/test/ 补钉子时撞到),不在该 PR 处理 —— #3900 的完成范围被维护者框成「一行注册 flag + 钉子」,这是构建门自身的盲区,属另一类动作。

两处叠加的盲区

一、这个包的测试确实没人编译。

examples/schema-catalog/tsconfig.json:

"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "test"]

而 package.json 的 type-check 就是 tsc --noEmit,包内也没有 tsconfig.test.json。所以 examples/schema-catalog/test/*.test.tsx(当前 5 个文件)没有任何 tsc 调用读过。

二、本该抓这件事的门抓不到,有两个独立原因。

scripts/check-type-check-coverage.mjs:

  • :180 —— testFiles: countTestFiles(resolve(root, dir, "src")) 只递归 src/。这个包的测试在 test/,于是 testFiles === 0,而 :299 的 if (!pkg.hasScript || pkg.testFiles === 0) continue; 直接跳过整个 5c(「Undeclared gap — tests exist and nothing reads them」)检查。
  • :182 —— 即使数到了文件,buildExcludesTests 判据是 /\*\.test\./.test(tsconfig),即「tsconfig 里出现过 *.test. 这样的 glob」。按目录排除("exclude": ["test"])的 tsconfig 匹配不上,于是 testsCovered()(:296)返回 true,再一次判定「已覆盖」。

门当前的输出是绿的:

✅  test type-check coverage: 23/38 packages compile their tests, 15 declared debt (240 errors outstanding), 9 with a narrow type-assertion project.

这个 38 里不含本包 —— 它既不在「compile their tests」的 23 里,也不在 TEST_DEBT 的 15 里,而是根本没进分母。

为什么值得记一笔

这道门的自述把风险写得很清楚:「An unchecked test can assert a contract the compiler never checked, and then read as evidence that the contract holds」(:333-337)。对「按 glob 排除测试、测试放 src/」的包它成立;对「按目录排除、测试放 test/」的包它静默失效。而后者恰好是本仓唯一一个这样布局的包 —— 全仓扫一遍(遍历每个 package.json 所在目录,比较 src/ 内外的 *.test.ts(x) 计数),只有 examples/schema-catalog 命中:in_src=0 outside_src=5。

#3900 的钉子有一半正好落在这个盲区里(那份 demo fixture 的测试就住在这个 test/ 目录),写的时候才发现没人在编译它 —— 也就是说这个盲区已经在影响别的单子的验证强度,只是没人量过。

建议

两侧都收:

  1. countTestFiles 从包根开始递归(排除 node_modules / dist),而不是只从 src/ 开始 —— 否则任何把测试放包根 test/ 的新包都会重新落进同一个洞。
  2. buildExcludesTests 同时识别目录形式的排除("exclude" 里出现 test / tests 目录),不要只认 glob。
  3. 然后给 examples/schema-catalog 配 tsconfig.test.json 并从 type-check 串起来(门的 5a/5b 会检查它 noEmit: true 且真的 include 了测试 glob);若实测有错误,按门的既定做法进 TEST_DEBT 并附实测错误数。

分级说明(诚实标注)

按「今天有没有用户面影响」判,这是门的假绿,受害者是开发/CI 强度而非用户,所以我先打 finding 而不挂 pm:queue。但同时说明:本仓把假绿当一等缺陷处理过(#3288 / #3378 都是「跑了零个测试却报绿」),而这条正是同一族的第三例,只是发生在 type-check 侧。分诊时请按这个族的先例重新评级,不必受我这个标签约束。

关联:#3900(发现于此实现)、objectstack#4118(TEST_DEBT 的总账)、#3009(「配置文件存在但没人跑」的原型)、#3288 / #3378(假绿先例)

Activity

  1. os-zhuang commented on Aug 9, 2026

    @os-zhuang
    Contributor

    Findings triage — PROMOTED: finding → pm:queue (whole-repo seat, no domain label).

    Why promoted rather than held: the card itself invites re-grading by the false-green family precedent, and the precedent governs — #3288 / #3378 ("ran zero tests, reported green") were both treated as first-class defects, and this is the same shape on the type-check side: the gate's own stated risk ("an unchecked test can assert a contract the compiler never checked, and then read as evidence that the contract holds") is currently true of the one package laid out this way. A scoped tooling/gate fix with named lines is auto-queue class; the "victim is CI strength, not users" argument is exactly what the family precedent already rejected.

    Premise check on origin/main @ cdc0e44 (all read, not inferred):

    • examples/schema-catalog/tsconfig.json — "include": ["src/**/*"], "exclude": [..., "test"] verbatim; no tsconfig.test.json in the package;
    • scripts/check-type-check-coverage.mjs:180 — testFiles: countTestFiles(resolve(root, dir, "src")) (src-only recursion) confirmed; :182 buildExcludesTests is glob-only (/\*\.test\./), blind to directory-form excludes; :296 testsCovered and :299 if (!pkg.hasScript || pkg.testFiles === 0) continue; both confirmed — the two independent blind spots stack exactly as described.
    • One count drifted: test/ holds 4 *.test.tsx files on today's main (card says 5) — immaterial, in_src=0 / outside_src=4 still never enters the gate's denominator.

    Dedup: repo-scoped search on check-type-check-coverage / countTestFiles / type-check coverage — no open issue or PR overlaps; #3900 (discovery site) explicitly excluded this from its scope by maintainer framing; objectstack#4118 is the TEST_DEBT ledger, a consumer of this gate's output, not a fix of it.

    The card's three-part suggestion (recurse from package root; recognise directory-form excludes; then wire tsconfig.test.json for this package, entering TEST_DEBT with a measured count if red) is a complete acceptance sketch — dispatchable as-is.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    ContributorAuthor

    PM 分诊轮(session_01GTRjn8xBqp75dk7kFupVRt):finding → 晋级 pm:queue。理由:门缺陷且两个独立原因已锚定(countTestFiles 只递归 src/ + buildExcludesTests 认不出目录形式排除),examples/schema-catalog 的 5 个测试文件零 tsc 覆盖而门报绿 —— PR3973/3984 的钉子正住在这个盲区里,修好后它们获得编译期保护。范围:①check-type-check-coverage.mjs 两处判据修正;②给 examples/schema-catalog 补 test 覆盖(tsconfig.test.json 或 include 调整);③反向钉(人为造一个不被覆盖的测试目录,门必须红)。全仓扫描确认孤例的结论沿用 dev 报告。


    Generated by Claude Code

  3. self-assigned this
    on Aug 9, 2026
  4. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    ContributorAuthor

    🔒 认领(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt,批次 6)。分支 claude/issue-3968-typecheck-coverage-gate;范围按分诊评论:check-type-check-coverage.mjs 两处判据修正 + examples/schema-catalog 的 test 目录纳入 tsc 覆盖 + 反向钉(人为造未覆盖目录门必须红)。文件面:scripts/check-type-check-coverage.mjs + examples/schema-catalog/tsconfig* + 可能的 package.json script;与同批 #3965(同目录但只碰 src/schemas JSON 与 div.tsx)文件不相交,⛔ 不动任何 src/schemas/*.json。


    Generated by Claude Code

  5. added a commit that references this issue on Aug 10, 2026
    94d1d82
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions