Skip to content

Pay down 17 of packages/rest's test-typecheck ledger, and refute the cause it records - #12625

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-12573-rest-test-typecheck-paydown
Aug 27, 2026
Merged

Pay down 17 of packages/rest's test-typecheck ledger, and refute the cause it records#12625
os-litant merged 1 commit into
mainfrom
claude/issue-12573-rest-test-typecheck-paydown

Conversation

@os-litant

@os-litantos-litant commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Part of #12573

⚠️Deliberately Part of, not a closing keyword. The card asks for the ledger to be paid down; this pays 17 of the 33 in scope and reports the other 16 as questions rather than repairing them, so merging should not close the card. The dispatch order said to use a closing keyword — flagged here rather than silently chosen, per "report what you measure; do not reconcile". Switch it before marking ready if the card should close anyway.

Ruling 1 first: the ledger's own stated cause is refuted

The ledger's _comment claims the errors are "almost all of them fixture literals annotated with a schema OUTPUT type (z.infer) while holding an authored INPUT literal."

0 of 33. Not "few" — zero.

z.infer occurrences: 0 0 0 0 0 0 0 0 0 0 0 0 (all 12 non-fenced ledgered files)
positive control: 65 `expect` in export-integration.test.ts, 95 in import-integration.test.ts

The zero is a reading, not a broken grep. And there is a reason: that clause is #5478/#5543's finding — registerObject's schema parameter annotated with the z.infer OUTPUT type — and #5543 was closed as completed on 2026-08-08 by PR #6786. This ledger was created 18 days later and stamped with the already-fixed cause. Filed as #12624, together with the reason it cannot be corrected in place: LEDGER_COMMENT is a constant in scripts/check-test-typecheck.mts and --update rewrites _comment from it on every regeneration. I corrected the prose, re-ran the regenerator, and watched the refuted claim come back — so this PR leaves _comment byte-identical and the ledger diff is entries-only.

What the 33 actually are — four stories, exact counts

classcountwhat it isdisposition
TS255414registry.registerObject(x) missing the required packageIdnot repaired — see below
TS1804813getRoutes().find() is Route | undefined✅ repaired
TS70064untyped mock.calls callback parameters✅ repaired
TS23452request literals missing IHttpRequest's headers / pathnot repaired — see below

Two corrections to the card's own numbers, reported rather than reconciled:

  • the 14 TS2554 span six files, not five (export-integration ×4, import-integration ×3, rest-meta-save-receipt-envelope ×3, import-job-integration ×2, import-dryrun-parity ×1, rest-write-response-formula ×1);
  • tsconfig.test.json's header records 489 files in the program measured at 5fbd58e0d; this run measures 640. The 149 test files it records are unchanged.

Fence re-derived from PR #12421's own diff (still open, 5 files): of the 13 ledgered files it holds only src/rest.test.ts. Untouched here, its entry of 4 unchanged.

The 17 repaired — both annotation-only, both in the form this package already uses

TS18048 ×13, all in export-integration.test.ts. Array.prototype.find returns Route | undefined, so all thirteen route.handler(...) calls read as possibly-undefined. Asserted non-null at the two lookup sites rather than at the thirteen call sites — the lookup either finds the route registerRoutes() just registered or the boot is broken. Six already-green siblings in this package use exactly this form (e.g. analytics-dataset-where-gate.test.ts:100). ! erases at compile time, so no call below receives a different value than before.

TS7006 ×4. The vi.spyOn return type leaves mock.calls untyped, so each .map/.filter callback parameter was implicitly any. Annotated unknown[] — the form the green rest-5xx-status-passthrough.test.ts:425 already uses.

Neither emits different JavaScript. Ledger regenerated, not hand-edited: four entries reach zero and are deleted, export-integration.test.ts re-records 17 → 4. The regenerated diff moved only where I worked — every other entry, including the fenced rest.test.ts: 4, is byte-identical. 37 → 20 errors across 13 → 9 files. No number is raised.

The 16 NOT repaired — ruling 6, and they are not typing questions

TS2554 ×14.registry.registerObject(schema, packageId, …) requires packageId; the sibling registerItem on the same class declares the same parameter optional, and both feed the identical applyProtection(item, { packageId }). That helper documents the package-less case as intended: "leave the item alone so that DB-only / test fixtures don't acquire an unexpected _provenance field." So supplying a packageId to satisfy the compiler stamps _packageId and _provenance: 'package' onto the fixture — it changes what the test registers. Routing through the engine facade instead is not neutral either: it defaults to '__runtime__'and mutates the schema by auto-assigning field.name from each key.

That is a fixture's data, not its annotation ⇒ ruling 6 says stop and report. Filed as #12623, with the blast radius: 82 single-argument call sites repo-wide, of which 68 sit in objectql (55), runtime (9) and plugins (4) — none of which has a test-layer tsc program, so the same latent error is unmeasured everywhere except here.

TS2345 ×2 (meta-public-book-grant.test.ts:138, rest-batch-size-cap.test.ts:152). IHttpRequest requires headers and path; these request literals omit both. Adding them changes what the handler receives, and as any — the form the surrounding file uses — is forbidden by the card. Same disposition: data, not annotation.

