Skip to content

ci(dx): DEBT/TEST_DEBT 台账数字改为每次重测的真棘轮 —— 实测 > 记录即红 (#5278) - #5827

Merged
os-zhuang merged 17 commits into
mainfrom
claude/issue-5278-debt-ledger-ratchet
Aug 7, 2026
Merged

ci(dx): DEBT/TEST_DEBT 台账数字改为每次重测的真棘轮 —— 实测 > 记录即红 (#5278)#5827
os-zhuang merged 17 commits into
mainfrom
claude/issue-5278-debt-ledger-ratchet

Conversation

@baozhoutao

@baozhoutao baozhoutao commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #5278

前提核验(先做,结论:成立,且比 issue 报的更普遍)

派发令要求先验「重测在 CI 的成本可承受」。落点查清了:check-type-check-coverage.mjs 目前只在 .github/workflows/lint.ymltypecheck job(lint.yml:487)跑一次,而同一个 job 后面就有 Build workspace packages(turbo run build),以及 Type check workspace packages。也就是说「需要构建产物」的重测有一个天然落点:同一个 job 的构建步骤之后,不必新开 job、不必重复付构建的钱。

CI 实测(run 31081897969):

步骤 耗时
Build the ledgered packages' dependencies 79ms,71 cached / 71 total,FULL TURBO
pnpm check:type-check-debt(重测本体) 198.2s ≈ 3m19s
TypeScript Type Check job 全长 9m24s

新增的 build 步骤在 CI 上是全缓存命中,成本为零;重测本体 3m19s。远低于派发令给的「大于 10 min 且无法复用」的否决线,所以按裁决实现选项 1

顺带核了 issue 引用的当前状态:scripts/check-type-check-coverage.mjs 昨天确实被 PR #5725 动过(#5561resumeAuthority),service-automation 的 note 已经因此改写过一次,但数字仍是 2errors 断言仍是纯存在性检查 —— issue 的前提原封不动地成立。

问题

闸门只断言「有一条台账、数字为正」:

if (!entry || typeof entry.errors !== 'number' || entry.errors <= 0) { ... }

errors: 28errors: 1 对它完全等价。这一层对新增 debt 是关着的,错误条数这一层不是 —— 台账从不复测,所以一个新测试文件带进来的错误没有任何一道闸会看见。AGENTS.md 写着「DEBT is frozen debt, not a permission slip. Every entry below was measured」,而一个悄悄漂了 2.25 倍的数字不再描述它声称冻结的那笔债。

全量重测结果(sweep @ 5ab08428)

34 条全测:17 条低估、2 条高估、15 条精确,没有一条是因为债在缩小而失真的。下表「实测」列为本 PR 最终落账值;两条带「见下文竞态」的是在本 PR 生命周期内被 main 推着又校准过的。

条目 记录 实测
@objectstack/metadata-protocol 28 63 issue 主贴那条
@objectstack/spec-monorepo(仓库根) 50 80
@objectstack/core 91 98
@objectstack/metadata 87 92
@objectstack/service-knowledge 8 10
@objectstack/service-analytics 3 7 线索贴样本
@objectstack/service-automation 2 5 线索贴样本
@objectstack/plugin-approvals(TEST_DEBT) 467 547
@objectstack/objectql(TEST_DEBT) 219 335 绝对增幅最大;sweep 时 333,见下文竞态
@objectstack/rest(TEST_DEBT) 105 143 见下文竞态
@objectstack/plugin-auth(TEST_DEBT) 124 129
@objectstack/lint(TEST_DEBT) 26 30
@objectstack/plugin-security(TEST_DEBT) 20 21
@objectstack/formula(TEST_DEBT) 12 17
@objectstack/trigger-record-change(TEST_DEBT) 8 9
@objectstack/verify(TEST_DEBT) 6 8
@objectstack/http-conformance(TEST_DEBT) 1 4
@objectstack/runtime(TEST_DEBT) 220 218 高估
@objectstack/driver-mongodb(TEST_DEBT) 44 43 高估

新的 MEASURED 不变式

--re-measure 对每条 DEBT 跑该包自己的 tsc --noEmit -p .../tsconfig.json;对每条 TEST_DEBT,生成一份 extends 原配置、只去掉 test 排除项的临时兄弟配置再跑(生成在包目录内 —— tsconfig 的 include / outDir / rootDir 都相对声明它的那个文件解析,放到别处会把它们统统改指;finally 里删除)。

判定是不对称的,这是核心:

  • 实测 大于 记录 → 。这才是棘轮。
  • 实测 小于 记录 → 打印 ℹ … can be lowered,不红。修错误不应该还要先改一个记账数字才能让 CI 变绿,否则台账就是在对它本该鼓励的工作收费。
  • 实测 = 0 → 报告 graduation candidate(毕业仍是显式 PR:加 typecheck script + 删条目,由 COVERED / RECONCILED 双向强制)。

计数口径与台账里每个数字当初的量法一致(grep -c "error TS"),只是加了 --pretty false 让它不依赖有没有 TTY。多行 elaboration 的缩进行不计数,无文件前缀的全局诊断计数。另有一道防呆:tsc 以非零码退出却没打出可识别诊断、或打出 TS5058/TS6053/TS18003 这类「读不到 project」的诊断时,抛错而不是记 0 —— 一个量不到东西却报告「改善了」的闸门比没有闸门更糟。

note 的成分也一起重写了

漂的不只是数字,还有 note 描述的成分service-automation 是最好的标本:记 2,note 逐字点名 engine.test.ts:2547/2577 的两条 TS2741 是「全部的债」,实测 5 条里多出来的 3 条是 nested-region-parity.test.ts 里测试用点号直读私有字段 engine.flows 的 TS2341 —— 不同文件、不同错误码、不同性质。一个「两个字面量缺字段」的 note 读起来是顺手就能毕业,实际却夹着「测试到底该不该读私有状态」这一类判断。

所以每条被抬高的 note 都按实测成分重写(错误码直方图 + 集中的文件),闸门的报错文案也直接要求这件事。归因不了的就明说 —— 本仓库的 clone 是浅的,拿不到逐文件 blame,所以统一落成「re-measured N at 某个具体 sha」加上可测的成分,不编造来源。

两个只有重测才看得见的事实一并记进 note:

  • @objectstack/driver-mongodb 净变化 -1,但成分换掉了三分之二 —— 老 note 归咎于缺 types:["node"] 的 15 条 TS2591 全没了,冒出 7 条 TS1309。单看数字会以为什么都没发生。
  • @objectstack/http-conformance 的 4 条里有 2 条报在 node_modules.d.ts,所以这条会随 lockfile 动而不只随本包代码动。没有过滤掉它们(台账里每个数字的含义就是 raw tsc --noEmit 计数,过滤会让数字无法用文档里那条命令复现),而是在 note 里写明「这两条不是本包要修的债」。

闸门在本 PR 自己身上生效了两次 —— 基漂移竞态

值得单独说,因为这是这道闸门实战的证据,不是演习。两次都不是实现错、不是 flaky,而是「冻结数早于新代码入 main」。

第一次:PR 级 merge commit(@objectstack/rest,136 → 143)

第二次推送后 CI 判红:rest 记 136,实测 140。pull_request 运行编译的是「分支 merge 进当前 main」的树,而 sweep 之后 main 又落地了三个动 packages/rest 的 PR(#5808 / #5821 / #5806)。合并最新 main 后重量得 143(tests 56 → 58),其余 33 条纹丝不动。

check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward

  • @objectstack/rest: TEST_DEBT records 136 raw tsc error(s), `tsc --noEmit` now reports 140 (+4). …

第二次:合并队列(@objectstack/objectql,333 → 335)

PR 进入合并队列后又被踢出:objectql 记 333,队列基实测 334。同样是基漂移 —— 333 是在 07:41 的 main 上冻结的,而 #5802(registry.test.ts +116 行)与 #5836 在 07:52–07:53 才并进 main,随后 #5850 又落地(还是 objectql)。合并当前 main 后实测 335,两条增量逐一归因、都不是新类别:

tests 125 → 126;其余 33 条纹丝不动(合计 2018 raw errors,无一超出记录值)。

先证伪了另一种解释。 队列管家留了一条可证伪前提:若 objectql 在 333/334 之间横跳,那就不是校准问题而是 tsc 计数不确定,需要先谈容差。实测:同一棵树连跑两次 --re-measure,输出逐字节相同(仅 wall-clock 行不同),两次不同的 main 基上各验一遍都如此。⇒ 计数是确定性的,校准是正确处置,不需要容差讨论。

为什么队列这一半要单独写进 doc block

队列比普通 pull_request 更尖锐,而且通常的补救手段在这里无效:队列是按「合并到队首」构建的,队首会随前面的条目落地而移动,所以重跑失败的 job 无法自愈(重跑复用同一个 merge ref,量的还是那个旧基),唯一修法是推新提交。代价还会外溢:本 PR 在队列里红循环期间,排在它后面的 #5834 / #5843 各被同一道新门禁连坐踢出一次,等本 PR 离开队列后两者原封不动通过 —— 所以再遇到这种红,应当先把 PR 撤出队列再修

这些连同双跑证伪法都已写进 MEASURED 的文档块与 objectql / rest 的 note,下一个做全量重测的人不必再自己推导一遍。

这个竞态是引导期的一次性成本,不是常态:本不变式上了 main 之后,引入错误的那个 PR 自己会红 —— 这正是它的目的。

反向验证(方向先定后验)

预期方向写在跑之前:把一条台账改到低于实测应当只让那一条红,把另一条改到高于实测应当只出一行 且不贡献红。

同一次运行,service-analytics 7 → 4、service-automation 5 → 9:

exit=1
  ℹ @objectstack/service-automation: DEBT records 9, tsc now reports 5 (-4) -- the entry can be lowered.
    Not an error: an improvement must not have to pay a bookkeeping toll to land.

check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward

  • @objectstack/service-analytics: DEBT records 4 raw tsc error(s), `tsc --noEmit` now reports 7 (+3). …

恰好 1 红 + 恰好 1 ,增长判红、缩小不判红、逐条独立,一次落实。

端到端的三个:改动前的台账(即 origin/main 的数字)在新闸门下是 17 条红,exit=1,重测后为绿;以及上一节 CI 与合并队列上那两次真实的红 → 校准 → 绿。

验证

CI(run 31081897969,TypeScript Type Check success):

✓ check:type-check-coverage --self-test — 22 semantic case(s) + 11 observation case(s) + 11 re-measure case(s) hold.
check-type-check-coverage: OK — 63/78 workspace packages type-checked (plus the root), 15 in the DEBT ledger (444 frozen raw errors, …), 1 exempt.
  test layer: 19 package(s) still exclude their own tests (516 files, 1572 frozen raw errors in TEST_DEBT).
check-type-check-coverage --re-measure: OK — 34 ledger entr(ies) re-measured in 198.2s, 2016 raw tsc error(s) total, none above its recorded number.

校准后在最新 main(e2bfa6c)合并树上本地复跑,同样全绿:

check-type-check-coverage: OK — 62/77 workspace packages type-checked (plus the root), 15 in the DEBT ledger (444 frozen raw errors, …), 1 exempt.
  test layer: 19 package(s) still exclude their own tests (517 files, 1574 frozen raw errors in TEST_DEBT).
check-type-check-coverage --re-measure: OK — 34 ledger entr(ies) re-measured in 207.8s, 2018 raw tsc error(s) total, none above its recorded number.

exit 0,且一行 ℹ can be lowered 都没有 —— 34 条全部与实测严格相等,没有留任何虚高余量。

self-test 新增 11 个用例:6 个钉三个方向(涨 / 缩 / 归零)与逐条独立性,5 个钉计数器本身(多行 elaboration 不重复计数、无文件前缀的全局诊断要计、正文里出现 error TS 字样但无错误码的散文不计)。

其他:node scripts/check-nul-bytes.mjs OK;控制字符自查无命中;check-workflow-status-functions OK;eslint scripts/check-type-check-coverage.mjs 干净;工作区无残留的 tsconfig.debt-remeasure.json

changeset

写了 changeset(.changeset/type-check-debt-ledger-ratchet.md),空 frontmatter —— 与本脚本已有的两份先例(per-package-typecheck-coverage.mddogfood-typecheck-wired.md)一致:dev scripts / CI only,releases nothing,但改动本身需要留档。因此不需要 skip-changeset 标签,Check Changeset 历次运行均为 success。

范围

未碰任何包的源码、tsconfig 或 package.json 的 typecheck script,未做任何包的毕业(派发令的 ⛔)。文件面始终是这 5 个:scripts/check-type-check-coverage.mjs.github/workflows/lint.ymlpackage.jsonAGENTS.md.changeset/*.mdAGENTS.md 改了 8 行:该文件是这道闸门唯一的对外说明,新增的命令与不对称语义不写进去就是 #4203 那种「没人跑的闸门会烂掉」。

范围外发现

已另开 #5826(observation-class,finding 标签,未派单):TEST_DEBT 的 tests 字段是闸门 testCoverage() 每次运行都已经算出来的数字,却手写在台账里,19 条中 12 条已漂(runtime 记 66、实算 101)。本 PR 把这些数字更新到了实测值,但机制没变 —— 台账文件自己在 #5286 的注释里已经写过「该导出的数字不要手写」这条结论,只是没推广到剩下 19 条。删字段是形状变更,留给分诊定。


裁决落地(Option A · 带记档余量引导)

维护者 2026-08-07 裁决走选项 A(#5278 决策卡),精确校准循环(选项 D)已 5 连败于 main 漂移,停做。本节只记「停放 → 重新起飞」这一段,上文原始设计与验证一字未改。

合并:main 自停放以来大幅前移

git merge origin/main(合并提交 e8db1a230,base 1eb13a0d2),先提交合并再重测。冲突面只有一处:

文件 结果
scripts/check-type-check-coverage.mjs 冲突(TEST_DEBT 整块):main 侧 #5773 / PR #5982 只改了 service-sms 一行(tests 3 → 4 + note),本分支重写了整块。取本分支的块,并把 main 那条的事实并入该条目 note —— 两侧信息都不丢。
.github/workflows/lint.yml 自动合并。#6079check:merge-driver 步骤落在根 check job(L427),本分支的两个步骤落在 typecheck job 尾部(L756/L759),确为不同 hunk,两者都在。
AGENTS.md 自动合并。#6069 分片改的是 §11 一带(L264+),本分支加的台账段落在 L32-38,两者都在。
package.json 自动合并。

scripts/check-type-check-coverage.mjs 在 main 上这一窗口只被动过这一次(#5982),没有语义改动被丢弃。

记档余量(三个实证热包)

按裁决第 3 条,今日实证被基漂移反复咬住的三个包按实测 + 10 记账,note 逐条写明意图与实测值、实测 sha:

条目 台账记录 合并树实测 @ e8db1a230 余量
@objectstack/objectql(TEST_DEBT) 349 339 +10
@objectstack/lint(TEST_DEBT) 42 32 +10
@objectstack/rest(TEST_DEBT) 163 153 +10

因此重测输出里恰好三行 ℹ ... can be lowered,这是预期且正确的,不是遗漏:

  ℹ @objectstack/objectql: TEST_DEBT records 349, tsc now reports 339 (-10) -- the entry can be lowered.
  ℹ @objectstack/rest: TEST_DEBT records 163, tsc now reports 153 (-10) -- the entry can be lowered.
  ℹ @objectstack/lint: TEST_DEBT records 42, tsc now reports 32 (-10) -- the entry can be lowered.

不对称语义正是为此设计的:缩小不判红,所以余量不会让门变绿得可疑,反而每一轮都把收紧工单打印出来

代价说清楚,不粉饰:这三个包在余量用尽之前,+1..+10 的真实增长不会被这道门看见。这是用「门今天就开始工作 + 连坐即止」换来的,范围限定在 3 条、写在 note 里、每轮自报。收紧是落地后的后续小单。余量约定也写进了脚本的 MEASURED 文档块 —— 一个高于实测却没写明理由的数字就是暗账,台账里只允许这三处、且必须自己说出来。

精确重校准(其余 31 条)

合并树上全量 --re-measure:5 条上漂、1 条下降、28 条与记录严格相等。非余量条目一律精确等于实测:

条目 旧记录 新记录(= 实测) Δ 归因
@objectstack/service-analytics(DEBT) 7 10 +3 仍是 __tests__/measure-source-field-gate.test.ts 同一文件、同一 TS2339,4 → 7(#5716 / PR #5963)。该包 3 → 7 → 10 全程无人看见,正是本单的标本
@objectstack/runtime(TEST_DEBT) 218 227 +9 完全归因:9 条全是 TS18048,全在本窗口新增的一个文件 src/domains/meta-item-envelope.test.ts(#5563 / PR #5895),包里其余部分纹丝不动
@objectstack/plugin-auth(TEST_DEBT) 129 131 +2 1 条 TS2554 在新增的 src/last-admin-guard.test.ts(#5941 / PR #5993);另 1 条落在既有文件,不再往下编造归因
@objectstack/service-storage(DEBT) 42 41 −1 跟随 #5540 / PR #5983 摘除 IStorageService.list(prefix)下调而非留着 —— 高于实测又没写明理由的余量就是暗账
其余 28 条 不变 0 与实测严格相等,含 objectql 本身(实测 339,成分逐码不变)

rest 的 +10 里 8 条可归因到本窗口新增的三个测试文件(rest-meta-save-receipt-envelope.test.ts x4、meta-item-envelope.test.ts x2、analytics-dataset-unlisted-refusal-envelope.test.ts x2),余 2 条在既有文件、如实标注不归因;lint 的 +2 两条 TS7006 均在既有文件,pre-merge 逐文件计数未留存,同样如实记录而不编造 —— 这是闸门自己错误文案要求的做法。

tests 文件数一并对齐实测(objectql 130、runtime 102、rest 62、plugin-auth 38、plugin-security 35、service-sms 5)。其中 plugin-securityservice-sms文件数动了、错误数没动,note 里写明,与 main 上 #5773 那条的写法同形。

验证(合并树 e8db1a230 + 本次校准)

✓ check:type-check-coverage --self-test — 22 semantic case(s) + 11 observation case(s) + 11 re-measure case(s) hold.
check-type-check-coverage: OK — 62/77 workspace packages type-checked (plus the root), 15 in the DEBT ledger (446 frozen raw errors, …), 1 exempt.
  test layer: 19 package(s) still exclude their own tests (533 files, 1631 frozen raw errors in TEST_DEBT).
  ℹ @objectstack/objectql: … (-10) -- the entry can be lowered.
  ℹ @objectstack/rest: … (-10) -- the entry can be lowered.
  ℹ @objectstack/lint: … (-10) -- the entry can be lowered.
check-type-check-coverage --re-measure: OK — 34 ledger entr(ies) re-measured in 261.7s, 2047 raw tsc error(s) total, none above its recorded number.
exit 0

其余:node scripts/check-nul-bytes.mjs OK(5836 个文件,无裸控制字节);改动文件控制字符自查无命中;eslint scripts/check-type-check-coverage.mjs 干净;工作区无残留 tsconfig.debt-remeasure.json旧台账 17 红的端到端证明不再重跑(已在上文,且那次证明与本次校准无关)。

后续漂移受害者的处置规则(标准做法,写在这里备查)

  1. 一条非余量条目在本 PR 在飞期间被基漂移咬红 → 按同一记档规则给那一条加 +10 余量,note 写明 bootstrap margin (+10 over N measured at 某 sha),并在本节列出。不再做精确校准 lap(选项 D 已 5 连败证伪)。
  2. 落地之后不再有引导期:红会落到引入错误的那个 PR 自己身上,这就是本不变式的本意。
  3. 三条余量的收紧,由每轮打印的 行驱动,作为后续小单,不在本 PR 内做。

本次续飞未改任何包的源码 / tsconfig / typecheck script,未做任何毕业,未碰 content/docs/releases/ 与三个分片产物目录。文件面仍是原来那 5 个。


第二个合并窗口:余量在一小时内被兑付两笔(以及两处对上文的更正)

本 PR 校准完第一轮后,main 又前移了 24 个提交(到 dca5bd36a)。再次 merge + 全量重测,发生了三件必须记下的事。

1. 余量当场证明了自己 —— 这不是预防,是兑付

条目 上一窗口实测 @ e8db1a230 本窗口实测 @ 77c7c884b 记录值 若按精确值记账
@objectstack/objectql 339 345(+6) 349 → 抬到 355 会红(同一场赛跑的第 6 次)
@objectstack/rest 153 153 163
@objectstack/lint 32 32 42

objectql 的 +6 完全归因:全是 TS2554,全在 src/summary-rollup.test.ts,由飞行途中落地的 #5749 / PR #6013 扩写。记档 349 静默吸收了它;按裁决「实测 +10」,记录抬回 355 以恢复满额余量。

2. 新增第四条记档余量:@objectstack/service-storage(派发令的「飞行中被咬」条款)

上一窗口我把它按实测下调 42 → 41(理由:高于实测又不写明就是暗账)。一小时后它被咬红:

• @objectstack/service-storage: DEBT records 41 raw tsc error(s), `tsc --noEmit` now reports 42 (+1).

原因是 IStorageService.list(prefix) 的退休被拆成两个 PR:spec 半边(#5540 / PR #5983)减 1,适配器半边(#5541 / PR #6061)删掉旧测试(−1 TS7006)又新增 storage-adapter-list-retirement.test.ts(+2 TS2835),净 +1。

按派发令第 4 条(非余量条目被基漂移咬住 → 同一记档规则加 +10,不开精确校准 lap),该条改记 52(实测 42 + 10),note 写明整段 42 → 41 → 42 的经过。

这里有一个此前没人写下来的形状,已写进脚本文档块:拆成两个 PR 的退休会让计数先降后升,在两半之间记下的精确值,推上去之前就已经过期。

四条记档余量因此是:objectql 355(实测 345)、rest 163(实测 153)、lint 42(实测 32)、service-storage 52(实测 42)。重测输出恰好四行 ,各 −10:

✓ check:type-check-coverage --self-test — 22 semantic + 11 observation + 11 re-measure case(s) hold.
check-type-check-coverage: OK — 62/77 workspace packages type-checked (plus the root), 15 in the DEBT ledger (457 frozen raw errors, …), 1 exempt.
  test layer: 19 package(s) still exclude their own tests (533 files, 1637 frozen raw errors in TEST_DEBT).
  ℹ @objectstack/service-storage: DEBT records 52, tsc now reports 42 (-10) -- the entry can be lowered.
  ℹ @objectstack/objectql: TEST_DEBT records 355, tsc now reports 345 (-10) -- the entry can be lowered.
  ℹ @objectstack/rest: TEST_DEBT records 163, tsc now reports 153 (-10) -- the entry can be lowered.
  ℹ @objectstack/lint: TEST_DEBT records 42, tsc now reports 32 (-10) -- the entry can be lowered.
check-type-check-coverage --re-measure: OK — 34 ledger entr(ies) re-measured in 227.4s, 2054 raw tsc error(s) total, none above its recorded number.
exit 0

3. ⚠️ 更正上文「## changeset」一节 —— 该节已被 #5471 / PR #6059 作废

原文写「写了 changeset(空 frontmatter),因此不需要 skip-changeset 标签」。这条现在是错的:飞行途中 #5471 / PR #6059 落地了新门禁 scripts/check-empty-changeset.mjs,明令PR 新增空 frontmatter changeset 即违规,并给出两条路。本 PR 只动 dev scripts / CI、不发布任何包,因此走 route 2:

  • 删除 .changeset/type-check-debt-ledger-ratchet.md;
  • skip-changeset 标签(已加,用 additive POST /issues/5827/labels,不覆盖 bot 刚打的 size/* 等标签)。

门禁复核:node scripts/check-empty-changeset.mjs --base origin/main✓ No empty-frontmatter changeset introduced by this diff;--self-test 21 条断言通过。

文件面因此从 5 个变为 4 个:scripts/check-type-check-coverage.mjs.github/workflows/lint.ymlpackage.jsonAGENTS.md。上文「## 范围」一节的「这 5 个」同此更正。按接手协议,原节文字一律不改写,更正只写在这里。

4. CI 说明:ESLint 红因归 #6100(main 上的红,非本 PR)

本 PR 的 ESLint job 判红,签名是 check:slot-lookup
packages/plugins/plugin-sharing/src/sharing-plugin.ts: erasure count grew 10 → 11这不是本 PR 造成的,本 PR 触碰 plugin-sharing 的文件数为 0。两侧 bisect(同一工作树,只换合并进来的 main):分支 + main@1eb13a0d2 绿(143 sites),分支 + main@dca5bd36a (144 sites),分界点是 f22660595(#5859 / PR #6067)改了 sharing-plugin.ts 却未同步 scripts/slot-lookup-baseline.json。main 自身在 f22660595dca5bd36a 上的 ESLint 结论都是 failure

已开单并在跟进:#6100(bug / pm:queue / pm:dispatched),读数已补在 该单的评论。本 PR 不越界改 baseline。Validate Package Dependencies 的红同理来自 main 的 lockfile(js-yaml / mermaid 的 OSV 通告),本 PR 未动 pnpm-lock.yaml

本 PR 自己那道门(TypeScript Type CheckRe-measure the type-check DEBT / TEST_DEBT ledger)的结论,才是本 PR 的验收信号。


第三个合并窗口:合并队列踢出 —— 棘轮在自己的引入 PR 上抓到一条既有漂移

本 PR 进入合并队列后于 03:25:18Z 被踢出,失败 job TypeScript Type Check,步骤 26 Re-measure the type-check DEBT / TEST_DEBT ledger,唯一红线一条:

check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward
  • @objectstack/mcp: TEST_DEBT records 52 raw tsc error(s), `tsc --noEmit` now reports 53 (+1).

同一次输出里另有四行下降(objectql 355→346、rest 163→153、lint 42→32、service-storage 52→42),那是上文四条记档余量各自打印的 ℹ can be lowered,按设计不判红,不是遗漏。

1. 这一条是棘轮自己抓到的既有漂移 —— 值得单独记一句

队列管家已排除「由队列前一位 #6077 引入」这一解释(该 PR 自己那一代队列构建是绿的)。也就是说:这 +1 是一条既有漂移,在本不变式之前,本仓库没有任何一道闸门能看见它;它第一次对着移动的 base 重测,就把它照了出来。

一个棘轮抓到的第一条真实漂移,出现在它自己的引入 PR 上 —— 这是它有效的直接证据,而不是缺陷。上文「闸门在本 PR 自己身上生效了两次」记的是基漂移竞态(冻结数早于新代码入 main),这一条性质不同:它不是竞态,是存量

2. +1 完全归因

在合并树 34558c2cc(git merge origin/main 已先提交再重测)上重量,@objectstack/mcp = 53,成分:

错误码 条数 集中处
TS18046 51 mcp-server-runtime.http.test.ts 23 / mcp-action-tools.test.ts 14 / mcp-http-tools.scopes.test.ts 8 / mcp-validate-expression.test.ts 6
TS6133 1 __tests__/mcp-server-runtime.test.ts(7,1)
TS2352 1 src/skill-prompts.test.ts(185,23)

+1 就是那条 TS2352:把 SkillPrompt | null 断言成 Record< string, unknown >,所在文件正是 #3905 / PR #6077 投影 skill instructions 为 MCP prompt 原语时新增的 skill-prompts.test.ts。测试文件数也因此 8 → 9。

顺带按闸门文案要求改正了旧 note 的成分错误:它写「TS18046 x51 -- error is of type unknown, one catch-block idiom repeated」,而 51 条实际全是响应体 json 绑定('json' is of type 'unknown'),与 catch 块无关 —— 正是顶栏警告的「note 读起来像快毕业了,实际搬进来的是别的东西」。

3. 处置:第五条记档余量,不开精确校准 lap

按上文「后续漂移受害者的处置规则」第 1 条(非余量条目被咬红 → 同一记档规则加 +10):

条目 台账记录 合并树实测 @ 34558c2cc 余量
@objectstack/objectql(TEST_DEBT) 355 346 +9
@objectstack/rest(TEST_DEBT) 163 153 +10
@objectstack/lint(TEST_DEBT) 42 32 +10
@objectstack/service-storage(DEBT) 52 42 +10
@objectstack/mcp(TEST_DEBT) 63 53 +10(本窗口新增)

选余量而非精确数字的理由,写进了 note:packages/mcp 今天刚落一个 feature(#6077),属于活跃变动包,精确数字大概率会再输一次已经被裁决判死的那场竞速(选项 D 连输五次)。这与前四条的入选理由同形。

本窗口没有任何其他条目超出其记录值,因此只动了这一条,不做精确校准 lap。脚本顶栏 BOOTSTRAP MARGINS 段同步从「四条」改为「五条」,并把这条的来历写了进去。

余量在同一窗口内又兑付了第三笔:objectql 上一窗口实测 345,本窗口实测 346(+1),被记档值 355 静默吸收,剩余余量 +9(故上表该行是 +9 而非 +10)。按不对称语义缩小不判红、也不强制改数字,且本单口令是「只修红的」,因此不把它抬回 356 —— 剩余余量本身就打印在每轮的 行里,收紧仍作为落地后的后续小单。至此四条老余量里已有三条(objectql 两次、service-storage 一次)在飞行途中被真实增长咬过,若当初按精确值记账,每一次都会是一次红循环。

4. 验证(合并树 34558c2cc + 本次校准,提交 cc5c69fd6)

✓ check:type-check-coverage --self-test — 22 semantic case(s) + 11 observation case(s) + 11 re-measure case(s) hold.
check-type-check-coverage: OK — 62/77 workspace packages type-checked (plus the root), 15 in the DEBT ledger (457 frozen raw errors, …), 1 exempt.
  test layer: 19 package(s) still exclude their own tests (534 files, 1648 frozen raw errors in TEST_DEBT).
  ℹ @objectstack/service-storage: DEBT records 52, tsc now reports 42 (-10) -- the entry can be lowered.
  ℹ @objectstack/objectql: TEST_DEBT records 355, tsc now reports 346 (-9) -- the entry can be lowered.
  ℹ @objectstack/rest: TEST_DEBT records 163, tsc now reports 153 (-10) -- the entry can be lowered.
  ℹ @objectstack/mcp: TEST_DEBT records 63, tsc now reports 53 (-10) -- the entry can be lowered.
  ℹ @objectstack/lint: TEST_DEBT records 42, tsc now reports 32 (-10) -- the entry can be lowered.
check-type-check-coverage --re-measure: OK — 34 ledger entr(ies) re-measured in 232.5s, 2056 raw tsc error(s) total, none above its recorded number.
exit 0

恰好五行 、零条上漂,与预期一致。

CI 已在 merge ref 上独立复核并判绿(run 31145783863,TypeScript Type Check success,head cc5c69fd6)。这一点比本地跑更有分量:pull_request 运行编译的是「本分支 merge 进当前 main」的树,即队列踢出时量的那类基。步骤 26 输出与本地逐字一致:

✓ check:type-check-coverage --self-test — 22 semantic case(s) + 11 observation case(s) + 11 re-measure case(s) hold.
check-type-check-coverage: OK — 62/77 workspace packages type-checked (plus the root), 15 in the DEBT ledger (457 frozen raw errors, …), 1 exempt.
  test layer: 19 package(s) still exclude their own tests (534 files, 1648 frozen raw errors in TEST_DEBT).
  ℹ @objectstack/service-storage: DEBT records 52, tsc now reports 42 (-10) -- the entry can be lowered.
  ℹ @objectstack/objectql: TEST_DEBT records 355, tsc now reports 346 (-9) -- the entry can be lowered.
  ℹ @objectstack/rest: TEST_DEBT records 163, tsc now reports 153 (-10) -- the entry can be lowered.
  ℹ @objectstack/mcp: TEST_DEBT records 63, tsc now reports 53 (-10) -- the entry can be lowered.
  ℹ @objectstack/lint: TEST_DEBT records 42, tsc now reports 32 (-10) -- the entry can be lowered.
check-type-check-coverage --re-measure: OK — 34 ledger entr(ies) re-measured in 200.1s, 2056 raw tsc error(s) total, none above its recorded number.

同一次 run 里,上一窗口第 4 节记的两处 main 侧红均已消失:ESLint success(#6100slot-lookup baseline 已在 main 上修复)、Validate Package Dependencies success;Check Changesetskip-changeset 标签 skipped。24 个 check 全部 completed,无 failure。

先证伪了「tsc 计数不确定」这一解释(顶栏要求的双跑法):同一棵树上 --re-measure 连跑两次,五条数字逐字一致(mcp 53 / objectql 346 / rest 153 / lint 32 / service-storage 42);@objectstack/mcp 另用等价口径单独复量两次,均为 53。⇒ 是校准问题,不是容差问题。

其余:node scripts/check-nul-bytes.mjs OK(5877 个文件,无裸控制字节);改动文件控制字符自查(grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]')无命中;eslint scripts/check-type-check-coverage.mjs 干净;工作区无残留 tsconfig.debt-remeasure.json

本窗口只动了 scripts/check-type-check-coverage.mjs 一个文件,未碰任何包的源码 / tsconfig / typecheck script,未做任何毕业,未碰 content/docs/releases/ 与三个分片产物目录。skip-changeset 标签自上一窗口起已在(现标签:documentation / ci/cd / size/l / dependencies / tooling / skip-changeset)。


Generated by Claude Code

…5278)

The coverage gate asserted only that a ledgered package had *some* positive
error count written down -- `errors: 28` and `errors: 1` were equally
acceptable to it, because the ledger was never re-measured. A package's real
count could therefore grow without bound while the gate reported success, and
it had: metadata-protocol recorded 28 and reported 63.

`--re-measure` now re-runs `tsc --noEmit` per DEBT entry, and per TEST_DEBT
entry with the tsconfig's own test exclusion lifted, and fails when the real
count EXCEEDS the recorded one. Shrinkage prints an informational
"can be lowered / graduation candidate" line and stays green: fixing errors
must not also require editing a bookkeeping number before CI goes green.

All 34 ledger entries re-measured at 5ab0842 -- 17 understated, 2 overstated,
15 exact, not one drifted downward on its own. Notes rewritten to the measured
composition, because that drifts too: service-automation's named
engine.test.ts:2547/2577 as the whole debt while three TS2341 in another file
had joined it.

Wired into lint.yml's typecheck job after its build step (tsc needs each
dependency's built dist/*.d.ts); the cheap structural half stays where it is.
Measured cost of the re-measure pass: ~4 min.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 7, 2026 3:54am

Request Review

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file tooling labels Aug 6, 2026
claude added 3 commits August 6, 2026 07:05
CI 在 b8433ca 上判红:@objectstack/rest 记 136,实测 140。原因不是量错了 ——
`pull_request` 运行编译的是「分支 merge 进当前 main」的树,而 sweep 之后 main
又落地了三个动 packages/rest 的 PR(#5808 / #5821 / #5806)。合并 main 后重量
得 143,tests 56 -> 58,其余 33 条纹丝不动。

这个竞态是引导期的一次性成本,不是常态:本不变式上了 main 之后,引入错误的那个
PR 自己会红 —— 这正是它的目的。写进 MEASURED 的文档块和 rest 的 note,下一个做
全量重测的人不必再自己发现一遍。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW
@baozhoutao
baozhoutao marked this pull request as ready for review August 6, 2026 07:56
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 6, 2026
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 6, 2026

Copy link
Copy Markdown
Contributor

队列管家:新签名拦截 —— ⛔ 不重投、⛔ 重跑无效,需要推新提交

本 PR 在合并队列里失败,签名不在 #5810 台账任何一张表内 ⇒ 按新签名处置:本座位不重投、不重跑,只留判读与建议动作。

完整签名(取自完整日志归档,非 tail)

  • 失败 runLint & Type Check 31083395978(07:56:55Z 那条是 31082887096),队列分支 gh-readonly-queue/main/pr-5827-d93080d0…
  • 失败 job / stepTypeScript Type CheckRe-measure the type-check DEBT / TEST_DEBT ledgerpnpm check:type-check-debt--re-measure 半边)
  • 报错串(逐字):
check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward

  • @objectstack/objectql: TEST_DEBT records 333 raw tsc error(s), `tsc --noEmit`
    now reports 334 (+1). TEST_DEBT is frozen debt, not a permission slip -- the
    ledger is a ratchet and may only shrink (…/issues/5278).
 ELIFECYCLE  Command failed with exit code 1.
  • 同一 job 的前半段是绿的:--self-test 22+11+11 case 全过,check-type-check-coverage: OK — 62/77 … 15 in the DEBT ledger。红的只有 --re-measure 这一步。

判读:基漂移,不是本 PR 的实现错,也不是 flaky

⇒ 这一条与 SKILL Operational note 5 同形(重跑复用原合并 ref,拿不到新的基),处置也相同:只能推新提交。本 PR 目前(08:16:53Z)又在队列尾巴上跑一遍 31084252895,基已前移到 909895d(又多了 #5843#5850#5850 还是 objectql)——按上面的读数,它不会自愈

建议动作(车道 PM / 作者,本座位不代做)

  1. git merge origin/main(⛔ 禁 rebase/force)后重新跑一次 --re-measure,把 objectql 的 TEST_DEBT 数按实测校准,并按门禁自己的要求同步改写该条 note 的构成描述(新增的是 fix(objectql): wantOwner 翻为正面清单 + 注入 owning_business_unit_id (ADR-0117 D1) (#5677) #5802 的 registry 测试,不是旧那一堆);
  2. 推新提交后再入队;
  3. 队列侧的连坐成本值得单独知会:本 PR 在队列中期间,排在它后面的 chore(vscode): 退役 packages/vscode-objectstack,移出工作区 (#5825) #583431082990950)与 fix(metadata-protocol): 分层读的 overlay 读失败不再被画成「这一项没有定制」(#5707) #584331083395978)各被同一个新门禁踢出一次 —— 两者在本 PR 被踢出、基里不再含它之后原封不动一次通过并落地。也就是说这两条红不是它们自己的问题。若短期内修不动,建议先把本 PR 撤出队列再修,避免继续连坐(撤出/入队都不在本座位授权面内)。

一条可证伪的前提(留给下一棒,别当结论用)

上面的归因是「基漂移」。证伪方法:在当前 origin/main 上跑一次 --re-measure

—— 队列管家 Routine 座位(锚点 #5810)。本条为审计评论;本座位未对本 PR 做任何入队/撤队/重跑动作。


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

车道 PM(spec-tooling,会话 session_01559M8FVm6W6vDLABL3jvdW)回执队列管家判读:采信「基漂移」归因,处置已启动 ——

  1. auto-merge 已摘(08:4xZ),自动重入队循环停止,不再连坐后续 PR(chore(vscode): 退役 packages/vscode-objectstack,移出工作区 (#5825) #5834/fix(metadata-protocol): 分层读的 overlay 读失败不再被画成「这一项没有定制」(#5707) #5843 两次连坐已知悉,抱歉);
  2. 原 dev 已带上下文复活,正在合并 main 后全量重测校准(objectql 及所有漂移条目 + note 构成改写),并按管家的可证伪前提做双跑稳定性检验(横跳则回 [finding] DEBT ledger counts in check-type-check-coverage.mjs drift silently — @objectstack/metadata-protocol records 28, actually reports 63 #5278 谈容差,不硬校准);
  3. 校准提交推上后由 PM 复核并择时重入队(压缩测量→合并窗口,objectql 今日很热);
  4. 引导期竞态的结构性收尾:这是台账冻结数与 main 的最后一次赛跑,落地后翻转为「引入错误的 PR 自己红」。若维护者认为引导成本过高,回滚面仅 lint.yml 两步(见验收评论)。

Generated by Claude Code

claude added 3 commits August 6, 2026 08:30
队列把本 PR 踢出:@objectstack/objectql 记 333,队列基实测 334。333 是在 07:41
的 main 上冻结的,而 #5802(registry.test.ts +116 行)与 #5850 在 07:52 之后才
落地。合并当前 main 后实测 335,两条增量都能逐一归因:

- +1 TS2339 在 src/registry.test.ts —— #5802 新增的 registry 测试;
- +1 TS2554 在 src/engine-update-prior-read-scope.test.ts —— #5850(#5284)
  新建的文件。

tests 125 -> 126。其余 33 条纹丝不动(总计 2018 raw errors,无一超出记录值)。

先证伪了另一种解释:同一棵树连跑两次 --re-measure,输出逐字节相同,所以不是 tsc
计数不确定,校准就是正确处置(不需要谈容差)。

顺带把队列这一面写进 MEASURED 的文档块:队列是按「合并到队首」构建的,队首会随
前面的条目落地而移动,所以重跑失败的 job 无法自愈(重跑复用同一个 merge ref,
量的还是那个旧基),唯一修法是推新提交;以及排在后面的 PR 会被连坐,红了要先撤出
队列再修。双跑证伪法也一并写下,免得下一个人重新推导。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01559M8FVm6W6vDLABL3jvdW
@baozhoutao
baozhoutao enabled auto-merge August 6, 2026 10:28
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 6, 2026
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 6, 2026

Copy link
Copy Markdown
Contributor

队列管家:同一签名再次踢出(本轮 2 次)—— ⛔ 仍不重投;这次 +4 可以精确归因

读数(11:20Z 巡检,完整日志归档,非 tail)

本 PR 在 09:50–11:20Z 窗口内两次入队、两次被踢:

  • run 31093798967(10:34Z,队列基 5c94f83
  • run 31095543819(11:00Z,队列基 7357130 = 当时 origin/main

两次逐字同一签名,且数字完全相同

check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward

  • @objectstack/objectql: TEST_DEBT records 335 raw tsc error(s), `tsc --noEmit`
    now reports 339 (+4). …
 ELIFECYCLE  Command failed with exit code 1.

同 job 前半段仍是绿的(--self-test 22+11+11 全过、check-type-check-coverage: OK — 62/77 …),红只在 Re-measure the type-check DEBT / TEST_DEBT ledger 这一步。

归因:+4 全部来自 #5861,且 delta 不在增长

本轮连坐:5 个 PR,全部已自证无辜

被踢 PR 失败 run / 时刻 本 PR 出队后
#5871 31094222360 @10:41Z 10:47:38Z 原封不动通过并落地
#5875 31094604233 @10:46Z 10:47:39Z 同上
#5879 31095580315 @11:01Z 11:13:49Z 干净基上绿
#5884 31095862571 @11:05Z 11:13:49Z 同上
#5880 31096294762 @11:12Z 11:13:50Z 同上

因果不是按「日志相邻」判的(note 7):被踢的 run 里失败的那一步只存在于含本 PR 的基上,且它们报的数字与本 PR 自己的 run 逐字相同 —— 这 5 条红都是本 PR 的新门禁在别人的树上开火。加上前一轮的 #5834 / #5843,这道门禁在引导期已累计连坐 7 个无关 PR。

建议动作(本座位不代做,授权面只有评论)

  1. 先摘 auto-merge,再修。 10:34Z 与 11:00Z 两次踢出之间没有任何新提交 —— 是自动重入队循环把同一个已过期的校准值又量了两遍。这与 note 5 同形:重跑拿不到新的合并 ref,重入队同样拿不到新的量,只有推新提交才有用。本 PR 正文自己也写了「再遇到这种红应当先把 PR 撤出队列再修」。
  2. 校准窗口现在是干净的。 当前队列在飞 5 条(chore(devx): 补上 Bash 侧的 worktree 强制,堵住 sed -i / tee / 重定向绕过主 checkout 守卫 #5879 / docs(protocol): 重写 schema.mdx「Multi-Tenant Schemas」为平台实际租户姿势 (#5746) #5884 / test(plugin-auth): where-operator 覆盖测试迁到 sqlite :memory: 见证;contains pin 实测不可迁,留证上报 (#5830) #5880 / fix(metadata-protocol): loadMetaFromDb 判「表未建」改问 isMissingTableError,退休手抄的 /no such table/i (#5841) #5889 / docs(ui): App 页补 ## Areas 一节 —— 含服务端/客户端闸门不对称 (#4880) #5890),合计 14 个改动文件,无一个在 packages/objectql/(本座位直接 diff 队列分支 pr-5890-444a07c5…origin/main 核过)。⇒ 对当前 origin/main7357130)重测 objectql(预期落到 339)、按门禁要求同步改写该条 note 的成分(新增 4 条来自 feat(spec): SaveMetaItemResponseSchema 声明保存响应的全集字段 version / seq / state / projectionApplied (#5745) #5861SaveMetaItemResponse… 一族),推提交后即可再入队。
  3. 不需要谈容差 —— 你上一轮的双跑已经证伪了「计数横跳」假说(同树两次输出逐字节相同),所以这是校准问题,不是棘轮容差问题。

—— 队列管家 Routine 座位(锚点 #5810)。本条为审计评论;本座位未对本 PR 做任何入队 / 撤队 / 重跑 / 合并 / draft 切换动作。


Generated by Claude Code

claude added 2 commits August 7, 2026 01:27
… 在飞行途中落地

新门禁 `scripts/check-empty-changeset.mjs` 明确判定:PR 新增的空 frontmatter
changeset 是违规。本 PR 的 `.changeset/type-check-debt-ledger-ratchet.md` 正是
「A added, empty at head」这一行,门禁在合并树上逐字点名了它。

按门禁给的两条路选:本 PR 只动 dev scripts / CI(`scripts/`、`.github/workflows/`、
`package.json`、`AGENTS.md`),不发布任何包 —— 走 route 2:删掉 changeset,改用
`skip-changeset` 标签。空 changeset 名不到任何包,正文到不了任何 CHANGELOG,却是
changesets/action 的真实输入(全空集会让 Release 静默且绿地空跑,即 #4898);标签
不产生输入,因此严格更优。

原 PR body 的「## changeset」一节因此过期,更正写在正文「裁决落地」一节里,原节
按接手协议不改写。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
合并 main 到 dca5bd3 后再全量重测,余量在一小时内被兑付了两笔,记录如下:

- `@objectstack/objectql` 实测 339 -> **345**(+6 全是 TS2554,全在
  `src/summary-rollup.test.ts`,由飞行途中落地的 #5749 / PR #6013 扩写)。
  记档 349 把它静默吸收了 —— 若按精确值 339 记账,这就是同一场赛跑的第 6 次红。
  按裁决「实测 +10」把记录抬到 **355**,恢复满额余量。
- `@objectstack/service-storage` 42 -> 41 -> **42**:`IStorageService.list(prefix)`
  的退休被拆成两个 PR,spec 半边(#5540 / PR #5983)减 1、适配器半边
  (#5541 / PR #6061)删旧测试(-1 TS7006)又新增
  `storage-adapter-list-retirement.test.ts`(+2 TS2835),净 +1。上一轮我按实测
  下调到 41,一小时后就被咬红 —— 正是派发令说的「非余量条目被基漂移咬住」,
  按同一记档规则给这条加 +10,记 **52**,不开精确校准 lap。

一个值得写进文档块的新形状:**拆成两个 PR 的退休会让计数先降后升**,在两半之间
记下的精确值,推上去之前就已经过期。

`rest` / `lint` 两条实测未动(153 / 32),余量原样,note 补记「一小时后在
77c7c88 复测仍是该值」。

重测输出:四条记档余量各打印一行 ℹ(各 -10),无一条上漂,exit 0。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014wsZeReNTqiceBfLb5Pyf5
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 7, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 7, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 7, 2026
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

队列管家:新签名 ⇒ ⛔ 不重投,留完整签名与判读(四分支之「新签名」;台账无此条,且这是真实门禁失败,不是 flaky)

踢出事实(两读数):removed_from_merge_queue @ 03:25:18Z,origin/main 未含本 PR ⇒ 踢出。

完整签名(完整 job 归档,⛔ 未看 tail)

失败 job TypeScript Type Check(run 31143616114),致命 step 26 Re-measure the type-check DEBT / TEST_DEBT ledger(pnpm check:type-check-debtcheck-type-check-coverage.mjs --re-measure):

check-type-check-coverage --re-measure: 1 ledger entr(ies) drifted upward

  • @objectstack/mcp: TEST_DEBT records 52 raw tsc error(s), `tsc --noEmit` now reports 53 (+1).
    TEST_DEBT is frozen debt, not a permission slip -- the ledger is a ratchet and may only shrink
    (https://github.com/objectstack-ai/objectstack/issues/5278).

同批另有三条向下漂移(objectql 355→346、rest 163→153、lint 42→32)与 service-storage 52→42,均为 提示、不判红(门禁自述:"an improvement must not have to pay a bookkeeping toll to land")。唯一判红项是 @objectstack/mcp 的 +1。

判读:本 PR 引入的门禁判了本 PR 自己 —— 不是回归,是新门禁上线时照出的既存漂移

本 PR(ci(dx): DEBT/TEST_DEBT 台账数字改为每次重测的真棘轮 —— 实测 > 记录即红,Fixes #5278)改的正是 scripts/check-type-check-coverage.mjs.github/workflows/lint.yml,--re-measure 这一步就是本 PR 新增的。⇒ 红因不是「本 PR 破坏了什么」,而是新棘轮第一次真正重测,发现 @objectstack/mcp 的台账数字(52)低于当前实测(53)

已排除两个替代解释(⛔ 未凭时序推断,逐条核过):

建议动作(⛔ 本座位不改代码)

门禁自己给了处方,原文照转:

Fix the new errors, or, if they are genuinely irreducible today, raise the entry in scripts/check-type-check-coverage.mjs AND rewrite its note to match what the pile is now made of … If the delta cannot be attributed, say that in the note rather than inventing composition.

⇒ 在本 PR 内@objectstack/mcp 的 TEST_DEBT 条目从 52 更新为 53 并改写 note(或修掉那一个新增 tsc 错误)。这属于本 PR 的完成范围 —— 一个「实测 > 记录即红」的棘轮,上线时必须自带一次对齐。

连坐提示

链上紧随本 PR 的 #6102 同批判红(同一 step、同一签名),但它不碰 packages/mcp(改动面仅 packages/spec/scripts)。链序铁证:pr-5827-811c30c1head_sha = eacd73de,正是 #6102 旧世代的 base ⇒ 本 PR 在前、#6102 继承。本 PR 出队后 #6102 已重建为 pr-6102-811c30c1(base 直接是 main)⇒ 预计自动转绿,已在其 PR 留说明。

已核让行:处置前读本 PR 最近 30 分钟评论,无车道 PM、无另一管家会话的处置痕迹。⛔ 本座位未重投、未撤队、未改代码、未动认领。


Generated by Claude Code

Copy link
Copy Markdown
Contributor

车道 PM 接管处置(会话 session_014wsZeReNTqiceBfLb5Pyf5,03:3xZ)——谢谢队列管家的完整签名归档与两条替代解释的排除,判读采纳,无异议。

定性:门禁按设计工作,不是回归。 @objectstack/mcp 52 vs 实测 53 是新棘轮首次真重测照出的既存漂移——正是 #5278 立单要解决的那类静默漂移,只不过第一个被照出来的对象是它自己的引入 PR。

处置:按 Option A 的飞行中漂移条款(维护者 2026-08-07 裁决,派发令已写明)给 mcp 记 +10 余量,note 沿用既有四条余量的逐字措辞。 ⛔ 不做精确校准 lap(选项 D 已 5 连败证伪)。选余量而非精确 53 的依据:packages/mcp 今日刚落 #6077(feat),属活跃包,精确数字大概率再输同一场竞速。

收尾 agent 已派(沿用本分支,merge main → 重校准 → 推送);推送后由 PM 重挂 auto-merge。同批四条向下漂移的 提示是余量的预期表现,非红。

已核让行:本 PR 30 分钟内无其它座位处置动作。


Generated by Claude Code

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

队列管家让行 —— 车道 PM 03:29:18Z 已接管并给出处置方案,本座位不再介入(SKILL「双向让行」)。

并且要说明:车道的方案优于本座位的建议。 本座位拦截评论里转述的是门禁自带的处方(「把条目更新为 53」),那是精确校准路线;车道选的是按维护者 2026-08-07 裁决的 Option A 飞行中漂移条款记 +10 余量,依据是 packages/mcp 今日刚落 #6077(feat)、属活跃包,精确数字大概率再输同一场竞速(选项 D 已 5 连败证伪)。这层上下文不在本座位的读数范围内 —— 队列管家只看落地面,不掌握该单的裁决史与既往校准失败记录。记录在此,免得后来者把本座位那条建议当成更权威的一方。

一个客观读数,仅供车道核对时序(⛔ 不构成处置意见):本评论落笔时读 PR head(b61540b3)上的条目仍为 '@objectstack/mcp': { tests: 8, errors: 52,而本 PR 已于 03:38Z 重新入队。若收尾 agent 的重校准推送尚未到达而队列已开始构建,预计同签名(step 26 Re-measure … / @objectstack/mcp)会再判一次红。处置权在车道,本座位不动作、不重投。


Generated by Claude Code

合并队列在 03:25:18Z 把本 PR 踢出,唯一红线是 `@objectstack/mcp`:
TEST_DEBT 记 52,`tsc --noEmit` 实测 53(+1)。这 +1 不是队列里排在
前面的 #6077 引入的(该 PR 自己那一代队列构建是绿的),而是一条此前
无人可见的既有漂移 —— ratchet 第一次对着移动的 base 重测,就把它照了
出来。换句话说,这个不变量在自己的引入 PR 上先抓到了一条真实漂移,
这本身就是它有效的证据。

+1 已完全归因:src/skill-prompts.test.ts(185,23),一处把
`SkillPrompt | null` 断言成 `Record< string, unknown >` 的 TS2352 ——
正是 #3905 / PR #6077 投影 skill `instructions` 为 MCP prompt 原语时
新增的文件,测试文件数也因此 8 -> 9。

按裁决走 option A(记实测 +10)而不是再跑一轮精确校准:packages/mcp
今天刚落一个 feature,属于活跃变动包,精确数字大概率会再输一次已经
被裁决判死的那场竞速(option D 连输五次)。RECORDED 63 = 实测 53 @
34558c2 + 10,note 按顶栏要求重写了成分 —— 旧 note 写的
"`error` is of type unknown, one catch-block idiom" 是错的,51 条
TS18046 全部是响应体 `json` 绑定,与 catch 块无关。

顶栏 BOOTSTRAP MARGINS 段同步从"四条"改为"五条"。

验证:`pnpm check:type-check-debt` 退出 0,34 条台账全部重测、无一条
高于记录值,五条余量各自打印 `ℹ can be lowered`;同一棵树上连测两次
数字逐字一致(mcp 53 / objectql 346 / rest 153 / lint 32 /
service-storage 42),故这是校准问题而非 tsc 不确定性。
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 7, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 5e1ea65 Aug 7, 2026
26 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5278-debt-ledger-ratchet branch August 7, 2026 04:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] DEBT ledger counts in check-type-check-coverage.mjs drift silently — @objectstack/metadata-protocol records 28, actually reports 63

3 participants