Blocked-by: #5286 在 #5286 的横扫环节发现(该单只授权 `packages/spec` 文件面,故此处只记录不修)。基线 `origin/main` @ `39396bd`。 ## 事实 按 `pnpm-workspace.yaml` 的全部 glob 枚举 77 个 workspace 包,逐包读 `package.json.scripts.typecheck` 与 `tsconfig.json.exclude`,并统计其测试文件里的 `@ts-expect-error` 指令数: | 指标 | 值 | |---|---| | workspace 包总数 | 77 | | `tsconfig.json` 排除自身测试文件 | 24 | | 其中同时声明了 `typecheck` 脚本(即绿灯但没读测试) | 23 | | 完全没有 `typecheck` 脚本 | 15 | | **落在排除区内、因而从未被求值的 `@ts-expect-error`** | **18** | 18 处的分布: ``` @objectstack/spec 17 处 / 5 文件 <- #5286 的范围 @objectstack/client 1 处 / 1 文件 <- 本单 ``` 具体位置:`packages/client/src/client.test.ts:1283` ```ts // @ts-expect-error — empty string rejected at runtime ``` `packages/client/tsconfig.json` 的 `exclude` 为 `["node_modules", "dist", "**/*.test.ts"]`,而 `typecheck` 脚本是裸 `tsc --noEmit`(读同一份 tsconfig),vitest 也不做类型检查 —— 与 #5286 完全同一根因,只是换了个包。 对照组(`exclude` 不含测试、指令真的会被求值,无需处理):`@objectstack/cli`(3 处)、`@objectstack/types`(2 处)、`@objectstack/metadata-core`(1 处)、`@objectstack/service-cluster-redis`(1 处)。 ## 为什么这不是 #4311 的重复 `scripts/check-type-check-coverage.mjs` 的 `TEST_DEBT` 已经记录了「这些包的测试没被 tsc 读」这一事实(`@objectstack/client`、`@objectstack/rest`、`@objectstack/runtime` 都在册),那是 #4311 的量化欠账。 本单记录的是**另一层**:那片盲区里躺着 18 条**读起来像门禁的断言**。台账说的是「测试没被检查」,没有任何东西说「这些已声明的 pin 是空转的」—— 而 pin 的作者与后来的读者都会当它们是有效守卫。这正是 #5286 命名的 phantom check 类。台账条目消化完之前,这 18 条一直是假绿。 ## 处置 取决于 #5286 为 `packages/spec` 定下的机制(`tsconfig.test.json` 双跑 / vitest `typecheck` / 改写为运行时断言),`@objectstack/client` 这 1 处按同一机制跟进即可,不宜独立发明第二套。故标 Blocked-by。 顺带:若 #5286 最终引入「测试文件必须进 tsc」的门禁,建议同时加一条**跨包不变式** —— 任何携带 `@ts-expect-error` 的测试文件都不得落在该包 tsc 的排除区内。有了它,这一类幽灵 pin 就无法再新增,而不必等 24 个包的存量欠账全部还清。 关联:#5286、#4642(更早的同根因单)、#4311(类型检查覆盖台账)。
Activity
os-zhuang commentedon Aug 5, 2026
分诊结论:
pm:blocked+domain:cli前提复核(
origin/main最新 fetch):packages/client/tsconfig.json的exclude仍为["node_modules", "dist", "**/*.test.ts"],package.json.scripts.typecheck仍是裸tsc --noEmit,packages/client/src/client.test.ts中// @ts-expect-error — empty string rejected at runtime一行仍原样存在。前提未过时。去重结果:本单的阻塞项 #5286 已有在飞 PR —— #5478(draft,
Fixes #5286)。该 PR 的正文明确把本单的处置点名延后:即 #5478 只把该文件 seed 进新增的
PHANTOM_PIN_DEBT台账作为已知条目,并没有在该 PR 里修复它,机制留待 #5286 定案(tsconfig.test.json双跑方案,即 ruling A1)落地后本单再按同一套跟进 —— 与本单正文的「不宜独立发明第二套」自述处置一致。因此本单目前不适合入队并发调度,避免与 #5286/#5478 的收尾产生实现冲突或返工。Domain:修复落点是
packages/client/src/client.test.ts与packages/client/tsconfig.json,packages/client在 domain 映射表中属于domain:cli。Blocked-by: objectstack-ai/objectstack#5286(当前经由 draft PR #5478 推进中)。待 #5286/#5478 合入后应解除pm:blocked并转pm:queue。本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
解锁 + 认领(PM 会话
session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)Blocker #5286 已于 16:00Z closed(completed,经 PR #5478 落地)。#5478 定下的机制即本单要跟的:sibling
tsconfig.test.json(build config 的排除保留,ci.yml 的「产物无测试文件」gate 不动)+check:test-typecheck挂进typecheck链 +test-typecheck-debt.jsonEXACT ratchet +check-type-check-coverage.mjs的 TESTS_COVERED 毕业逻辑(它已会读 typecheck 链上的全部 tsconfig,无需再改)。claude/issue-5449-client-ghost-pin../objectstack-5449(os-dev 自建)packages/client/(tsconfig.test.json 新增、package.json scripts、src/client.test.ts:1283那处 pin 及编译暴露的存量错误)+ 可能的 debt 台账文件。与在飞 [17.0-rc2验收] 安全:REST /actions 与 /automation 派发路由缺少匿名拒绝门 —— 未认证调用者可触发 system 提权的 RLS/FLS 绕过写入 #5519(runtime)、fix(rest): 缺表错误只在「缺的正是所请求对象」时才判为 unknown object (#5462) #5530(rest)均不相交。@ts-expect-error退役 pin 在packages/spec里是幽灵检查:tsconfig 把**/*.test.ts排除出唯一的tsc --noEmit#5286 处置段留给后续的独立提案,越界即另立单。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
开工跟进(os-dev 会话
session_016FNvXhtSdnEGEfLEsMmvxh派发,cli 车道)claude/issue-5449-client-ghost-pin../objectstack-5449(基于最新origin/main)@ts-expect-error退役 pin 不再是幽灵检查 #5478(commit7617956ac)对齐 —— 新增packages/client/tsconfig.test.json(build config 的 exclude 保留)、typecheck挂check:test-typecheck链、存量按test-typecheck-debt.json的 EXACT ratchet 记账,并毕业PHANTOM_PIN_DEBT里packages/client/src/client.test.ts的 seed 条目 +check-type-check-coverage.mjs的 client TEST_DEBT 陈旧条目。origin/main上先证明该 pin 仍是幽灵(删掉指令行两态皆绿),再动手。packages/client/**+ 台账/脚本文件,不触碰packages/runtime/**([17.0-rc2验收] 安全:REST /actions 与 /automation 派发路由缺少匿名拒绝门 —— 未认证调用者可触发 system 提权的 RLS/FLS 绕过写入 #5519 在飞)与packages/rest/**(fix(rest): 缺表错误只在「缺的正是所请求对象」时才判为 unknown object (#5462) #5530 在飞)。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
实现完成 → draft PR #5546(会话
session_016FNvXhtSdnEGEfLEsMmvxh,分支claude/issue-5449-client-ghost-pin)前提复核成立(最新
origin/main@9894a723e两态皆绿 = 该指令从未被求值)。一条需要维护者注意的方向修正:派发单预判「修好后删掉指令行应红 TS2578」在本单不成立,而这正是本单的核心发现。
project(environmentId: string)接受''—— 合法string—— 该指令从来没有东西可压制,第一次被编译报的就是TS2578: Unused '@ts-expect-error' directive。所以正确的修法是删掉该指令(它自己的注释已说明测试真正证明的是运行时 guard),反向验证相应地是镜像的:把指令行加回去才应该红,已先判后跑并实测通过。详见 PR 正文。按 #5478 的先例:sibling
tsconfig.test.json(build 的 exclude 保留)、typecheck挂链、残留进 EXACT ratchet 台账、两处台账毕业(TEST_DEBT + PHANTOM_PIN_DEBT seed,均由闸门强制)。为落实「不要发明第二套」,check-test-typecheck.mts从packages/spec/scripts/提升为共享脚本(--package指定包),而不是复制一份进 client;spec 的台账与计数一字未动,已实跑确认。未做正文「跨包不变式」建议(越界)。界外发现已查重后新立,无标签无指派:#5543、#5544、#5545。
Changeset:纯测试层 + 工装,按
pr-automation.yml首选路径打了skip-changeset标签(同 PR #5478 先例),未塞空 changeset。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
ACCEPT → PR #5546。(PM 会话
session_016FNvXhtSdnEGEfLEsMmvxh,cli 车道)验收要点:
project(environmentId: string)类型层本就接受'',该指令从来无物可压,第一次被编译就是 TS2578。正确修法是删指令、保留运行时断言(下面的 guard 已测);镜像反向验证(加回指令 → 红 TS2578)先判后跑成立。采纳 open_question 1 的 A 案:B 案(non-empty branded string)是把运行时守卫编进公共签名,越出本单契约面,且运行时已守住,不买任何东西。check-test-typecheck.mts从packages/spec/scripts/提升为共享脚本 +--package参数,而非复制第二份——这是对「不要发明第二套」的正确字面执行;spec 侧仅两行脚本接线,台账字节未动,79 文件 / 691 错误实跑复核不变。spec 面这两行若与在飞 spec 单冲突,merge queue 会裁,风险已知可受。TEST_DEBT删 client 陈旧条目(coverage 台账实跑 19 包,由 20 减一),PHANTOM_PIN_DEBT删 fix(spec): 让 spec 测试层真的进 tsc,@ts-expect-error退役 pin 不再是幽灵检查 #5478 点名「留给 幽灵@ts-expect-error不止 spec:@objectstack/client也有 1 处落在 tsconfig 排除区内(全仓横扫结果) #5449」的 seed 条目。pin 所在文件零错误不入账,反向验证正是靠它成立。registerObject用 OUTPUT 型而非 INPUT 型)另立 objectqlregisterObject的参数标成 schema 的 OUTPUT 类型(z.infer),合法的作者态字面量一律 TS2740 —— 这是 spec/client 两份测试层欠账的同一根因 #5543——采纳 open_question 2 的 A 案:producer 公共签名修正属另一契约面,台账在 objectqlregisterObject的参数标成 schema 的 OUTPUT 类型(z.infer),合法的作者态字面量一律 TS2740 —— 这是 spec/client 两份测试层欠账的同一根因 #5543 落地当天自动变红强制毕业,不会烂尾;interim 用as any反而会藏真拼错(本 PR 修的reference_to就是证据)。registerObject的参数标成 schema 的 OUTPUT 类型(z.infer),合法的作者态字面量一律 TS2740 —— 这是 spec/client 两份测试层欠账的同一根因 #5543/packages/client/tests/integration/不在任何 tsconfig 里,且其中的client.discovery是早已不存在的属性(集成套件对着一个不存在的 API 断言) #5544/client SDK 的meta.getItem没有声明返回类型(载荷为unknown),而并排的meta.getItems有 —— 同一表面上相邻两个方法的类型化不对等 #5545 已查重(含 closed)后无标签落池,留 triage 席分域。Check Changeset 首跑红是 opened 事件与
skip-changeset标签的竞态(标签 16:54:27Z 打上,该跑 16:54:43Z 完成但检出的是无标签状态)——已摘/重打标签触发重评,走的正是 PR body 自述的 route 2(#5478 同先例,拒绝空 changeset 的理由即 #4898)。CI 全绿后转 ready 挂 auto-merge,跟到 MERGED。
Generated by Claude Code
fix(client): compile the client test layer so its `@ts-expect-error` …
fix(client): compile `tests/integration/` and point its discovery ass…
docs(client): re-anchor the dead tracker citations in packages/client…
docs(plugin-hono-server): re-anchor the dead tracker citations in pac…
docs(plugin-webhooks): re-anchor the dead tracker citation to the com…