Skip to content

fix(cli): add two missing .js import extensions, shrink TEST_DEBT 188 to 146 with a re-measured note - #8779

Merged
qq9340100 merged 3 commits into
mainfrom
claude/issue-8612-cli-test-debt-import-extensions
Aug 15, 2026
Merged

fix(cli): add two missing .js import extensions, shrink TEST_DEBT 188 to 146 with a re-measured note#8779
qq9340100 merged 3 commits into
mainfrom
claude/issue-8612-cli-test-debt-import-extensions

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#8612

Two relative imports in @objectstack/cli's hidden test layer were missing their .js extensions. Under moduleResolution: NodeNext neither resolves, so every symbol they name becomes any and each unannotated parameter downstream becomes an implicit any — the "a pile of TS7006 is usually one broken import upstream" shape AGENTS.md describes. Adding the two extensions collapses the cascade and the package's TEST_DEBT entry drops 188 → 146.

Measured, both halves, on the same tree

Both numbers come from this branch, measured with the gate's own synthesized project (test layer un-hidden, typeRoots reconstructed) on main at 3508678 with the closure built. The two import extensions are the only difference between the before tree and the after tree.

beforeafter
total188146
TS700610060
TS28355957
TS23392424
TS230733
TS1804622

The −42 is fully attributed, with no unexplained remainder:

  • test/i18n-coverage.test.ts 35 → 0 (1 TS2835 + 34 TS7006)
  • test/i18n-extract.test.ts 7 → 0 (1 TS2835 + 6 TS7006)

Outside those two files the before and after diagnostic sets are identical line for line (146 before, 146 after), so nothing else in the layer moved and nothing new appeared anywhere.

The note rewrite

The card's substance, not a formality: after the collapse the surviving pile has a different composition, and a note still naming the old errors would read as "nearly graduated" to the next author. The new note records what the pile is actually made of — 57 of the 59 extension-less imports still present across 24 files, and every one of the 60 surviving TS7006 sitting in a file that also carries a TS2835, so there is no implicit-any left in this layer without a broken import above it. Nothing in it is inferred; every figure is from the runs above.

A repair here can be bigger than its TS2835 line suggests

Verified rather than assumed, and now recorded in the note. Fixing the i18n-extract import alone takes that file 7 → 4, not 7 → 0: it carried an (e: { path: string[] }) parameter annotation written to dodge the implicit-any while the import was broken, and that annotation narrowed away the real ExpectedEntry the producer declares. In that intermediate state the layer total sits at 150 (TS2339 24 → 28). Deleting the annotation — so the parameter takes the producer's declared type — takes the file to 0. The annotation is deleted, not widened, and no @ts-expect-error or per-parameter annotation is used anywhere in this diff.

Scope

Only @objectstack/cli's entry is touched. Across the whole ledger exactly one errors: value changed, 188 → 146; every other entry is byte-identical. In particular packages/lint stays at 20 against a measured 19 — that surplus belongs to #8610, which remains open and is not addressed here.

No changeset: tests plus a CI-internal gate script release nothing, which is the skip-changeset case lint.yml names explicitly.

