Skip to content

finding(tooling): every generated test-typecheck ledger states a cause that #5543 fixed 18 days ago, and --update overwrites any correction written into the file #12624

Description

@os-litant

Filed unassigned and ungraded while paying down packages/rest's test-typecheck ledger (part of #12573). ⛔ Not graded, not routed. Measured on origin/main @ 527e0505d.

The fact

scripts/check-test-typecheck.mts:107 builds the _comment every ledger carries, interpolating the package name into an otherwise fixed string:

const LEDGER_COMMENT =
  `Per-file tsc error debt of the ${PKG_NAME} TEST layer (#5286). ` +
  // …
  'and every file below still carries errors from before that gate existed, ' +
  'almost all of them fixture literals annotated with a schema OUTPUT type (`z.infer`) while holding ' +
  'an authored INPUT literal. EXACT ratchet, …';

Two things follow, and the second is what makes the first hard to notice.

1 · The stated cause is a fossil

That clause is the finding from #5478 / #5543: registerObject's schema parameter was annotated ServiceObject (the z.infer OUTPUT type) instead of ServiceObjectInput, so legal authored literals raised TS2740. #5543 was closed as completed on 2026-08-08 by PR #6786, which dropped the 135 as any that had been dodging it.

packages/rest's ledger was created 18 days later, by PR #12570 on 2026-08-26 — and was stamped with the fixed cause as though it were present tense.

Measured against the ledger's own 12 non-fenced files:

z.infer occurrences: 0 0 0 0 0 0 0 0 0 0 0 0      (all 12 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. The 37 errors that ledger actually recorded are four unrelated stories, none of them the named one:

class count what it really is
TS2554 14 registry.registerObject(x) missing the required packageId — see #12623
TS18048 13 getRoutes().find() is Route | undefined
TS2345 5 request literals missing IHttpRequest's required headers / path
TS7006 4 untyped mock.calls callback parameters
TS6133 1 an unused import

⚠️ I measured this for packages/rest only. packages/spec's 55 entries were not checked against the claim — for that package the clause may well still be accurate, since #5478 is where the wording came from.

2 · The ledger cannot correct itself

check-test-typecheck.mts:258 rebuilds the object from the constant on every --update:

const ledger: Ledger = { _comment: LEDGER_COMMENT, entries };

So a corrected _comment written into test-typecheck-debt.json survives exactly until the next gen:test-typecheck-debt — which the ratchet requires a dev to run on every repair (a file that loses errors is red until its number is re-recorded). I hit this directly: corrected the prose, re-ran the regenerator, and the refuted claim came back. The one workflow that guarantees the ledger's numbers are honest also guarantees its stated cause cannot be.

Why it is worth fixing rather than shrugging at

The _comment is the first thing a dev picking up a paydown card reads, and it is load-bearing: #12573's dispatch made "test the ledger's own hypothesis before repairing anything" its first ruling precisely because a wrong cause sends the reader file-by-file down the wrong shape. Here it also points at a resolved issue, so a reader who follows it finds a closed card and no obvious next step.

packages/client's ledger is the sharpest case — 0 entries, and it still asserts a cause for the debt it does not have.

Three ledgers carry the identical clause today:

packages/client/test-typecheck-debt.json   claim present | entries: 0
packages/rest/test-typecheck-debt.json     claim present | entries: 9
packages/spec/test-typecheck-debt.json     claim present | entries: 55

Options

  • A. Drop the causal clause from LEDGER_COMMENT entirely. The mechanism sentences (EXACT ratchet, the three red directions, the regenerate command) are the part that is true for every package; the cause never was.
  • B. Keep a causal note but make it per-package — read from the ledger file's existing _comment when one is present, so a package can record what its own debt actually is and a regeneration preserves it.
  • C. Leave it and rely on readers distrusting it. ⛔ Not recommended: the regenerator actively restores it over corrections.

No urgency claimed — no gate reads _comment, so nothing is red and nothing regresses. This is about the prose the ratchet hands its next reader.

Re-check

sed -n '107,116p' scripts/check-test-typecheck.mts
sed -n '255,260p' scripts/check-test-typecheck.mts
for f in packages/*/test-typecheck-debt.json; do echo "$f"; done

Refs

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions