fix(qa,dx): 让 dogfood 的 strict tsconfig 真正被执行 —— 修 14 条积压并接进 turbo typecheck (#4855) - #5002
Merged
Merged
Conversation
…pecheck (#4855) `packages/qa/dogfood/tsconfig.json` 是一份认真的配置(strict、NodeNext、 include 覆盖 test/**),但 package.json 的 scripts 里只有 `test`。根 `pnpm typecheck` 是 `turbo run typecheck`,只跑声明了该 script 的包 —— 三个 qa 包里这是唯一没声明的一个,于是这份配置从未被执行过。 #4311 的覆盖率闸门看见了这个洞,但把它记成 DEBT(errors: 12)冻结下来。 DEBT 是「暂缓」不是「豁免」:在最新 main 上实测是 14 条,比冻结时多了 2 条 —— 漂移本身就是不能长期用冻结替代执行的证据。 14 条全部修掉: - NodeNext 缺扩展名(2 条 TS2307 + 1 条级联 TS7006):两处 `./field-zoo.matrix` 补 `.js`。包内另外 33 处相对 import 全都带 `.js`,这两处是仅有的例外。 - flow fixture 的 `type` 没收窄(8 条 TS2322):四个 fixture 的 flow 是裸对象 字面量。按 examples/app-todo 的既有写法标注 `: Flow`,而不是 `as const` —— 整份 fixture 因此被 spec 的真实契约检查,而不只是让报错闭嘴。 - 条件展开出的 headers(2 条 TS2322):给 auth 常量标注 Record<string, string>。 - 连接器 handler 少传参(1 条 TS2554):`handler!({})` 改为 `handler!({}, {})`。 `McpConnectorBundle.handlers` 声明的是 (input, ctx),引擎侧 connector-nodes.ts 也始终按两参数派发;这条一直「能跑」只因这个 handler 恰好忽略 ctx。按声明 修正调用方,没有放松任何契约。 接进执行:package.json 加 `"typecheck": "tsc --noEmit"`,并按闸门的 RECONCILED 不变式在同一个 PR 里删掉 DEBT 条目。覆盖率 60/77 → 61/77,DEBT 17 → 16 个包。 反向验证:塞一个非法 flow `type`,`turbo run typecheck` 判红并精确指出该行; 移回后判绿(命中修复前那次绿跑的同一个 turbo hash)。 `pnpm --filter @objectstack/dogfood test` 481 passed / 3 skipped,行为未变。 Fixes #4855 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 19:56
xuyushun441-sys
enabled auto-merge
August 3, 2026 19:56
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.
Fixes #4855
问题
packages/qa/dogfood/tsconfig.json是一份认真的配置 ——strict: true、module/moduleResolution: NodeNext、include覆盖test/**/*。但packages/qa/dogfood/package.json的 scripts 里只有test。根pnpm typecheck是turbo run typecheck,只跑声明了该 script 的包;三个 qa 包里(downstream-contract、http-conformance、dogfood),这是唯一没声明的一个 —— 于是这份 strict 配置从未被执行过。这就是「declared ≠ enforced」在构建配置层的形状:读代码的人(和写代码的 agent)会合理假设它在 CI 里把关,照着它的严格度写;实际没有任何一步跑它。而 dogfood 是本仓最重的行为门,它的 fixture 类型漂移此前没有任何东西会挡。
覆盖率闸门为什么没抓到
抓到了,但记成了冻结债务而不是缺口。
scripts/check-type-check-coverage.mjs的DEBT账本里有:该闸门的
COVERED不变式接受「声明了typecheckscript」或「有一条带实测错误数的 DEBT 条目」。dogfood 走的是后一条,所以闸门一路绿灯 —— 它诚实地记录了这个包没被检查,但记录不等于执行。DEBT 是暂缓,不是豁免,而且会漂移:账本冻结于
b07d829(2026-07-31)时是 12 条,我在最新 main(7d0e7b5)上实测是 14 条。多出来的 2 条正是「冻结不能长期替代执行」的直接证据 —— 门后的东西只会继续涨。所以本 PR 走的是账本注释里写明的毕业路径:修完错误 → 加 script → 同一个 PR 里删掉 DEBT 条目(否则RECONCILED不变式会失败)。实测的 14 条与修法
./field-zoo.matrix补.jstype没收窄 TS2322: FlowRecord< string, string >1. NodeNext 缺扩展名。
field-zoo-roundtrip.dogfood.test.ts与field-zoo-value-shape.test.ts写from './field-zoo.matrix'。文件确实在,但moduleResolution: NodeNext要求.js。这不是风格问题:包内另外 33 处相对 import 全部带.js,这两处是仅有的例外。未解析的 import 让符号退化成any,回调参数随即报 implicit-any —— 补上扩展名同时消掉那条级联的 TS7006。2. flow fixture 的
type。 四个 fixture 里的 flow 是裸对象字面量,type: 'autolaunched'推成string,喂给defineStack时对不上字面量联合。修法不是as const,而是按仓内既有写法(examples/app-todo/src/flows/task.flow.ts)标注:差别是实质性的:
as const只让报错闭嘴,: Flow让整份 fixture 被 spec 的真实契约检查。反向验证那一步(见下)正是靠这个标注才判红的。3. headers。
token ? { Authorization } : {}在匿名分支上推出Authorization?: undefined,展开进headers后HeadersInit(Record< string, string >)拒收。给该常量显式标注即可。4. 连接器 handler —— 这条值得单独说。
showcase-mcp-self-connection.dogfood.test.ts调handler!({}),但契约声明的是两个参数:引擎侧也始终按两参数派发(
service-automation/src/builtin/connector-nodes.ts:90:await handler((cfg.input ?? {}) as Record< string, unknown >, handlerCtx)),connector-mcp 自己的测试同样写handlers.create_issue({...}, {})。这条调用一直「能跑」,只是因为 MCP 这个 handler 的实现恰好忽略ctx—— 契约上它是错的,是一处被这道没人跑的门盖住的真实契约违反(运行时不炸,但它在冒充引擎的调用而少传了引擎必给的东西)。按契约优先修的是调用方:改成
handler!({}, {})。反方向(把ctx改成可选)会为了迁就一个测试而放松 connector-mcp 的公开契约,是错误方向,没有采纳。接进强制执行
外加删除
check-type-check-coverage.mjs里的 DEBT 条目。闸门自测与实跑:覆盖率 60/77 → 61/77,DEBT 17 → 16 个包。
turbo.json的typecheck任务与 lint.yml 的调用都已存在(闸门的RUNNABLE不变式在管),无需改动 —— 缺的只是这个包的 script。反向验证
在
flow-touch-fixture.ts里把type改成'not_a_real_flow_type',走真实 CI 入口:改回后:
238d29ba02f83710与注入前那次绿跑是同一个 turbo hash —— 证明状态被精确还原,绿不是残留缓存蒙对的。测试
零行为改动:所有修改要么是类型标注,要么是补模块扩展名,要么是把调用补齐到既有契约(
ctx在这个 handler 的实现里本就未被读取)。ESLint 干净。改动范围
限于
packages/qa/dogfood,加两个接线文件:scripts/check-type-check-coverage.mjs—— 根目录共享文件,只删掉 dogfood 那一条 DEBT 条目(账本注释里写明的毕业动作;不删则RECONCILED不变式失败)。未改动闸门的任何语义。.changeset/dogfood-typecheck-wired.md—— 内部 qa 包 + dev script,按per-package-typecheck-coverage.md/ci-performance-optimization.md的先例用空 frontmatter,不发版。turbo.json与.github/workflows/lint.yml未改动。Generated by Claude Code