Gates, all run at 81a3616e8 (this PR's head)

  • pnpm check:type-check-debtgreen, 33 entries re-measured in 316.2s, 1926 raw errors total, none above its recorded number. The cli entry prints no line at all, meaning measured equals recorded exactly at 146.
  • pnpm check:type-check-coverage — green, including the self-test's 109 cases. TEST_DEBT total moves 1533 → 1491, exactly −42.
  • pnpm check:query-options-erasure — green (ratchet holds, 67 unswept non-test sites, none new). Not named in dispatch; surfaced by re-deriving scripts/pm/dispatch-gates.mjs against the actual changed paths, since editing any test file moves it.
  • pnpm check:nul-bytes — green, 5794 files; plus a control-byte self-scan of the three changed files.
  • pnpm --filter @objectstack/cli typecheck — exits 0, which is the point: it is structurally blind to this layer (include: ["src"]), so only the ledger measures it.
  • vitest run test/i18n-extract.test.ts test/i18n-coverage.test.ts — 2 files, 33 tests, all passing.

The package's full suite was not run to completion locally: its e2e files boot a runtime and exceeded this session's per-command cap under shared-lock contention. CI runs it.


Generated by Claude Code

…hrink TEST_DEBT 188 -> 146
Under moduleResolution NodeNext the extension-less relative imports in
test/i18n-extract.test.ts and test/i18n-coverage.test.ts do not resolve, so
every symbol they name becomes `any` and each unannotated parameter downstream
becomes an implicit any. Adding the extensions collapses the cascade: those two
files go 35 -> 0 and 7 -> 0, and no other file in the layer moves by one error.
Fixing the i18n-extract import exposed 4 TS2339 that the broken import had been
hiding: the file carried an `(e: { path: string[] })` parameter annotation
written to dodge the implicit-any, and it narrowed the real ExpectedEntry away.
The annotation is deleted rather than widened, so the file now type-checks
against the producer's declared type.
The @objectstack/cli TEST_DEBT entry drops 188 -> 146 with its note rewritten to
describe the post-collapse composition -- 57 of the 59 extension-less imports
remain, and every surviving TS7006 sits in a file that still carries a TS2835.
No other ledger entry is touched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NaS1PAHJcPfAA2acnV53Tn
… the note's base
Re-ran both halves on main@35086781b with the closure built, replacing the
numbers measured at the earlier base: 188 before, 146 after, delta -42, fully
attributed to test/i18n-coverage.test.ts (35 -> 0, 1 TS2835 + 34 TS7006) and
test/i18n-extract.test.ts (7 -> 0, 1 TS2835 + 6 TS7006). Outside those two
files the before and after diagnostics are identical line for line, so nothing
else in the layer moved and nothing new appeared.
Also verified the exposure lesson the note carries rather than inheriting it:
with the i18n-extract import fixed and the dodge annotation still in place the
file reports 4 TS2339, not 0 -- the layer total sits at 150 in that
intermediate state. Deleting the annotation, so the parameter takes the real
ExpectedEntry the producer declares, takes the file to 0.
The header comment above TEST_DEBT now reads 146 across 65 files rather than
carrying both the old and new counts.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NaS1PAHJcPfAA2acnV53Tn
@vercel

vercelBot commented Aug 15, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 15, 2026 12:00am

Request Review

@qq9340100qq9340100 added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/s labels Aug 15, 2026 — with Claude
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@qq9340100Claude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPT — PM review, domain:cli seat

All four rulings verified from the diff rather than from the PR body, because this is a card where every claim is a number and a green gate cannot distinguish an honest shrink from a quietly raised ceiling.

Ruling 1 — shrink only, never raise: VERIFIED. Across the entire ledger diff exactly twoerrors: lines changed — -188 / +146. One entry, and it went down.

Ruling 2 — only @objectstack/cli's entry: VERIFIED by the same count.packages/lint keeps its 20-against-19 surplus untouched, so #8610's open question is not silently resolved inside a diff about something else.

Ruling 4 — fix at source: VERIFIED. No @ts-expect-error, no @ts-ignore, no : any, no as any anywhere in the diff. The change is two .js extensions and the deletion of an (e: { path: string[] }) annotation — deleted, not widened, so the parameter takes the producer's declared ExpectedEntry.

Ruling 3 — the note rewrite: this is the part that was done properly. The −42 is fully attributed with no unexplained remainder (i18n-coverage 35 → 0, i18n-extract 7 → 0), and outside those two files the before/after diagnostic sets are identical line for line, which is the claim that makes "nothing else moved" checkable rather than assertable. The new note describes what the pile is now made of instead of inheriting the old composition — 57 of the 59 extension-less imports still present across 24 files, and every one of the 60 surviving TS7006 sitting in a file that also carries a TS2835, i.e. no implicit-any in this layer without a broken import above it. It also corrects the sizing line honestly: 117 of the 146 are 57 repairs, not one.

Beyond the card, and worth keeping. The note records something the card did not ask for and that the next author needs: collapsing a cascade can expose errors, not only remove them. Fixing the i18n-extract import alone took that file 7 → 4 new TS2339, because the annotation written to dodge the implicit-any had narrowed the real type away; only deleting it reached 0. That is a trap sitting under each of the 57 remaining extension fixes, and it is now written where whoever does them will read it.

The 65 hidden files, up from 56 at #7353, while the layer itself stayed frozen correction is also a real catch — the old note's file count had drifted and would have misled anyone sizing this next.

Honestly reported gap: the package's full suite was not run to completion locally (its e2e files boot a runtime and exceeded the per-command cap under shared-lock contention). Reported as a gap rather than dressed as a pass; CI runs it, and Test Core is the job that matters here.

Flip held until every gate job concludes success on its own reading. check:type-check-debt is the load-bearing one — it was green locally at this PR's head 81a3616e8 with the cli entry printing no line at all, meaning measured equals recorded exactly at 146, but CI re-measures on a fresh closure and that is the reading that counts.


Generated by Claude Code

@qq9340100Claude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPT — PM review, domain:cli seat

All four dispatch rulings verified from the diff rather than from the PR body, because every one of them is the kind of claim a green CI run cannot distinguish from a violation.

Ruling 1 — shrink only, never raise: VERIFIED. Across the entire ledger exactly twoerrors: lines changed — 188 out, 146 in. One entry, and it went down.

Ruling 2 — @objectstack/cli's entry only: VERIFIED by the same reading.packages/lint stays at 20 against a measured 19; that surplus belongs to #8610 and was left alone. Tidying it here would have silently resolved another card's open question inside a diff about something else.

Ruling 4 — fix at source: VERIFIED. No @ts-expect-error, no @ts-ignore, no : any, no as any anywhere in the diff. The whole change to the test files is two .js extensions plus the deletion of one workaround annotation — and deleted, not widened, so the parameter picks up the producer's declared ExpectedEntry instead of a hand-written narrowing.

Ruling 3 — the note rewrite: this is the part that earns the card. The −42 is fully attributed with no unexplained remainder (i18n-coverage 35 → 0, i18n-extract 7 → 0), and the claim that nothing else moved is backed by the before/after diagnostic sets being identical line for line outside those two files. The new note describes what the pile is now made of — 57 of the 59 extension-less imports still present across 24 files, and every one of the 60 surviving TS7006 sitting in a file that also carries a TS2835, so there is no implicit-any left in this layer without a broken import above it. That last sentence is what stops the next author mis-sizing the work.

Two things it did beyond the ask, both worth keeping:

  • It recorded a trap rather than just a number. Fixing the i18n-extract import alone takes that file 7 → 4, not 7 → 0, because the annotation written to dodge the implicit-any had narrowed the real type away — so collapsing a cascade can expose errors, not only remove them. That sits under each of the 57 remaining extension repairs, and it is now written where the next person will meet it instead of rediscovering it.
  • It caught a stale figure in the old note. The hidden-file count had drifted 56 → 65 while the layer itself stayed frozen since [observation] check:type-check-coverage's test-layer count is exclude-shaped, so a package that simply omits test/ from include is invisible to it #7353. The old note would have mis-sized the work for whoever picked it up next.

Honest gap, correctly reported: the package's full suite did not finish locally — its e2e files boot a runtime and exceeded the per-command cap under shared-lock contention. Reported as not-run rather than dressed up, and CI ran it. pnpm --filter @objectstack/cli typecheck exiting 0 is noted for what it is: structurally blind to this layer (include: ["src"]), so it proves nothing here and only the ledger measures it.

All 32 checks concluded success or skipped — including check:type-check-debt re-measuring the cli entry to exactly 146 with no line printed. Flipping to ready with auto-merge.


Generated by Claude Code

@qq9340100
qq9340100 marked this pull request as ready for review August 15, 2026 00:14
@qq9340100
qq9340100 added this pull request to the merge queueAug 15, 2026
Merged via the queue into main with commit 8d4f8c4Aug 15, 2026
33 checks passed
@qq9340100
qq9340100 deleted the claude/issue-8612-cli-test-debt-import-extensions branch August 15, 2026 00:32
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

2 participants

@qq9340100@claude