Skip to content

fix(scripts): check-type-check-coverage sees a chain entry whose project is missing (#4347) - #4449

Merged
yinlianghui merged 2 commits into
mainfrom
claude/issue-4347-chained-but-missing
Aug 12, 2026
Merged

fix(scripts): check-type-check-coverage sees a chain entry whose project is missing (#4347)#4449
yinlianghui merged 2 commits into
mainfrom
claude/issue-4347-chained-but-missing

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes#4347

scripts/check-type-check-coverage.mjs asks two independent questions about each chained tsconfig project — does the file exist (has*Config, a readFileSync in collect()) and does type-check run it (chains*Config, a regex over the script string) — and reported three of the four combinations. The fourth, chained but missing, was skipped by each section's entry guard: section 5½ opens with if (!pkg.hasTypeTestsConfig) continue;, and section 5 opened on !pkg.hasScript || pkg.testFiles === 0. A type-check reading tsc --noEmit && tsc -p tsconfig.typetests.json with no such file on disk passed this gate at exit 0.

The change

Both project kinds are now reported before those guards, through one shared message builder so the two spellings cannot drift apart:

@object-ui/plugin-dashboard (packages/plugin-dashboard): "type-check" chains tsconfig.test.json, which does not exist.
Delete the chain entry, or restore the project. The chained `tsc -p` fails with TS5058
on the very next run, so nothing can ship in this state — but a coverage gate that reads
green here is claiming more than it checked, and this is the mismatch it exists to report.
  • Section 5½ — reported before if (!pkg.hasTypeTestsConfig) continue;, exactly as the card specifies.
  • Section 5 — the entry guard is split, and the tsconfig.test.json case is asked between the halves, i.e. after !pkg.hasScript and before pkg.testFiles === 0. A dangling chain entry is broken whether or not the package still has test files, and deleting a package's tests together with their project while leaving the chain entry behind is one of the two ways to reach this state — the one the test-file guard hid completely.
  • It replaces the vaguer 5c "N test files that no tsc invocation reads" message rather than stacking on it: there is one defect here, and 5c sends the reader to write a test project that the script already declares.

The blind spot, demonstrated (#4118: pre-fix green, post-fix red)

The card's own observed repro, reproduced as a scratch mutation of real package state inside the worktree and reverted after capture: packages/auth chaining the tsconfig.typetests.json that #4291 retired, and packages/plugin-dashboard — the single remaining TEST_DEBT entry, as auth was at the time — chaining both projects, neither on disk.

Same tree state, both gates:

$ node scripts/check-type-check-coverage.mjs # gate at origin/main
✅ type-check coverage: 43/45 via `type-check`, 1 via their own build, 0 known-broken ...
✅ test type-check coverage: 39/40 packages compile their tests, 1 declared debt ...
gate exit=0
$ node scripts/check-type-check-coverage.mjs # gate in this PR
❌ type-check coverage regressed:
• @object-ui/plugin-dashboard (packages/plugin-dashboard): "type-check" chains tsconfig.test.json, which does not exist.
• @object-ui/auth (packages/auth): "type-check" chains tsconfig.typetests.json, which does not exist.
• @object-ui/plugin-dashboard (packages/plugin-dashboard): "type-check" chains tsconfig.typetests.json, which does not exist.
gate exit=1

That the state really is broken, not merely undeclared:

$ cd packages/plugin-dashboard && pnpm exec tsc -p tsconfig.test.json
error TS5058: The specified path does not exist: 'tsconfig.test.json'.

Real-repository verdict: clean

The fixed gate is green against the real repository — no package here chains a project that is not on disk, which is the expected result, and the new repo-state case in the self-test is what keeps it that way (it names the offender and its script rather than counting).

Tests

scripts/__tests__/check-type-check-coverage.test.ts gains one describe block of five fixture cases plus one repo-state ratchet, following the suite's conventions (throwaway package trees, and the pre-fix entry guards reproduced verbatim as executable blind-spot predicates, the way the #3968 predicates are). The #4291 terminal assertions and the retired-list handling are untouched.

$ pnpm exec vitest run scripts/__tests__/check-type-check-coverage.test.ts --maxWorkers=1
Test Files 1 passed (1)
Tests 33 passed (33)
$ pnpm exec vitest run scripts/ --maxWorkers=1 # whole scripts/ suite
Test Files 39 passed (39)
Tests 899 passed (899)

Also green: pnpm exec tsc -p tsconfig.scripts.json (the program this test file belongs to), eslint on both touched files, node scripts/check-control-bytes.mjs, node scripts/check-phantom-dependencies.mjs, and node scripts/check-changeset-presence.mjs — the last reporting No source of a released package changed in this range, so no changeset is owed (scripts-only change), so no changeset and no skip-changeset label.

Reverse verification

Direction predicted before running, and it is not uniform — two of the six new cases assert a direction that must NOT change, so they stay green by design:

  • Gate reverted to origin/main, new self-test cases keptTests 4 failed | 29 passed (33). The four cases asserting the new error go red; says nothing when every chained project is really there stays green (chained AND present was always quiet), and so does the repo-state ratchet (it judges repository state, not gate code — reverting the gate cannot move it).
  • Fix kept, repository mutated into the chained-but-missing state → the repo-state ratchet goes red and names both offenders: ["@object-ui/auth: tsc --noEmit && tsc -p tsconfig.test.json && tsc -p tsconfig.typetests.json", "@object-ui/plugin-dashboard: ..."]. The pre-existing Retire the narrow per-file tsconfig.typetests.json projects in packages that have graduated out of TEST_DEBT #4291 retirement pin also fires on auth, which is the half of this combination the suite could already see — for the ten named retired packages only, and only for the narrow project.

Working tree verified clean after every capture; all mutations were made with git checkout restores, never git stash.


Generated by Claude Code

…ect is missing (#4347)
Sections 5 and 5½ asked two independent questions about each chained tsconfig
project — does the file exist, does `type-check` run it — and reported three of
the four combinations. The fourth, CHAINED BUT MISSING, was skipped by each
section's entry guard (`!pkg.hasTypeTestsConfig`, and the test-file guard), so a
`type-check` reading `tsc -p tsconfig.typetests.json` with no such file on disk
passed this gate at exit 0 while the chained `tsc` failed with TS5058.
Both kinds are now reported before those guards, with one shared message so the
two spellings cannot drift apart. The self-test pins each shape against
throwaway package trees, plus a repo-state ratchet asserting no package here
chains a project that is not on disk.
@vercel

vercelBot commented Aug 12, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectuiIgnoredIgnoredAug 12, 2026 8:49am

Request Review

@yinlianghuiClaude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPT — step-7 复核 by PM session session_017Qqyix2QcnpUC9XeYVDzx3.

  • Premise re-verified against origin/main before work (and the report correctly notes main moved since the card — Retire the narrow per-file tsconfig.typetests.json projects in packages that have graduated out of TEST_DEBT #4291 emptied the narrow-project population; work was done against origin/main, not the stale shared checkout).
  • Blind spot reproduced honestly: same tree state, gate at origin/main exit 0 (both green lines) vs gate in this PR exit 1 naming plugin-dashboard/tsconfig.test.json, auth/tsconfig.typetests.json, plugin-dashboard/tsconfig.typetests.json — and tsc -p TS5058 confirms the state is really broken, not merely undeclared.
  • Reverse verification with direction predicted first, including the partial prediction (four new cases red on the reverted gate, two that must stay green stayed green — the repo-state ratchet correctly can't move when only gate code reverts).
  • Deviations accepted: the section-5 guard split is a measured superset of the card's literal placement (zero-test-files packages were invisible in every configuration otherwise); replace-not-stack messaging follows the gate's one-gap-one-error rule and is pinned; the extra repo-state ratchet is exactly the two-way discipline this gate family wants.
  • Scripts-only diff, changeset presence checker itself confirms none owed. CI green on 8ff0b5b (the one red was actions/checkout TLS infra, re-run green).

Flipping ready + arming auto-merge. Risks noted in the report (text-derived chain detection, message-pin granularity) are recorded as known scope, not defects.


Generated by Claude Code


Generated by Claude Code

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

check-type-check-coverage.mjs reports green when a "type-check" script chains a tsconfig project that does not exist

2 participants

@yinlianghui@claude