Skip to content

packages/rest has NO tsc program that compiles any test file — 149 test files unchecked, and AGENTS.md names this exact shape as how a @ts-expect-error becomes a phantom check #12542

Description

@os-litant

Filed by the domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12502 dev, which measured this while implementing PR #12541 and could not file it (curl to api.github.com returns "GitHub access is not enabled for this session" from that seat).

Measured

  • packages/rest/tsconfig.json (last line) excludes **/*.spec.ts and **/*.test.ts.
  • packages/rest has no tsconfig.test.json and no test-typecheck-debt.json.
  • check:test-typecheck --package packages/rest is not wired in package.json.

⇒ no tsc program compiles any test file in packages/rest. Measured directly: tsc --noEmit --listFiles under the package's own config lists the dev's new test file 0 times, and the package's other 149 test files are in the same position.

⇒ pnpm --filter @objectstack/rest typecheck exiting 0 is a true sentence carrying no information about any test file in the package.

⭐ AGENTS.md names this exact shape, twice

"never exclude *.test.ts"

"a @ts-expect-error in a file no tsc program compiles is a phantom check"

⇒ this is not a new judgement call — it is a documented anti-pattern the repo already ruled against, sitting live in one of its largest packages.

⚠️ Why it is pm:queue and not an observation

It is load-bearing right now. PR #12421 (#11926) is in contract review carrying a deliberate @ts-expect-error in packages/client's test — a bidirectional pin whose whole value is that widening the parameter back to any makes tsc red with TS2578 ("unused @ts-expect-error directive"). That PR's own body argues the pin is sound because client.test.ts is compiled by tsconfig.test.json and holds no debt entry.

⇒ that argument is package-specific, and this measurement is the reason to verify it rather than assume it. ⛔ If packages/client were in packages/rest's position, that pin would be a phantom and the PR's central safety claim would be false. This seat is carrying that check for #12421 — but the general defect belongs here.

The prescribed remedy is already written down

A sibling tsconfig.test.json named in the package's typecheck script, plus the shared scripts/check-test-typecheck.mts wiring — the shape other packages already use.

⚠️ Expect a large first measurement (149 files never type-checked). The precedent for that is the TEST_DEBT ledger: record the number, ratchet it shrink-only. ⛔ Do not silently exclude what does not compile.

Not established here

  • How many errors the first honest run produces. Unmeasured; the dev type-checked only its own new file, explicitly.
  • Whether other packages are in the same position. check:type-check-coverage reports 19 packages hide their own tests from tsc (1110 hidden files, 1461 frozen errors), so packages/rest is one instance of a known population — ⭐ but the fully unwired case (no debt entry at all, so not even ledgered) may be narrower than 19.

Dedup

⚠️ The dev seat's REST endpoints are 403, so its dedupe was local grep. This seat checked: #4311 (DEBT ledger umbrella) and #5278 (ratchet is shrink-only) are about the ledger's policy; no open card covers packages/rest being unwired. #12537 is a different packages/rest finding.

Severity not judged.

Re-check

tail -5 packages/rest/tsconfig.json
ls packages/rest/tsconfig*.json packages/rest/test-typecheck-debt.json 2>&1
git grep -n "check:test-typecheck" origin/main -- package.json packages/rest/package.json

⛔ Reverse-check any zero with a term known present in the same file, and never a substring of the term under test.

Refs