Anti-vacuity — the gate still says no

  • tsc -p tsconfig.test.json --noEmit --listFiles: 149src/**/*.test.ts still in the program (640 files total), and all five edited files are in it — so these repairs were measured, not merely unopposed.

  • Planted a real type error (const __plant_12573: number = 'not a number';) in rest-unclassified-fault-status.test.ts — a file this PR repaired, whose ledger entry it deletes, so it is now unlisted and any error must red. Mutation confirmed on disk before any verdict was read (marker count 1, blob a46e4c50…078d4759…). The gate exited 1 and named the file:

    • src/rest-unclassified-fault-status.test.ts: 2 type error(s) in a file the ledger does not cover.

  • Restored under a trap … EXIT INT TERM with absolute paths, via git checkout HEAD -- plus the absolute path (never bare). Restore proved by blob hash, not by an exit code: worktree a46e4c50e6a23925b83015701c1ede06a8e40e84 == HEAD: blob, marker count 0, git diff HEAD empty, git status --porcelain empty. The repairs were committed before this leg so HEAD was a real restore point.

Verification

All on 0886595c2, the final commit.

  • pnpm --filter @objectstack/rest test149 files / 2441 tests passed, VERDICT command-exit 0
  • pnpm --filter @objectstack/rest typecheck (tsc --noEmit + check:test-typecheck) — exit 0
  • Gate families re-derived in this worktree with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (it derives its own changeset; 6 changed paths). All matched + convention-triggered families run, exit codes captured before any pipe: check:cross-package-test-inputs, check:dispatcher-error-vocabulary, check:objectql-double-limit, check:page-declaration-shape, check:published-files, check:slot-lookup, check:test-source-alias, check:type-source-resolution, check:query-options-erasure, check:engine-double-contract, check:where-matcher, check:nul-bytes, check:type-check-coverage, check-ci-filter-parity, check-comment-mask-adoption, check-cross-package-test-inputs, check-plugin-teardown-shape, check-affected-docsall exit 0.
  • check:type-check-debt --re-measure first refused to run (a prerequisite refusal, not a red gate: 32 workspace dependencies had no built type entry point, because I had built only @objectstack/rest's own closure). Re-run after building the full closure exactly as lint.yml does — result recorded in the report on the card.
  • The 9 packages/spec families under "THE LAYOUT MOVED" are hintCovers reads an extensionless module specifier as a filesystem path, so 9 packages/spec gate families can never be MATCHED to a change set — silent under-derivation on every dispatch #12514 — not refiled.

Changeset: none, skip-changeset label applied. Measured against the repo's rule rather than recalled: packages/rest's package.json publishes files: ["dist","README.md","CHANGELOG.md"], and this PR changes only src/**/*.test.ts (excluded from the build config) plus test-typecheck-debt.json — nothing published moves. scripts/check-empty-changeset.mjs documents that an empty-frontmatter changeset is a real input to changesets/action and buys nothing the label does not, so the label is the mechanism here and an empty changeset would be the wrong answer.

Scope

No production source touched. packages/rest/src/rest-server.ts, packages/rest/src/rest.test.ts, packages/client/** and content/docs/releases/** are all untouched. The two out-of-scope findings are filed as separate unlabelled issues (#12623, #12624) and not folded into this PR.


Generated by Claude Code

Two annotation-only classes, both repaired in the form this package's
already-green test files use:
- TS18048 x13, all in `export-integration.test.ts`: `getRoutes().find()`
is `Route | undefined`, so every `route.handler(...)` below read as
possibly-undefined. Asserted non-null at the two lookup sites rather
than at the thirteen call sites. `!` erases, so no call receives a
different value than it did before.
- TS7006 x4: `ReturnType<typeof vi.spyOn>` leaves `mock.calls` untyped,
so each `.map`/`.filter` callback parameter was implicitly `any`.
Annotated `unknown[]`, the form `rest-5xx-status-passthrough.test.ts`
already uses.
Ledger regenerated, not hand-edited: four entries reach zero and are
deleted, `export-integration.test.ts` re-records 17 -> 4. 37 -> 20
errors across 13 -> 9 files. No number is raised.
The remaining 20 are NOT repaired, on purpose: they need a fixture's
data or a producer's signature changed, not an annotation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjujZN219uFzBhSYfMykCd
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/rest/test-typecheck-debt.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/rest/test-typecheck-debt.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 13 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json e2d1f800117c9b62d8d62f77c14682958920c280packageMentionDocs.

@os-litantos-litant added skip-changeset PR has no user-facing published change; bypasses the changeset gate and removed size/s tests labels Aug 27, 2026 — with Claude
@os-litant
os-litant marked this pull request as ready for review August 27, 2026 01:30
@os-litant
os-litant added this pull request to the merge queueAug 27, 2026
Merged via the queue into main with commit cbacc96Aug 27, 2026
46 checks passed
@os-litant
os-litant deleted the claude/issue-12573-rest-test-typecheck-paydown branch August 27, 2026 02:07
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 gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-litant@claude