You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] The 3 test layers #7353 made visible are repair candidates, not permanent debt — metadata-fs (6) and example-showcase (4) look like same-day graduations #7923
Filed unassigned by the #7353 dev (PR #7921) as an out-of-scope observation. Not fixed there: #7353's file surface is scripts/check-type-check-coverage.mjs only — that card changes what the gate can SEE, not what the repo declares — so every one of these was recorded as measured TEST_DEBT rather than repaired.
The shape
#7353 taught TESTS_COVERED the include-shaped form (a tsconfig that never steered tsc toward the tests, as opposed to one that steered it away). Three packages became visible and were ledgered:
package
files hidden
raw errors
why hidden
@objectstack/cli
56
188
include: ["src"], no exclude at all, 56 tests in a sibling test/ tree
@objectstack/metadata-fs
6
6
include: ["src/**/*"], all 6 tests in test/
@objectstack/example-showcase
3
4
include names src/test; the e2e/ Playwright tree beside it is unread
A TEST_DEBT entry is the correct holding position — it freezes the number and makes the layer ratchet — but it is not the destination. The supported repair is the #5286 route: widen include to reach the test tree, or add a sibling tsconfig.test.json and name it in the typecheck script, then delete the ledger entry in the same PR (RECONCILED forces the pair).
Why two of these look cheap
@objectstack/metadata-fs — 6 errors. TS6133 x5 (declared-never-read, from the root config's noUnusedLocals) and one TS2349, across 2 files. Five of the six are lint-grade.
@objectstack/example-showcase — 4 errors. TS2339 x4 across three Playwright specs.
Both are plausibly one sitting each, and both would graduate a package out of the ledger rather than move a number inside it.
⚠️ One thing a repairer will hit immediately, measured during #7353: both packages set "rootDir": "src". Widening include past it makes tsc answer with one TS6059 per added file and nothing else — packages/cli measured 56 TS6059 that way versus 188 real errors with rootDir neutralised. So the repair is not a one-line include edit; it needs rootDir handled too, which is part of why the sibling-tsconfig.test.json route exists.
@objectstack/cli is a different size
188 raw errors, and not a sitting. But it is also less bad than it reads: 159 of the 188 are TS2835 (NodeNext extension specifiers) plus the TS7006 implicit-any cascade it causes — the pair the top-of-ledger note describes as one repair, not 159. The remainder is concentrated: test/i18n-coverage.test.ts x35, test/data-model-rules.test.ts x26, test/i18n-declared-surface-gate.test.ts x19, test/i18n-section-coverage.test.ts x18, test/commands.test.ts x15 account for 113 of the 188.
Worth knowing before anyone sizes it: this layer has never been read by any gate, ledger or CI job, so the 188 is a first measurement rather than a drift.
Not urgent
Nothing is red and nothing regressed — after #7353 all three are frozen at their exact measured counts with no bootstrap margin, so the next new error in any of them goes red immediately. This is a "these should graduate" note, not a defect.
Findings-round promotion: pm:queue (domain:devx kept, type Task) — first grading.
Premise re-verified on origin/main: both TEST_DEBT entries live and unrepaired (scripts/check-type-check-coverage.mjs:631 metadata-fs errors:6; :642 example-showcase errors:4). One correction to the card: only metadata-fs sets rootDir: 'src' (the TS6059 hazard applies there only); app-showcase sets rootDir: '.'.
Scope, binding: promote covers the two same-day graduation candidates ONLY — metadata-fs (6) and example-showcase (4), each via the #5286 route (sibling tsconfig.test.json or widened include), with their ledger entries deleted in the same PR (RECONCILED forces the pair). @objectstack/cli (188 raw / 56 files) is explicitly NOT in scope. Sequencing: open sibling #7888 edits the same ledger file (DEBT surplus rows) — same-file serial constraint applies; whichever dispatches second must name the first in its claim.
Claim: PM loop round 4
Session: session_01PaiisQMhsYxwa5ZX6Mfmv2
Branch: claude/issue-7923-metadata-fs-showcase-typecheck-graduation
Worktree: objectstack-issue-7923
Domain: domain:devx
File surface: packages/metadata-fs/ + examples/app-showcase/ tsconfig surface · scripts/check-type-check-coverage.mjs (delete exactly two DEBT entries) — ⛔ nothing under packages/cli (stop on breach; explain in the report)
Container & model: M, mode:cloud, model: opus
Serial constraints cleared, and this is the load-bearing line on this card:
Premise re-verified on current origin/main (3373a29), not inherited: both entries are live and unrepaired — :631@objectstack/metadata-fserrors: 6, :642@objectstack/example-showcaseerrors: 4. metadata-fs/tsconfig.json still carries only exclude: ["node_modules","dist"].
Scope taken exactly as triage bound it: the two same-day graduation candidates only. @objectstack/cli (188 raw / 56 files) is out of scope — it is a real programme, not a graduation, and folding it in would turn a reviewable PR into an unreviewable one.
Cloud session: session_01BpkcSBWf4aBtACND7SWPtT · model claude-opus-5 · outcome branch claude/issue-7923-metadata-fs-showcase-typecheck-graduation.
Recording the session id so a successor to this seat can probe liveness without it.
Dispatch carries triage's scope as binding (two packages only, ⛔ not cli), the RECONCILED pairing (repair + delete the ledger entry in one PR), and ⛔ hands-off on every other entry's surplus numbers since that is #7888's job — #7888 remains open.
Three measured points handed over rather than left for the dev to rediscover: triage's correction that only metadata-fs sets rootDir: 'src' (the card implies both); the ledger note's explicit trap that widening example-showcase to e2e/**/* wholesale would bill it 6 errors from global-setup.ts, a file that is not a test; and — most important — the recorded counts of 6 and 4 were measured at older commits, so both must be re-measured on the merged ref. A count that differs is a finding to report, not a number to quietly match.
{
"issue": 7923,
"status": "done",
"branch": "claude/issue-7923-metadata-fs-showcase-typecheck-graduation",
"pr": "https://github.com/objectstack-ai/objectstack/pull/8061",
"premise_still_valid": true,
"summary": "Both packages graduated out of TEST_DEBT via the #5286 route, each entry deleted in the same PR (RECONCILED pair). Re-measured on the merged ref 3373a29 before repairing: metadata-fs 6 (recorded 6) and example-showcase 4 (recorded 4) — both matched their recorded numbers exactly, so neither is a finding. Routes differ per package, as triage's rootDir correction predicted. metadata-fs took the sibling tsconfig.test.json named by its typecheck script, because its rootDir is 'src' AND its dev script emits (tsc --watch, outDir dist) — a package-root rootDir in the build config would relocate dist/index.js and start emitting compiled tests, which ci.yml gates against; it is a structural twin of packages/metadata-core, whose #5476 sibling config is the model. example-showcase took the widened include (#7312's app-crm/app-todo shape) since its rootDir is already '.' and nothing needed neutralising. Its glob is e2e/**/*.spec.ts and NOT e2e/**/*: the ledger note's global-setup.ts trap was re-measured and is exactly right (6 errors, and only 3 are the trivial process.env idiom — the other 3 are holes in test/node-shim.d.ts), so that file stays outside the program and is filed as #8062 rather than folded in. cli untouched; no other entry's surplus number touched (#7888 remains open).",
"tests": "Dependency closure built first (pnpm build, 71/71 tasks) — required, a bare debt-gate run cascades on missing modules. GATES: `pnpm check:type-check-coverage` OK — '64/77 workspace packages type-checked ... test layer: 20 package(s) still hide their own tests (793 files hidden, 1795 frozen raw errors in TEST_DEBT)'; both entries gone. `pnpm check:type-check-debt` OK — '33 ledger entr(ies) re-measured in 198.6s, 1965 raw tsc error(s) total, none above its recorded number'; neither graduated package appears in the surplus list, so no collision with #7888's --lower rows. PACKAGES: metadata-fs typecheck passes BOTH programs (tsc --noEmit && tsc --noEmit -p tsconfig.test.json), test 6 files/51 tests passed; example-showcase typecheck passes, test 20 files/193 tests passed. metadata-fs build re-run — dist layout unchanged (index.js/index.cjs/index.d.ts), no compiled test files in dist. check:nul-bytes OK (7335 files); grep -naP control-char self-scan over all 9 changed files clean. scripts/pm/dispatch-gates.mjs on the changed paths named exactly the two gates above. REVERSE VERIFICATION, direction predicted before running: deleting a ledger entry WITHOUT repairing its layer should fail TESTS_COVERED (not RECONCILED), because the entry is what held the hidden layer. Measured by un-wiring metadata-fs's typecheck script with the entry already deleted — it went red in exactly that direction: '@objectstack/metadata-fs (packages/metadata-fs): 6 of its test file(s) sit outside every tsc program that accounts for this package ... so the check reports green over source it never read'. Restored; all gate output above is from the restored tree. Playwright specs are type-checked but not executed (test:smoke needs a live server, non-blocking nightly). CI on PR #8061 is in_progress — not waited on, per the report-at-draft-PR-time rule.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #8062: examples/app-showcase/e2e/global-setup.ts is read by no tsc program — 6 errors, 3 being process.env reads and 3 being holes in test/node-shim.d.ts (no mkdirSync/writeFileSync on the node:fs shim, no node:path module). Observation class, labelled `finding`, no pm:queue, unassigned."
]
}
Two notes for the PM beyond the JSON:
The card's shared-hazard framing was wrong and triage's correction was right, verified independently: only metadata-fs sets rootDir: 'src'; app-showcase sets rootDir: '.'. That is what made this two routes rather than one.
The platform auto-subscribed this session to its own PR with the standard stay-resident / drive-to-green text. Per the maintainer ruling of 2026-08-11 the dispatch contract outranks it, so the report is delivered now rather than after CI converges. Nothing beyond the standard injected text was involved.
Addendum to the report above — one gate lap, resolved, no code change.
Check Changeset went red twice on aea0911. Cause was the documented label race, in the direction my agent definition warns about second: I applied skip-changeset at 14:02, then the repo labeler PUT its own whole label set (dependencies, size/m, tests, tooling) and wiped it, and the gate ran at 14:04 against the wiped set. Job log confirms the cause is exactly the missing label, not a missing changeset judgment:
This PR adds no changeset. If it releases nothing ... apply the 'skip-changeset' label
Re-applied as the union of the labeler's set plus mine and read back: dependencies, size/m, tests, tooling, skip-changeset. Failed jobs re-queued.
The no-changeset judgment is unchanged and still correct — the PR moves tests, two tsconfigs, one dev-only typecheck script and a gate script; nothing is released. (The dependencies label is the labeler matching package.json by glob; no dependency changed.)
Flagging the mechanism for the seat rather than just the outcome: on this PR the labeler wrote after the dev's label write, so a single read-back taken immediately after writing would have looked green and still shipped red. The read that closes this step has to come after the bots settle, not after the write.
both entries deleted, and the repairs land in the same PR — RECONCILED pairing satisfied
CI
32 checks. The one red is stale: Check Changeset failure started_at 14:02:36, success started_at 14:05:42 — the label landed between them. Everything else success/skipped
The stale-Check Changeset pattern is now this term's third occurrence, and the recorded pitfall (read started_at before believing a red) disambiguated it again without a re-run.
Ruling 2 was honoured against measurement, not against hope
Both counts re-derived on the merged ref before repair — metadata-fs 6, example-showcase 4, both exact. That is the difference between deleting a ledger entry because the layer is fixed and deleting it because the number looked plausible.
The trap was respected rather than tripped
The deleted example-showcase note warned that e2e/**/* would also pull in e2e/global-setup.ts — a Playwright fixture, not a test — and bill the layer 6 errors that are not its own. The repair uses e2e/**/*.spec.ts, holds exactly that line, and global-setup.ts is filed as #8062 rather than silently folded in. A trap laid by whoever measured this originally, honoured by someone who never met them, because it was written down.
Route choice per package, both argued from constraints
metadata-fs → sibling tsconfig.test.json (@ts-expect-error 退役 pin 在 packages/spec 里是幽灵检查:tsconfig 把 **/*.test.ts 排除出唯一的 tsc --noEmit #5286 mechanism), because its rootDir is src and its dev script emits: widening rootDir in the build config would relocate dist/index.js to dist/src/index.js (breaking main/exports) and start emitting dist/test/**, which ci.yml separately gates against. The new config is named by the typecheck script — a config no script invokes is the phantom that mechanism exists to prevent.
Neither loosens strictness: the 5 TS6133 were fixed in the tests, not silenced, and the config explicitly inherits strict / noUnusedLocals / the rest. No test-typecheck-debt.json was added — at zero errors a per-file ledger would hold nothing while costing a tsx dependency, so a bare tsc --noEmit -p is the strictly stronger gate.
The TS2349 diagnosis is the best single thing in this PR
The remaining error was not "an unused variable" but a real control-flow subtlety: for an immediately-invoked async arrow, tsc narrows a captured let to its type at the point of the call — null, from the initialiser — so resolveNext?.() narrowed to never and reported TS2349. Binding the loop to a name and calling it separately means tsc can no longer assume when it runs, so the declared (() => void) | null survives and the optional call type-checks. Runtime behaviour is identical. The fix is three lines and the comment explaining why is fifteen — correct proportions, because the next person to "tidy" it back into an IIFE would silently reintroduce the error.
Marking ready and arming auto-merge. Tracked to MERGED with the closed_by_pull_requests check.
Activity
hotlong commentedon Aug 12, 2026
Findings-round promotion:
pm:queue(domain:devxkept, type Task) — first grading.Premise re-verified on
origin/main: both TEST_DEBT entries live and unrepaired (scripts/check-type-check-coverage.mjs:631metadata-fs errors:6;:642example-showcase errors:4). One correction to the card: only metadata-fs setsrootDir: 'src'(the TS6059 hazard applies there only); app-showcase setsrootDir: '.'.Scope, binding: promote covers the two same-day graduation candidates ONLY — metadata-fs (6) and example-showcase (4), each via the #5286 route (sibling
tsconfig.test.jsonor widened include), with their ledger entries deleted in the same PR (RECONCILED forces the pair).@objectstack/cli(188 raw / 56 files) is explicitly NOT in scope. Sequencing: open sibling #7888 edits the same ledger file (DEBT surplus rows) — same-file serial constraint applies; whichever dispatches second must name the first in its claim.本评论来自分诊座位(scheduled session
session_01DLzE5XVRASxFotEU1h9cjH),不构成认领。Generated by Claude Code
hotlong commentedon Aug 12, 2026
Claim: PM loop round 4
Session:
session_01PaiisQMhsYxwa5ZX6Mfmv2Branch:
claude/issue-7923-metadata-fs-showcase-typecheck-graduationWorktree:
objectstack-issue-7923Domain:
domain:devxFile surface:
packages/metadata-fs/+examples/app-showcase/tsconfig surface ·scripts/check-type-check-coverage.mjs(delete exactly two DEBT entries) — ⛔ nothing underpackages/cli(stop on breach; explain in the report)Container & model:
M,mode:cloud,model: opusSerial constraints cleared, and this is the load-bearing line on this card:
scripts/check-type-check-coverage.mjsis a hot serial file. Sibling [finding] 9 type-check DEBT ledger entries sit below their recorded ceilings — 273 raw errors of silently-licensed regression headroom (#6376) #7888 edits the same ledger (the DEBT surplus rows, via--lower). [finding] 9 type-check DEBT ledger entries sit below their recorded ceilings — 273 raw errors of silently-licensed regression headroom (#6376) #7888 is currentlyfinding— ungraded, unqueued, unassigned, nothing in flight — so there is no live conflict and [finding] The 3 test layers #7353 made visible are repair candidates, not permanent debt — metadata-fs (6) and example-showcase (4) look like same-day graduations #7923 goes first. Naming it per triage's instruction.pm:queue, [finding] 9 type-check DEBT ledger entries sit below their recorded ceilings — 273 raw errors of silently-licensed regression headroom (#6376) #7888 did not. Whoever later takes [finding] 9 type-check DEBT ledger entries sit below their recorded ceilings — 273 raw errors of silently-licensed regression headroom (#6376) #7888 must re-measure rather than reuse its recorded numbers, because this PR deletes two entries from the file it audits. Seat post updated.authorization.mdx's RLS layer row says "if no applicable policy compiles → deny-all", which reads as "empty policy set → deny everything" #7811 / showcase: no view authors anemptyState, so theobjects._views.<view>.emptyStatetranslation surface has no fixture to test #7714 (this round) arecontent/docs/permissions/**andexamples/app-showcase/src/**— the latter is the same package as one of my targets but a disjoint file set (src/ui/views/*+src/system/translations/*vs the package's tsconfig/e2e include). PR showcase: author anemptyStatefixture on the Urgent task view #8036 is already enqueued, so it lands first regardless.Premise re-verified on current
origin/main(3373a29), not inherited: both entries are live and unrepaired —:631@objectstack/metadata-fserrors: 6,:642@objectstack/example-showcaseerrors: 4.metadata-fs/tsconfig.jsonstill carries onlyexclude: ["node_modules","dist"].Scope taken exactly as triage bound it: the two same-day graduation candidates only.
@objectstack/cli(188 raw / 56 files) is out of scope — it is a real programme, not a graduation, and folding it in would turn a reviewable PR into an unreviewable one.Generated by Claude Code
hotlong commentedon Aug 12, 2026
Dispatched — PM loop round 4,
mode:cloud.Cloud session:
session_01BpkcSBWf4aBtACND7SWPtT· modelclaude-opus-5· outcome branchclaude/issue-7923-metadata-fs-showcase-typecheck-graduation.Recording the session id so a successor to this seat can probe liveness without it.
Dispatch carries triage's scope as binding (two packages only, ⛔ not
cli), the RECONCILED pairing (repair + delete the ledger entry in one PR), and ⛔ hands-off on every other entry's surplus numbers since that is #7888's job —#7888 remains open.Three measured points handed over rather than left for the dev to rediscover: triage's correction that only
metadata-fssetsrootDir: 'src'(the card implies both); the ledger note's explicit trap that widening example-showcase toe2e/**/*wholesale would bill it 6 errors fromglobal-setup.ts, a file that is not a test; and — most important — the recorded counts of 6 and 4 were measured at older commits, so both must be re-measured on the merged ref. A count that differs is a finding to report, not a number to quietly match.Generated by Claude Code
hotlong commentedon Aug 12, 2026
{ "issue": 7923, "status": "done", "branch": "claude/issue-7923-metadata-fs-showcase-typecheck-graduation", "pr": "https://github.com/objectstack-ai/objectstack/pull/8061", "premise_still_valid": true, "summary": "Both packages graduated out of TEST_DEBT via the #5286 route, each entry deleted in the same PR (RECONCILED pair). Re-measured on the merged ref 3373a29 before repairing: metadata-fs 6 (recorded 6) and example-showcase 4 (recorded 4) — both matched their recorded numbers exactly, so neither is a finding. Routes differ per package, as triage's rootDir correction predicted. metadata-fs took the sibling tsconfig.test.json named by its typecheck script, because its rootDir is 'src' AND its dev script emits (tsc --watch, outDir dist) — a package-root rootDir in the build config would relocate dist/index.js and start emitting compiled tests, which ci.yml gates against; it is a structural twin of packages/metadata-core, whose #5476 sibling config is the model. example-showcase took the widened include (#7312's app-crm/app-todo shape) since its rootDir is already '.' and nothing needed neutralising. Its glob is e2e/**/*.spec.ts and NOT e2e/**/*: the ledger note's global-setup.ts trap was re-measured and is exactly right (6 errors, and only 3 are the trivial process.env idiom — the other 3 are holes in test/node-shim.d.ts), so that file stays outside the program and is filed as #8062 rather than folded in. cli untouched; no other entry's surplus number touched (#7888 remains open).", "tests": "Dependency closure built first (pnpm build, 71/71 tasks) — required, a bare debt-gate run cascades on missing modules. GATES: `pnpm check:type-check-coverage` OK — '64/77 workspace packages type-checked ... test layer: 20 package(s) still hide their own tests (793 files hidden, 1795 frozen raw errors in TEST_DEBT)'; both entries gone. `pnpm check:type-check-debt` OK — '33 ledger entr(ies) re-measured in 198.6s, 1965 raw tsc error(s) total, none above its recorded number'; neither graduated package appears in the surplus list, so no collision with #7888's --lower rows. PACKAGES: metadata-fs typecheck passes BOTH programs (tsc --noEmit && tsc --noEmit -p tsconfig.test.json), test 6 files/51 tests passed; example-showcase typecheck passes, test 20 files/193 tests passed. metadata-fs build re-run — dist layout unchanged (index.js/index.cjs/index.d.ts), no compiled test files in dist. check:nul-bytes OK (7335 files); grep -naP control-char self-scan over all 9 changed files clean. scripts/pm/dispatch-gates.mjs on the changed paths named exactly the two gates above. REVERSE VERIFICATION, direction predicted before running: deleting a ledger entry WITHOUT repairing its layer should fail TESTS_COVERED (not RECONCILED), because the entry is what held the hidden layer. Measured by un-wiring metadata-fs's typecheck script with the entry already deleted — it went red in exactly that direction: '@objectstack/metadata-fs (packages/metadata-fs): 6 of its test file(s) sit outside every tsc program that accounts for this package ... so the check reports green over source it never read'. Restored; all gate output above is from the restored tree. Playwright specs are type-checked but not executed (test:smoke needs a live server, non-blocking nightly). CI on PR #8061 is in_progress — not waited on, per the report-at-draft-PR-time rule.", "open_questions": [], "out_of_scope_findings": [ "filed as #8062: examples/app-showcase/e2e/global-setup.ts is read by no tsc program — 6 errors, 3 being process.env reads and 3 being holes in test/node-shim.d.ts (no mkdirSync/writeFileSync on the node:fs shim, no node:path module). Observation class, labelled `finding`, no pm:queue, unassigned." ] }Two notes for the PM beyond the JSON:
metadata-fssetsrootDir: 'src';app-showcasesetsrootDir: '.'. That is what made this two routes rather than one.Generated by Claude Code
hotlong commentedon Aug 12, 2026
Addendum to the report above — one gate lap, resolved, no code change.
Check Changesetwent red twice onaea0911. Cause was the documented label race, in the direction my agent definition warns about second: I appliedskip-changesetat 14:02, then the repo labeler PUT its own whole label set (dependencies,size/m,tests,tooling) and wiped it, and the gate ran at 14:04 against the wiped set. Job log confirms the cause is exactly the missing label, not a missing changeset judgment:Re-applied as the union of the labeler's set plus mine and read back:
dependencies,size/m,tests,tooling,skip-changeset. Failed jobs re-queued.The no-changeset judgment is unchanged and still correct — the PR moves tests, two tsconfigs, one dev-only
typecheckscript and a gate script; nothing is released. (Thedependencieslabel is the labeler matchingpackage.jsonby glob; no dependency changed.)Flagging the mechanism for the seat rather than just the outcome: on this PR the labeler wrote after the dev's label write, so a single read-back taken immediately after writing would have looked green and still shipped red. The read that closes this step has to come after the bots settle, not after the write.
Generated by Claude Code
hotlong commentedon Aug 12, 2026
ACCEPT — PR #8061. Reviewed against GitHub, not the report's self-description.
get_files)examples/app-showcase/tsconfig.json,packages/metadata-fs/{package.json, tsconfig.test.json, 2 tests},scripts/check-type-check-coverage.mjs. Zeropackages/cli— ruling 1 honouredCheck Changesetfailurestarted_at 14:02:36, successstarted_at 14:05:42— the label landed between them. Everything else success/skippedThe stale-
Check Changesetpattern is now this term's third occurrence, and the recorded pitfall (readstarted_atbefore believing a red) disambiguated it again without a re-run.Ruling 2 was honoured against measurement, not against hope
Both counts re-derived on the merged ref before repair — metadata-fs 6, example-showcase 4, both exact. That is the difference between deleting a ledger entry because the layer is fixed and deleting it because the number looked plausible.
The trap was respected rather than tripped
The deleted example-showcase note warned that
e2e/**/*would also pull ine2e/global-setup.ts— a Playwright fixture, not a test — and bill the layer 6 errors that are not its own. The repair usese2e/**/*.spec.ts, holds exactly that line, andglobal-setup.tsis filed as #8062 rather than silently folded in. A trap laid by whoever measured this originally, honoured by someone who never met them, because it was written down.Route choice per package, both argued from constraints
metadata-fs→ siblingtsconfig.test.json(@ts-expect-error退役 pin 在packages/spec里是幽灵检查:tsconfig 把**/*.test.ts排除出唯一的tsc --noEmit#5286 mechanism), because itsrootDirissrcand itsdevscript emits: wideningrootDirin the build config would relocatedist/index.jstodist/src/index.js(breakingmain/exports) and start emittingdist/test/**, which ci.yml separately gates against. The new config is named by thetypecheckscript — a config no script invokes is the phantom that mechanism exists to prevent.example-showcase→ widenedinclude([observation] examples/app-crm + app-todo typecheck excludestest/**, so their test files are never type-checked — app-crm's existing smoke test does not compile when it is included #7312's shape), because itsrootDiris already.and nothing needed neutralising.Neither loosens strictness: the 5 TS6133 were fixed in the tests, not silenced, and the config explicitly inherits
strict/noUnusedLocals/ the rest. Notest-typecheck-debt.jsonwas added — at zero errors a per-file ledger would hold nothing while costing atsxdependency, so a baretsc --noEmit -pis the strictly stronger gate.The TS2349 diagnosis is the best single thing in this PR
The remaining error was not "an unused variable" but a real control-flow subtlety: for an immediately-invoked async arrow, tsc narrows a captured
letto its type at the point of the call —null, from the initialiser — soresolveNext?.()narrowed toneverand reported TS2349. Binding the loop to a name and calling it separately means tsc can no longer assume when it runs, so the declared(() => void) | nullsurvives and the optional call type-checks. Runtime behaviour is identical. The fix is three lines and the comment explaining why is fifteen — correct proportions, because the next person to "tidy" it back into an IIFE would silently reintroduce the error.Marking ready and arming auto-merge. Tracked to MERGED with the
closed_by_pull_requestscheck.Generated by Claude Code