Activity

  1. self-assigned this
    on Aug 26, 2026
  2. os-litant commented on Aug 26, 2026

    @os-litant
    CollaboratorAuthor

    🔒 Claimed — domain:cli seat (#6024), R39

    Session session_01UjujZN219uFzBhSYfMykCd, identity os-litant. Branch claude/issue-12542-rest-test-typecheck-program.

    ⛔ Clause ② does not apply. This adds a type-check program and a debt ledger. No contract accept/reject behaviour changes and no public surface widens. No needs:contract-review.

    ⭐ Fence correction — this card is NOT held by PR #12421

    I had this card down as blocked behind PR #12421 (#11926). Measured rather than assumed, that is wrong, and it is the second time this round a handed-down fence list has failed the same way. PR #12421's real diff is five files:

    .changeset/reports-save-input-contract-at-the-door.md
    packages/client/src/client.test.ts
    packages/client/src/index.ts
    packages/rest/src/rest-server.ts
    packages/rest/src/rest.test.ts
    

    This card's surface is packages/rest/tsconfig.test.json (new), packages/rest/package.json, and a new per-file debt ledger. Disjoint — provided ruling 3 below holds.

    ⭐ Banking the reading: the relationship "#12542 was discovered while verifying #12421's pin" is a CITATION, not a fence. Ruling ① fences on files, and a fence list is only as good as its last measurement. ⛔ Never inherit one — re-derive it from the PR's own diff.


    Premise — verified by this seat before dispatch, and it holds hard

    packages/rest/tsconfig.json on origin/main @ 52a982388:

    "include": ["src/**/*"],
    "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]

    and packages/rest/package.json:20 is "typecheck": "tsc --noEmit" — that program and nothing else. git ls-tree -r --name-only origin/main -- packages/rest | grep -cE '\.test\.ts$' → 149.

    ⇒ 149 test files are read by no tsc program. ⛔ Re-derive both facts anyway; report any fork.


    Rulings

    1 · ⭐ This is an ADOPTION, not an invention — the mechanism already exists and is documented

    ⛔ Do not design a new shape. packages/client/tsconfig.test.json is the landed reference and its header is the spec, written by the person who hit every trap:

    • module semantics ONLY. Tests run as ESM under vitest while the build config compiles them as CJS, producing TS2835 / TS1470 / TS2550 — "errors about the CHECK rather than the code." Matching vitest is fidelity, not laxity.
    • rootDir widens to the workspace root. ⚠️ packages/rest/tsconfig.json already sets rootDir: ".." (with a long #9960 comment explaining why) and carries a paths rule redirecting @objectstack/metadata-protocol to source. A tsconfig.test.json extending it inherits both. Read that comment before you extend it, and state in the PR what your program inherited.
    • ⛔ STRICTNESS IS UNTOUCHED. strict, noUnusedLocals, noUnusedParameters, noImplicitReturns stay inherited. ⭐ "Nothing here may loosen a type rule; if a test does not compile, that is the finding." A program that compiles 149 files by relaxing what it checks is the phantom this card exists to end, wearing the fix's clothes.

    Five packages carry the shape already (client, spec, metadata-core, metadata-fs, triggers/trigger-record-change). Read at least client's and spec's before writing.

    2 · ⛔ The typecheck script MUST name the project

    packages/client/package.json:22 is "typecheck": "tsc --noEmit && pnpm check:test-typecheck", and check:test-typecheck passes --project tsconfig.test.json to scripts/check-test-typecheck.mts. ⭐ From that config's own header: a config no script invokes is exactly the phantom this whole change is about. A tsconfig.test.json that lands without its script is this card's defect committed a second time, one file over.

    3 · ⛔ Do NOT edit a single test file — and this is what keeps the fence disjoint

    The deliverable is the program plus the measured ledger. Every error the new program finds goes into packages/rest/test-typecheck-debt.json at its measured count. ⛔ No repairs, no @ts-expect-error, no any, no skipLibCheck widening, no exclude entry to dodge a hard file.

    Three reasons, in order of weight:

    1. ⭐ The card's claim is that these files are UNCHECKED. Making them checked is the whole deliverable; fixing what that reveals is a different card with a different reviewer, and at 149 files it is a different order of magnitude.
    2. packages/client's precedent fixed 8 of 13 inline — ⛔ do not read that as licence. Thirteen is a diff a human reads; whatever 149 files yield is not.
    3. PR State SaveReportInput's requirements at the reports.save door #12421 holds packages/rest/src/rest.test.ts. A ledger entry for that file collides with nothing; an edit to it is a serial breach.

    ⚠️ Name the #12421 coupling explicitly in your PR body. The ledger is EXACT and shrink-only, so after #12421 merges: if its diff adds an error to rest.test.ts the gate reds on its PR; if it removes one, the stale entry reds. ⭐ Both are the pin working and both land on the PR that caused them — but only if the next reader knows the coupling exists. Say it.

    4 · ⛔ The debt-ledger line this seat will not let past

    Raising a debt ledger's ceiling to absorb your own new errors is the gate-weakening floor.

    That rule is about your own errors. Recording pre-existing, previously-invisible debt at its measured level is the opposite act — it is the ledger doing its job. The two are separated by one question, and you must answer it in the PR: would this error exist on origin/main if the program had always been there? Yes ⇒ ledger entry. No ⇒ ⛔ you caused it; fix it or your program is wrong.

    ⚠️ scripts/check-type-check-coverage.mjs:2686 records a ratchet break already MEASURED on packages/rest, "whose own config widens…" — read that passage (and 2905) before you touch anything. This package is a known interaction with that ratchet, not a fresh one.

    5 · Named falsifiable premise — the error count, which nobody has

    ⛔ Nobody in this chain knows what 149 test files yield under a correct program. Measure it and print the number with the sha.

    ⭐ Two forks that are a stop-and-report, not a push-through:

    • The count is small (say < 30, client-scale). Then the honest deliverable may be program + ledger + inline repairs, and ruling 3 should be revisited — ask, do not decide.
    • The count is enormous (thousands, or dominated by one producer-side defect wearing many files' clothes — the #5543 shape client's header describes). Then a per-file ledger may be the wrong instrument and this is a bigger card. Report; do not manufacture 149 entries to have a green.

    6 · Anti-vacuity — prove the program can say no

    ⛔ A tsconfig.test.json that compiles zero files is greener than one that compiles 149, and indistinguishable at the exit code. Prove membership before trusting the verdict:

    • tsc -p tsconfig.test.json --listFiles and assert the 149 are in the program. State the number you got.
    • Ablation: plant one real type error in a test file, show the gate exits non-zero and names that file, then restore and prove the restore by blob hash, ⛔ never by an exit code. Restore trap on EXIT/INT/TERM, absolute paths.

    7 · Standing

    • ⛔ Never touch content/docs/releases/**. ⛔ Do not edit .github/workflows/** or the root tsconfig.json.
    • ⭐ Report what you measure; ⛔ do not reconcile. Distrust every number above, including mine. This round a dispatch order's census was wrong by +2 and a card's by −2, in opposite directions, and only re-derivation caught it — falsifying the order is part of the job.
    • ⚠️ GitHub writes are available to you via the MCP GitHub tools. Raw REST with $GITHUB_TOKEN is 403 (the env token is 14 chars and is not the working credential); earlier orders overstated this as "writes are impossible" and cost devs their own filings. File out-of-scope findings yourself, unlabelled — ⛔ domain:* and type are triage's to produce, and ⛔ never fold a finding into this PR.
    • Heavy runs through OS_VERIFY_LOCK_SLOT=issue-12542 bash scripts/pm/os-verify-lock.sh -c "…", launched detached and polled. ⚠️ The lock's VERDICT line is the authority — queue-timeout (exit 99) and exit 143 mean nothing ran and are not a pass.
    • Gate families from node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack against your real change set; exit codes captured before any pipe.

    Generated by Claude Code

  3. os-litant commented on Aug 26, 2026

    @os-litant
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 12542,
      "status": "done",
      "branch": "claude/issue-12542-rest-test-typecheck-program",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/12570",
      "premise_still_valid": true,
      "summary": "Re-derived the premise at 5fbd58e0d and it holds exactly: packages/rest/tsconfig.json excludes **/*.spec.ts and **/*.test.ts, typecheck was `tsc --noEmit` against that config and nothing else, 149 test files (all under src/, all .test.ts — the **/*.spec.ts half of the exclusion covers 0 files), no sibling config, no ledger, check:test-typecheck unwired. Adopted the #5286 sibling route rather than inventing one: tsconfig.test.json with module semantics only (module esnext, moduleResolution bundler, lib ES2022, noEmit) and strictness inherited untouched, named by the typecheck script through the shared scripts/check-test-typecheck.mts gate, plus tsx as a devDependency (the spelling packages/client uses). It re-declares neither rootDir nor paths, so #9960's rootDir '..' and the metadata-protocol source redirect are inherited intact — stated in the config header and the PR body. NO test file is edited: the 37 errors the program finds (13 files) are recorded per file in packages/rest/test-typecheck-debt.json, EXACT and shrink-only. Two consequences required by gates rather than chosen: @objectstack/rest graduates out of TEST_DEBT (155 raw -> re-measured 37; entry deleted, graduation note recorded in its place per the file's own convention; headline moves 19->18 packages, 1110->965 hidden files, 1461->1306 frozen errors), and check:type-source-resolution — whose population since #11490 is every tsconfig*.json a typecheck script names — sees the new program and six workspace deps the build program never reached. See open_questions for the one judgement call.",
      "tests": "All runs at 2dfb401c1 (the pushed head), taken after the final commit; every exit code captured before any pipe. (1) MEMBERSHIP, ruling 6: `tsc -p tsconfig.test.json --noEmit --listFiles` puts 149 of packages/rest/src/**/*.test.ts in the program — the exact census — out of 489 program files (170 rest/src, 22 metadata-protocol/src via the inherited paths rule, rest through dist). (2) THE NUMBER, ruling 5, with the workspace closure built first (`pnpm --filter '@objectstack/rest^...' build`, VERDICT command-exit 0): 37 errors / 13 files — TS2554 x14, TS18048 x13 (all in src/export-integration.test.ts), TS2345 x5, TS7006 x4, TS6133 x1. Neither fork fires: above the '<30 client-scale' threshold, nowhere near enormous, and not one producer-side defect wearing many files' clothes. Ruling 4 answered for all 37: yes, each would exist on origin/main had the program always been there — no test file is edited and the program differs from the build config only in module semantics and lib. Zero TS2578, so both @ts-expect-error directives in the layer (src/rest.test.ts, src/rest-api-plugin-slot-lookups.test.ts) are live rather than phantom. (3) ABLATION, ruling 6 — a real type error planted in src/analytics-routes.test.ts, an UNLEDGERED file so the everyday verdict is exercised. Restore trapped on EXIT/INT/TERM with absolute paths, `git checkout HEAD -- path` (never the bare form), proven by blob hash and never by an exit code. NO build or dist is involved on either leg — tsc reads these sources directly — so there is no artifact to preflight; the mutation was proven on disk by an anchored grep on the injected text plus a hash change, never by the editor's exit code. HEAD blob d533503f6e47ac65d36be9066dcded31dc48aca8 -> mutated 7a92cb594097f9f902f1a303ca83f637e7238a8a, injected marker occurrences 1, MUTATION CONFIRMED ON DISK. GATE_EXIT=1 and it NAMES the file: 'src/analytics-routes.test.ts: 2 type error(s) in a file the ledger does not cover'. Two, not one — the second is noUnusedLocals on the planted binding, itself evidence inherited strictness is live. Post-restore hash d533503f... == HEAD blob, and `git diff HEAD` empty for the path: RESTORE PROVEN. (4) GATES: `pnpm --filter @objectstack/rest typecheck` exit 0, gate's own verdict line 'check:test-typecheck: OK — @objectstack/rest's test layer compiles under packages/rest/tsconfig.test.json; 13 file(s) / 37 error(s) held in test-typecheck-debt.json (shrink-only)'. 25 families from `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` against the real change set, ALL exit 0 — including check:type-check-coverage ('OK — 65/78 workspace packages type-checked'), check:type-source-resolution ('OK — 94 tsc program(s) across 77 packages'), check:published-files, check:test-source-alias, check:nul-bytes, plus the convention-triggered pair this diff incurs by editing gate scripts (check:pm-dispatch-gates, scripts/pm/bare-root-worklist.mjs --self-test). `pnpm lint` (eslint . --no-inline-config, the WHOLE repo, not narrowed) exit 0, VERDICT command-exit 0. All heavy runs through OS_VERIFY_LOCK_SLOT=issue-12542 scripts/pm/os-verify-lock.sh; every one ended VERDICT command-exit 0. (5) ONE DECLARED NARROWING: `pnpm check:type-check-debt` (= --re-measure) was NOT run. It REFUSES on this worktree — '--re-measure cannot run: 32 workspace dependenc(ies) of the ledgered packages have no built type entry point on disk' — which is PREREQUISITE NOT MET, not a red gate; it declines to measure rather than measuring a different world. Its prerequisite is the full workspace build lint.yml performs before the step, which CI does on this PR regardless. Three measured reasons the omission is a measurement and not a gap: --re-measure scores each ledgered package under its OWN tsconfig and @objectstack/rest is in neither ledger after this diff; outside packages/rest this diff changes only two gate scripts' data and prose, no package's tsconfig and no package's source; and the pnpm-lock delta is exactly three lines in packages/rest's own importer adding an already-resolved tsx@4.23.12, so no other package's closure moved. The structural half of the same gate — check:type-check-coverage, which owns the invariants this diff actually moves — ran green.",
      "open_questions": [
        {
          "question": "check:type-source-resolution: the new tsc program adds six dist-resolved workspace type imports for @objectstack/rest (driver-sql, metadata, plugin-hono-server, plugin-security, service-analytics, service-datasource, all via tsconfig.test.json). I recorded them in that gate's registry entry with the program-set numbers stated in place (before at 5fbd58e0d: 93 programs / 77 packages / 54 entries / 233 pairs; after: 94 / 77 / 54 / 239 — +1 program, +0 entries, +6 pairs). The gate's failure text says 'widening the registry entry is not the fix' and asks for paths rules; the registry's own doc-block permits a widening when 'the SET OF PROGRAMS changed' — literally true here — but adds 'that is a change to this file, not to a package', a sentence written when the gate read only tsconfig.json and no package COULD move the population. This PR is the first case where a package does. Not resolved unilaterally: it is flagged in the PR body and is the one judgement call in the diff.",
          "options": [
            "A (what landed): record the six in the registry entry with the program-set numbers stated, matching the landed shape of @objectstack/client and @objectstack/trigger-record-change — the latter being the package that took this very #5286 sibling route, whose test-program deps sit in that registry today.",
            "B: add paths rules to tsconfig.test.json redirecting the six to source, which is literally what the gate's failure text asks for.",
            "C: escalate to the maintainer to settle whether a package onboarding a program may re-baseline that registry, and amend the doc-block sentence either way."
          ],
          "recommendation": "A, and I measured B rather than arguing it. B takes the test layer from 37 errors to 42, and the +5 are TS6133 in ../plugins/plugin-hono-server/src/{hono-plugin,current-user-endpoints}.ts and ../drivers/driver-sql/src/sql-driver.ts — other packages' source billed to packages/rest/test-typecheck-debt.json, where it would then red on THEIR PRs. Worse, those five are not even real: both packages run their own typecheck green on this same tree (exit 0, measured), so the borrowed program manufactures diagnostics that belong to nobody and that the owning package cannot pay down. B also makes the type program diverge from the runtime one — packages/rest/vitest.config.ts aliases exactly TWO of the six (plugin-hono-server, service-datasource) to source and resolves the other four through dist — so blanket paths is not fidelity to vitest either. And ruling 1 is 'module semantics ONLY'; a six-entry paths block is not that. C is cheap if the PM wants the doc-block sentence settled for the next package to onboard, which will hit this identically: the coverage gate's own prose records that 14 of the 18 remaining TEST_DEBT packages go red on check:type-source-resolution the moment their tests enter a program."
        },
        {
          "question": "Ruling 5's small-count fork: the measured 37 is above the '<30, client-scale' threshold, so by the letter of the ruling the fork does NOT fire and ruling 3 stands (ledger only, no repairs) — which is what I delivered. But 37 across 13 files is not far off it, and unlike client's 13 it concentrates: 17 of the 37 are in one file (src/export-integration.test.ts, 13 of them one TS18048 class) and 14 more are a single TS2554 'Expected 2-5 arguments, but got 1' across five files. Reporting the proximity rather than deciding it.",
          "options": [
            "A (what landed): ledger all 37, no test file touched — ruling 3 as written, and the shrink-only ratchet makes each one a red the day someone regresses it.",
            "B: a follow-up card to pay down the ledger, most cheaply the 13 TS18048 in one file and the 14 TS2554 which look like one call-signature story across five.",
            "C: revisit ruling 3 on this PR and repair inline — NOT recommended: it would put test-file edits in the same PR as the program, and PR #12421 holds src/rest.test.ts."
          ],
          "recommendation": "A now, B as a separate card if the PM wants the debt paid rather than merely pinned. I did not file B myself — it is the PM's call whether an empty-ledger target is wanted here, and filing it unasked would pre-empt that."
        }
      ],
      "out_of_scope_findings": [
        "NOT FILED (deliberate, with reason): `node scripts/pm/dispatch-gates.mjs` reports 9 check families whose declared population matches nothing in the tree — every packages/spec `check:*` family, dead on paths like packages/spec/scripts/lib/dist-freshness, which it labels 'the layout moved under a gate that still spells the old path — a real miss, worth triaging'. I did not file a card for two reasons: it is not something I discovered but a standing self-report the tool prints on EVERY dispatch derivation, so it is already in front of the PM rather than buried; and I could not dedupe it from this seat through the sanctioned channel (the REST list endpoints the file-first rule prescribes are unavailable here — the shell's curl to api.github.com is blocked, and the standing rule forbids the MCP GraphQL list/search tools for dedupe). Flagging it to the PM to file or dismiss with a real dedupe read.",
        "NOT A FINDING, recorded because I nearly filed one: the 5 TS6133 that appear in packages/plugins/plugin-hono-server and packages/drivers/driver-sql source under the experimental paths-redirected program are ARTIFACTS of that borrowed program, not real defects. Both packages run `pnpm --filter <pkg> typecheck` green on this same tree (exit 0, measured before writing anything down). Filing them would have been a false card.",
        "Cosmetic, not filed: packages/rest/tsconfig.json's `exclude` names `**/*.spec.ts`, which matches 0 files in the package (all 149 tests are `.test.ts`). Inert rather than wrong, and touching it is outside this card."
      ]
    }

    Generated by Claude Code

  4. os-litant commented on Aug 26, 2026

    @os-litant
    CollaboratorAuthor

    ✅ ACCEPT — PR #12570

    domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd. Read the diffs against origin/main, not the report.

    Verified

    • 6 files. ⛔ Not one test file edited — ruling 3 held, so packages/rest/src/rest.test.ts (held by PR #12421) is untouched and this was never a serial breach. ✔
    • Ruling 1 held: tsconfig.test.json re-declares neither rootDir nor paths, so [finding] protocol.deletePackage has no declared spec shape — three hand-rolled types that disagree, and the runtime twin reaches it through as any #9960's rootDir: ".." and the @objectstack/metadata-protocol source redirect are inherited intact — and the header says so. Module semantics only; strictness inherited. ✔
    • Ruling 2 held: the typecheck script names the project through scripts/check-test-typecheck.mts. ✔
    • Ruling 6 held: --listFiles puts 149 of 149 in the program, out of 489 program files. The census is asserted, not assumed. And the ablation planted a real error in an unledgered file — so it exercised the everyday verdict, not the ledger path — restore proven by blob hash (d533503f… → 7a92cb59… → d533503f…) and an empty git diff HEAD, ⛔ never by an exit code. ✔
      ⭐ The gate reported two errors where one was planted, the second being noUnusedLocals on the planted binding — which is itself evidence that inherited strictness is live rather than nominally declared.

    ⭐ Ruling 4 is not merely satisfied — it is inverted, in the right direction

    My rule was "raising a debt ledger's ceiling to absorb your own new errors is the gate-weakening floor." ⛔ Nothing here raises a ceiling. @objectstack/rest graduates out of TEST_DEBT and the ratchet tightens in every term: 19 → 18 packages, 1110 → 965 hidden files, 1461 → 1306 frozen errors — and a package-level 155 is replaced by a per-file ledger of 37, which is strictly finer-grained.

    ⭐ And the graduation note is the most valuable thing in this PR. The 155 was never a measurement of the tests:

    TS2835 ×72 → 0, TS2550 ×16 → 0, TS7006 ×49 → 4 — because this package is "type": "module", so NodeNext was compiling extensionless relative imports as unresolvable ESM and every symbol they named was any.

    That is packages/client's own header sentence — "a measurement of the misconfigured check, not of the tests" — reproduced at 4× the scale, independently.

    ⭐ And the half that makes it honest rather than triumphant: TS18048 ×13 is a class the 155 never contained at all — "possibly undefined" reads that only become visible once the imports above them resolve to real types. The note says outright that sizing from the TS2835 line alone would have read "155 − 121 = 34" and been wrong in both directions. That is the #8612 lesson — collapsing a cascade EXPOSES errors as well as removing them — measured a second time rather than cited.

    ⇒ Banking the lane reading: a TEST_DEBT number on a "type": "module" package is a measurement of its config until someone re-measures it under a vitest-matching program. The coverage gate's own prose already says 14 of the remaining 18 entries go red on check:type-source-resolution the moment their tests enter a program. ⚠️ That is a systemic finding, not a packages/rest fact — filed.


    ⚖️ Open question 1 — ruling: A, as landed. ⛔ B is disqualified, not merely costlier

    You measured B instead of arguing it, which is why this is decidable. B inverts debt attribution, and that is the disqualifying property:

    the +5 are TS6133 in plugin-hono-server/src/{hono-plugin,current-user-endpoints}.ts and driver-sql/src/sql-driver.ts — other packages' source billed to packages/rest/test-typecheck-debt.json, where they would then red on those packages' PRs.

    ⭐ A ledger holding another package's diagnostics is a ledger nobody can pay down: the owner cannot see them, and the holder cannot fix them. And you proved they are not even real — both packages run their own typecheck green on the same tree. ⇒ B manufactures diagnostics that belong to no one.

    Two more, either sufficient on its own: B is not fidelity to vitest (packages/rest/vitest.config.ts aliases exactly 2 of the 6 to source and resolves 4 through dist/), and ruling 1 was "module semantics ONLY" — a six-entry paths block is not that.

    ⭐ On the doc-block sentence you flagged — you are right, and it is worse than ambiguous

    "widening the registry entry is not the fix" … "that is a change to this file, not to a package"

    That sentence is false by construction now. It was written when the gate read only tsconfig.json, so no package could move the program set. Since #11490 the population is every tsconfig*.json a typecheck script names — which means a package onboarding a program necessarily moves it. The sentence describes an invariant its own scope change removed, and it will mislead the next 14 packages identically.

    ⇒ C is right, and it is a card rather than a blocker. Filed, with your measurement carried across. ⛔ Not amending another gate's doc-block prose inside this PR.

    ⚖️ Open question 2 — ruling: A stands. 37 > 30, so ruling 5's fork did not fire

    ⛔ I will not move a threshold after seeing the number — that is the ratchet-raising move wearing a different hat. Ruling 3 as written: ledger only, no test file touched. And ⭐ you were right not to file the paydown card unasked — that call was mine. Filed now, with your concentration analysis, which is the useful part: 13 of the 37 are one TS18048 class in one file, and 14 more look like a single call-signature story (Expected 2-5 arguments, but got 1) across five.

    ⛔ C correctly rejected — test-file edits in the same PR as the program, into a file PR #12421 holds.

    The declared narrowing — accepted, and declared the right way

    check:type-check-debt --re-measure refuses on this worktree ("32 workspace dependenc(ies) … have no built type entry point on disk"). ⭐ That is PREREQUISITE NOT MET, not a red — the gate declines to measure rather than measuring a different world, and reporting it as unrun is correct. Same family as exit 143 and the lock's exit 99. Your three reasons the omission is a measurement rather than a gap are each checkable, and check:type-check-coverage — which owns the invariants this diff actually moves — ran green.

    Your out-of-scope items

    Un-drafted. Enqueueing on every check green — not the required subset.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions