Repository navigation
Description
Restart-when: any PR reworks the PINS_CHECKED detector half of scripts/check-type-check-coverage.mjs (the PIN_DIRECTIVE recogniser), or a second non-@ts-expect-error pin is measured proving phantom in a landed PR
Found while implementing #7809 (PR #8106). Out of scope there, filed unassigned.
What
scripts/check-type-check-coverage.mjs carries a PINS_CHECKED invariant with a good rationale:
A
@ts-expect-erroroutside every invoked tsc program is a retirement guard that cannot fail — deleting the directive changes nothing, which is the definition of a phantom check.
It detects that condition by looking for @ts-expect-error directives (pinFiles). That is one idiom. A compile-time pin written any other way is not seen by it.
The measured example
While writing a vocabulary pin for #7809 I first expressed it as a mutual-assignability pair — the ordinary way to assert "these two types are the same" without a directive:
const _forward: Declared = undefined as unknown as EngineOp; // red if EngineOp widens
const _reverse: EngineOp = undefined as unknown as Declared; // red if EngineOp narrowsin packages/objectql/src/*.test.ts. packages/objectql/tsconfig.json excludes the test layer and its typecheck script is tsc --noEmit against that config, so the mandatory ablation (widen the union by one member, predict red) passed both pnpm typecheck and vitest. The pin asserted nothing in either runner a developer runs locally, and PINS_CHECKED had nothing to say about it because it carries no @ts-expect-error.
What this is NOT
Worth stating precisely, because the first version of this analysis was wrong and the correction matters:
These files are not unchecked. check:type-check-coverage's TEST_DEBT ledger lifts the exclusion, compiles the test layer, and ratchets the raw error count (@objectstack/objectql: 355). Verified from both sides on PR #8106 — three type errors in a new test file made it report 358 and go red; fixing them returned it to exactly 355. So a widened union would have been caught in CI.
The gap is therefore about signal, not coverage:
- what fires is
TEST_DEBT +1on a package with a 355-error pile, not "the dispatch vocabulary changed"; - it fires only in CI, not in the
pnpm typecheckthe author just ran locally and watched pass; PINS_CHECKED, the mechanism whose whole job is to say "this pin is a phantom", stays silent — so the author gets no warning that the idiom they chose is not load-bearing where they put it.
Why it is worth recording
The repo already decided this class matters (#5286, #5449, #4642, the PINS_CHECKED invariant, and scripts/check-test-typecheck.mts, which packages/spec and packages/client have onboarded to). This is a narrow hole in the detector, not a new class: an author who avoids @ts-expect-error — as anyone asserting type equality rather than expected-failure naturally does — falls outside it.
Non-obvious, and the reason this is filed rather than fixed in passing: the naive repair (flag any type-only const in a hidden test file) would be noisy and wrong. Something narrower is probably right — e.g. treat a package's hidden test layer as a place where compile-time pins are reported as unenforced-by-the-local-runner, or extend PINS_CHECKED's notion of a pin, or simply document at the ledger entry that pins in these packages should be expressed at runtime. Which of those is correct is a judgement call, hence a finding rather than a patch.
Ancillary datum
24 of 71 package tsconfigs exclude the test layer; a keyword scan finds type-level assertion idioms (@ts-expect-error, satisfies, assignability consts) in test files across ~12 of those packages. Most are presumably covered as counts by TEST_DEBT exactly as objectql is — that number is offered as scope context for whoever picks this up, not as a claim that any of them is broken.
Generated by Claude Code
Generated by Claude Code
Activity
hotlong commentedon Aug 12, 2026
Triage: lands in
domain:devx; rationale: the detector isscripts/check-type-check-coverage.mjs(gate-family script, general dev tooling, not spec-contract-centred). Held asfinding— the card itself argues the naive repair is wrong and the right detector shape is a judgement call. Type: Task.Generated by Claude Code
hotlong commentedon Aug 12, 2026
Finding-grading round: hold confirmed, now with the concrete re-grade trigger the earlier triage comment lacked: promote when (a) a second measured instance of a non-
@ts-expect-errorpin proving phantom in a landed PR appears, or (b) any PR reworks the PINS_CHECKED detector half ofcheck-type-check-coverage.mjs(note: #7888's--loweris ledger-data only and does not fire this). Premise re-verified exact:PIN_DIRECTIVEat :297 is the only pin recogniser.Generated by Claude Code
hotlong commentedon Aug 13, 2026
State-machine migration, maintainer-authorized (2026-08-13, live triage session: 「我授权你先迁标签」; semantics on #8449): this card is a graded hold — verdict and re-grade triggers are in the grading comments above — so
finding→pm:on-hold. Verdict, triggers, domain unchanged.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
关
not_planned—— 维护者逐张复核 on-hold 卡时同意关闭;纯开发工具,对产品没有影响分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T08:16Z。维护者 2026-09-23 在分诊会话里逐张复核pm:on-hold卡,对第三组的回复原文:「第三组 同意」。 本卡在那一组里的建议是关闭。呈给维护者的事实
scripts/check-type-check-coverage.mjs的PINS_CHECKED只认@ts-expect-error这一种写法。在一个测试层不参与本地类型检查的包里,用别的写法(比如互相赋值来断言类型相等)写的编译期断言,本地跑pnpm typecheck会静默通过。CI 仍然能抓到,只是表现为TEST_DEBT计数 +1,而不是一句「这个断言是假的」。SKILL.md:374:产品仓的 P0/P1 开着时,没有解锁对象的 p2/p3tooling卡一律关闭。重开条件
又一个不是
@ts-expect-error写法的编译期断言,在已合并的 PR 里被实测证明是假的;或者有 PR 重写PIN_DIRECTIVE这个识别器。按正文里的三个方向接着做。关闭理由:
not_planned,同时摘掉pm:on-hold。Generated by Claude Code