ci(devx): type-check ledger 的余量可见化、一键抹平,并拒绝在未构建闭包上测量 (#6376) - #6510
Merged
Conversation
`DEBT`/`TEST_DEBT` 的「记录值高于实测值」不是记账滞后,而是一张**实打实的许可 额度**:两个账本里的每一条 entry,都是它所度量那一层的**唯一看门人**(DEBT 只 在没有 `typecheck` script 时存在,TEST_DEBT 只在没有任何被调用的 tsconfig 读测 试层时存在),所以余量敞着的时候,任何不超过余量的回归都会全绿落地。 driver-mongodb 记 43 实测 10,把 `aggregate` 签名回退实测出的 12 条整个吞掉 —— 一次正当的改进(#6210 消掉 33 条)顺手把下一个人的 pin 变哑了。 本 PR **不**把余量判红(#5278 的裁决继续成立,改进仍然全绿落地),而是: - **可见**:每条 ℹ 提示带上「这道口子现在允许多少条回归静默通过」,并在绿色 收尾行汇总全仓余量。实测 main @ 1818998:11/34 条 entry 合计 310 条余量,占 两个账本记录总量的 15%,其中 199 条集中在 plugin-approvals 一条上。 - **可一键抹平**:`--lower` 把实测值写回账本,抹平一条 entry 不再需要人手敲一 个实测数字。实测值降到 0 的条目**不写**(那是毕业,不是更低的天花板)。 - **拒绝在未构建的依赖闭包上测量**:tsc 通过依赖的 `dist/*.d.ts` 解析工作区 导入,闭包没构建时测量不会失败,只会**测到另一个世界** —— 同一棵树同一个 commit,packages/lint 构建后实测 19、未构建实测 147(TS2307 x71 + 级联)。 偏差在两个方向上都无界,所以这里改为**前置拒绝**而不是扫 tsc 输出(账本里 本来就有条目把 TS2307 记为真实债务)。 自测新增 21 条(built-closure 12 + auto-lowering 9)与 4 条 #6376 用例,其中 driver-mongodb 那一对是把「余量吞掉回归」这件事本身钉下来:同一棵树同一次回 归,天花板 43 时门禁沉默、天花板 10 时判红。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
hotlong
marked this pull request as ready for review
August 8, 2026 02:46
hotlong
enabled auto-merge
August 8, 2026 02:46
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 #6376
结论先行:判据不是阈值,但也不是「有没有第二个看门人」
派单和出处方的分析都建立在一个布尔判据上:测试层在某个 tsc program 里 vs 被 tsconfig 排除。这个论证本身是对的,但实测表明它在账本内部恒为真,因此划不出子集:
TEST_DEBT19/19 条excludesTests(该包typecheckscript 调用的 tsconfig 没有一个读测试层),否则 TESTS_COVERED / RECONCILED 二者必红DEBT15/15 条typecheckscript(否则 RECONCILED 红);根条目@objectstack/spec-monorepo同理没有typecheck:rootpaths映射dist/*.d.ts解析,别的包的 program 不会把这些源文件拉进去⇒ 「有第二个看门人」的那一类,恰好就是「压根没有账本条目」的那一类,而没有条目就不可能有余量。所以方向 3 不是一次收窄,它展开后等于方向 1(全量抹平),也就正好是 #5278 判过不该付的那笔记账过路费。
出处方那句话仍然成立,而且比原文更强:余量从来都是许可额度,没有例外。今天全仓 11 条 entry 合计 310 条余量,占两个账本记录总量(2072)的 15%,其中 199 条集中在一条上。
实测表(main @
1818998,全量 build 后--re-measure,两次逐字节一致)@objectstack/plugin-approvals@objectstack/plugin-auth@objectstack/lint@objectstack/rest@objectstack/plugin-security@objectstack/service-storagetypecheckscript,源码层无人读)@objectstack/mcp@objectstack/runtime@objectstack/objectql@objectstack/service-automation@objectstack/http-conformanced8e8d9cbc)已全面失效:5 条变 11 条,最大余量从 -19 变 -199,plugin-approvals/plugin-auth/plugin-security是新出现的。两条未确认项已实测:service-storage记的是DEBT(源码层),它同样没有第二个看门人;@objectstack/mcp确实排除测试层。派单方转来同一条 entry(
@objectstack/lint)当天在并行 agent 之间流通的三个读数:19 / 39 / 147。我复现了其中的成因:同一棵树、同一个 commit、相差 7.7 倍,而两次运行都没有任何告警。 tsc 经由依赖的
dist/*.d.ts解析工作区导入,闭包没构建时测量不会失败,只会测到另一个世界;而且偏差在两个方向上都无界 —— 未解析的 import 让每个符号退化为any,凭空造出 TS2307/TS7006 的同时抹掉真正的结构性不匹配(TS2345/TS2322)。driver-mongodb那 33 条 TS2345 正是这一类,在未构建的@objectstack/spec面前会实测为 0。这直接决定了方向:一个不可复现的量,撑不起任何以「记录值 vs 实测值」为判据的政策,而方向 1 / 方向 2 都要求人手写下一个实测数字。所以本 PR 先让这个数字变得可信。
同一环境内它是确定性的:两次全量
--re-measure逐字节一致(1762 total),所以这不是 tsc 的不确定性,是环境/树的差异 —— 正是 ledger 头部要求先证伪的那一条。本 PR 做了什么(方向:auto-lowering,不判红)
⛔ 没有把余量判红。#5278 的裁决继续成立,改进仍然全绿落地。做的是三件让余量可见、可信、一键可抹平的事:
可见 —— 余量被量化并在绿色运行上报告。 每条 ℹ 现在直说这道口子允许多少条回归静默通过,收尾行汇总全仓:
「看不见的额度」才是伤人的部分。
可一键抹平 ——
--lower把实测值写回账本。 抹平一条 entry 不再需要人手敲一个实测数字(见上一节:人手敲的数字来自一个可能不是 CI 那个的环境)。实测跑过一次全量:11 条 entry 精确改写 11 处errors:,notes 与结构零损伤,并正确区分了同名跨账本的@objectstack/rest(DEBT 2 未动,TEST_DEBT 163 → 144)。实测值为 0 的条目不写 —— 那是毕业,写 0 会让下一次结构闸门直接红。可信 —— 拒绝在未构建的依赖闭包上测量。 前置检查(每个
workspace:依赖是否有已构建的类型入口),而不是扫 tsc 输出里的 TS2307:账本里本来就有条目把 TS2307 记为真实债务(根条目 note 明写TS2307 x17),一个分不清「记录在案的缺陷」和「测坏了的测量」的闸门,会去拒绝它本该测量的条目。钉住缺陷本身的那对用例
自测里最重要的不是新增数量,是这一对 —— 同一棵树、同一次回归,只有天花板不同:
门禁
pnpm lint(ESLint)pnpm check:type-check-debt34 ledger entr(ies) re-measured in 199.3s, 1762 raw tsc error(s) total, none above its recorded number.--self-test23 semantic + 16 observation + 15 re-measure + 12 built-closure + 9 auto-lowering case(s) hold.(新增 21 条 + 4 条 #6376 用例)pnpm check:nul-bytesscanned 6105 tracked text file(s) ... no raw ASCII control bytesgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'→ 0 hitspackages/formula/dist后--re-measure立即拒绝并点名该包,未启动任何 tsc反向验证(先声明,后运行)
unbuiltClosure()退回宽容分支lowerLedgerEntries()退回恒等plannedLowerings()去掉 0 值守卫R3 的分歧就是发现,不改声明:我按「负向断言会空过」把 3 条
applied === 0的用例整体划为空过,实际只有 1 条是(空计划那条)。另外两条断言的是skipped === 1—— 「拒绝被记录下来了」是一条正向断言,反转后skipped变空数组照样红。教训:空过与否要按每条断言判,不是按用例的方向判。R5 是专门用来证明 mongodb 那一对不空过的:把棘轮本体反转后,「同一次回归在 10 天花板下判红」立刻红,说明第二条确实在测东西。
R6(不是反转,是相反方向的一次测量):把余量改成判红,会有 4 条既有语义翻面,其中包括
a count that shrank is a note, never red—— 也就是说,#5278「改进不该付过路费」的裁决不只是散文,它是一条被钉住的断言;要把余量判红,就得先把它翻面。这条数据留给维护者决策用。⛔ 有意没做的事
--lower的全量演示跑过,产出的 11 处改动已还原、未提交。派单明确禁止攒批,而objectql/rest是活跃包([finding] DEBT ledger counts in check-type-check-coverage.mjs drift silently — @objectstack/metadata-protocol records 28, actually reports 63 #5278 的 option D 输过五次);11 条一把抹平必然在合并前失效。抹平应当一条一 PR、落地即合,而现在做这件事不再需要人手敲数字。packages/lint/src/validate-semantic-roles.test.ts:10那处缺.js的 import(单点可消 5 条,净减台账)—— 超出本单文件面,且 [P2] framework: 66 个包用 tsup 构建、无人做类型检查 —— 实测 18 个包共 380 处 code-tier 错误(#4118 的 framework 侧对应) #4311 已在追踪该类。留给维护者的一个判决
维护者的推进意见是「auto-lowering(或 surplus ceiling),而不是让改进变红」。本 PR 交付了 auto-lowering 的机制,但它是自愿的;而实测给出一个不利于「自愿」的证据:ℹ 提示自 #5278 落地起每次 CI 都在打印,五条 entry 的 note 自己写着「tighten immediately after landing」,至今一条都没被抹平,余量反而从 5 条涨到 11 条。也就是说,纯提示性的机制在这个仓库里已被实测证伪。
所以真正的判决是:记录值过期,要不要变成红?
--lower一条一 PR 抹平,最后再开强制。我的建议是 B,但必须按上面的排序执行,且只在 11 条全部抹平后再开;在那之前保持 A。理由:(1)真实业务需求 —— 310 条许可额度里有 199 条压在
plugin-approvals这个隐藏测试层最大的包上,而 mongodb 已经实测证明这种额度会吞掉真实回退;(2)长期健康 —— 唯一看门人的天花板必须是紧的,否则这两个账本只是在声称冻结;(3)让 AI 写的代码难以出错 —— 强制 +--lower意味着数字永远由做过测量的工具写下,而不是由人从一个可能不是 CI 的环境里抄来,这正是本 PR 第三项修复要解决的问题。⛔ 但 B 是判决,不是我该替维护者做的猜测,所以本 PR 不实施。Generated by Claude Code