Skip to content

packages/qa/dogfood 的 tsconfig 没人跑 —— 14 个类型错误积在一个「声明了但未执行」的门后面 #4855

Description

@os-zhuang

发现于 #4700 的收尾验证(顺手跑了一次 tsc --noEmit),与那条 issue 无关,按 Prime Directive #10 单独归档,未在 #4700 的 PR 里修。

现象

packages/qa/dogfood/tsconfig.json 是一份认真的配置 —— strict: true、module/moduleResolution: NodeNext、include: ["src/**/*", "test/**/*"]。但 packages/qa/dogfood/package.json 的 scripts 只有 test:

包 scripts
packages/qa/dogfood test
packages/qa/downstream-contract typecheck, test
packages/qa/http-conformance test, typecheck

根 pnpm typecheck 是 turbo run typecheck,只会跑声明了该 script 的包。于是 dogfood 这份 tsconfig 从来没有被执行过 —— 三个 qa 包里唯一漏掉的一个。

积下来的量

$ cd packages/qa/dogfood && npx tsc --noEmit 2>&1 | grep -c "error TS"
14

分三类:

  1. NodeNext 缺扩展名(2 处) —— field-zoo-roundtrip.dogfood.test.ts:24 与 field-zoo-value-shape.test.ts:17 都写 from './field-zoo.matrix'。文件确实在(test/field-zoo.matrix.ts),但 moduleResolution: NodeNext 要求 './field-zoo.matrix.js',所以报 TS2307: Cannot find module。vitest 能跑,tsc 不认。
  2. fixture 里的 flow type 没收窄(多处) —— test/fixtures/flow-durable-suspend-fixture.ts:103、flow-function-effect-fixture.ts:71 等,对象字面量推成 type: string,赋给 flow 那个字面量联合(api | schedule | autolaunched | screen | record_change)时失败。加 as const 或显式标注即可。
  3. 条件展开出的 headers 类型(2 处) —— attachments-permission-matrix.dogfood.test.ts:67,81,token ? { Authorization } : {} 展开后与 HeadersInit 不兼容。

为什么值得记一笔

这就是「declared ≠ enforced」在构建配置层的形状:一份 strict 的 tsconfig 摆在那里,读代码的人(和写代码的 agent)会合理地假设它在 CI 里把关,于是照着它的严格度写;实际上没有任何一步跑它。dogfood 是这个仓最重的行为门,它的 fixture 类型漂移没有任何东西会挡。而且它是可修的:14 个错误都是机械性的,没有一个需要架构决定。

建议

  1. 先把这 14 个修掉(三类都是小改)。
  2. 给 packages/qa/dogfood/package.json 加 "typecheck": "tsc --noEmit",让它进 turbo run typecheck 的图 —— 与两个 sibling qa 包一致。
  3. 顺序不能反:先加 script 会直接把 typecheck 作业弄红。

如果结论是「dogfood 故意不做类型检查」,那么该删的是这份 tsconfig(或把它降到非 strict),而不是让一份没人执行的严格配置继续留在那里误导人。

Refs: #4700(发现处)、Prime Directive #10

Activity

  1. xuyushun441-sys commented on Aug 3, 2026

    @xuyushun441-sys
    Collaborator

    认领(PM 分派)

    • session:session_018iARDqtrhQgz6fVHDeDkbQ
    • 分支:claude/issue-4855-dogfood-typecheck-wired
    • 车道:domain:devx(落点 packages/qa/dogfood)

    阻塞解除:#4719 的 PR #4999 已过审进队(动了同包的 enterprise-organizations 测试),从最新 main 开分支即可。本单形状与全会话主线一致:strict tsconfig 声明了、没有 typecheck script 执行它 —— declared ≠ enforced,14 个类型错误积在门外。


    Generated by Claude Code

  2. xuyushun441-sys commented on Aug 3, 2026

    @xuyushun441-sys
    Collaborator

    审核通过 — PR #5002 已取消草稿并挂上 auto-merge(SQUASH)

    议题前提被更正,而更正后的事实比原指控更有说服力:check-type-check-coverage 的门禁不是没看见这个包 —— 它把 dogfood 记成了 DEBT(12),COVERED 不变量被"有台账条目"这条分支满足。真实的发现是:台账在 3 天里从 12 漂到 14 —— 用一条记录顶替一次执行,记录就会漂,这正是毕业(修完 + 接线 + 同 PR 删台账条目)而非重测计数的论据。dev 走的正是台账自己文档写明的毕业路径,COVERED / RECONCILED 两条不变量都不违反。覆盖率 60/77 → 61/77。

    14 个错误里挖出一个真契约缺陷(议题的三类机械分类漏了它):测试用 handler!({}) 冒充引擎派发,而引擎总是传两个参数 —— 只因这个 MCP handler 恰好忽略 ctx 才一直没炸。修在调用点(补第二参)而不是把生产者的 ctx 放宽成可选 —— 方向对:contract-first,不为测试的便利松动生产契约。

    : Flow 优于议题建议的 as const,理由是本质性的:as const 只让报错闭嘴,类型标注让整个 fixture 对着 spec 的真实 schema 被检查 —— 反向验证的 sabotage(塞非法 type 字面量)之所以能被抓到,全靠这一点。而且标注后零额外报错,证明 fixtures 一直结构合法,只是 type 字面量此前不受约束。

    恢复证明用了 turbo 的缓存哈希:revert 后 cache hit, replaying logs 238d29ba02f83710,与注入前的绿运行哈希逐字相同 —— 精确态恢复,不是陈旧缓存的假绿。这个证法值得推广。

    共享文件:scripts/check-type-check-coverage.mjs 删 4 行台账(毕业要求),零冲突面。

    留给维护者的一条观察(dev 提出,不立单):DEBT 机制的固有漂移(3 天 +2)说明冻结数字的台账需要一个"重测对账"的节拍,否则每个 DEBT 条目都在静默过期 —— 若哪天有人想做,check-type-check-coverage 的 self-test 是现成的挂点。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions