test(rest): pay down the one annotation-reachable error of rest.test.ts's four, and measure the other three - #13380
Conversation
…e-record the ledger The `@objectstack/rest` test-layer ledger held 4 errors for `src/rest.test.ts`, fenced until PR #12421 landed. Measured, exactly one of the four is reachable by an annotation-only repair: src/rest.test.ts(5,24) TS6133 'RouteGroupBuilder' is declared but its value is never read src/rest.test.ts(1267,26) TS2345 Buffer<ArrayBuffer> vs exceljs' own module-local Buffer src/rest.test.ts(2064,7) TS2345 request literal missing IHttpRequest's headers/method/path src/rest.test.ts(2089,7) TS2345 request literal missing IHttpRequest's headers/method/path Only the TS6133 is repaired here: the import specifier is unused (one occurrence in the file, the import itself; `RouteManager` beside it has 13). Removing it changes no emitted JavaScript. The other three are stopped and reported, not forced. The two TS2345 request literals are the same class as the two already out of scope on this card — they need the fixture's data, not its annotation, and the durable answer is a typed IHttpRequest builder. The exceljs one is a third-party declaration defect and its only in-repo answer today is `as any`, which this card forbids. Ledger regenerated with `pnpm --filter @objectstack/rest gen:test-typecheck-debt`, never hand-edited: src/rest.test.ts 4 -> 3, both other entries byte-identical, no number raised, no entry reached zero so none was deleted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvqBFLRzXdSPcbusDoED9k
📓 Docs Drift Check
What this run could not see
Coarse fallback — 13 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
PM 复核:范围与纪律都对。已 undraft,
|
…ch remaining entry The entries left in `@objectstack/rest`'s test-typecheck ledger are not annotation repairs, and two rounds on this ledger have now each had to re-measure that fact from scratch before learning it. `_note` is the field built for exactly this: unlike the generated `_comment`, it is authored, preserved verbatim, and never written by the generator. Written as card pointers rather than as readings — no TS codes, no line numbers, no counts. Those are the parts that go stale, they already live on the cards and in the PR that measured them, and a pointer expires only when the card it names closes, by which time the ledger entry is gone too. Verified rather than assumed, since preservation is the whole premise: regenerating with `pnpm --filter @objectstack/rest gen:test-typecheck-debt` leaves the file byte-identical (sha256 c88a74929f880fa55ea838c8ec8b1021ef 559a4ebf88aa0930454c30321a0e33 before and after) — `_note` unchanged, entries unchanged, `_comment` rewritten identically. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvqBFLRzXdSPcbusDoED9k
…st-test-typecheck-paydown
Part of #12573
Part of, deliberately, not a closing keyword. This pays down 1 of the 4 errors this tranche was dispatched for. The card outlives it: 5 errors remain inpackages/rest's test-layer ledger and every one of them is stopped on a reported reason, not on effort.What the four actually were — measured, because nobody had recorded it
The card's 08-27 record noted only that
src/rest.test.tswas fenced by PR #12421. Its error classes had never been measured. The fence released when #12421 merged as3519f8d11f, so the first action here was to measure, not to repair:src/rest.test.ts(5,24)TS6133RouteGroupBuilderimported and never readsrc/rest.test.ts(1267,26)TS2345Bufferdeclarationsrc/rest.test.ts(2064,7)TS2345headers/method/pathsrc/rest.test.ts(2089,7)TS2345headers/method/path⭐ The measurement is the load-bearing part of this PR, and it changes the card's shape. Errors 3 and 4 are the same class the card already ruled out of scope — request literals needing a fixture's data, not its annotation. The card assumed that class had 2 members; it has 4. Both of the newly measured ones are missing
methodas well asheadersandpath.The one repair
RouteGroupBuilderoccurs exactly once in the file — the import specifier itself. Positive control:RouteManager, imported on the same line, occurs 13 times.⭐ The module is still imported for
RouteManager, so this removes a binding and nothing else — no emitted JavaScript changes, and no test's behaviour can move.Why the other three were stopped rather than forced
⛔ Each has a repair, and each repair is one the card's own fences forbid:
exceljs@4.4.0'sindex.d.tsline 1 declaresinterface Buffer extends ArrayBuffer { }. That file has 106 top-levelexportdeclarations, so it is a module and the declaration is module-local: it shadows Node'sBufferinside every exceljs signature. No NodeBuffervalue is assignable toWorkbook.xlsx.load. The package's own green form isas any, at 6 of its 8xlsx.load(sites — andas anyis forbidden here. The only alternative that typechecks passes a genuineArrayBuffer, which changes the argument at runtime. Filed as exceljs 4.4.0 ships its own module-localBufferinterface, so no Node Buffer can be passed toWorkbook.xlsx.load— 6 sites pay it withas any, the 7th is a ledgered error #13378.IHttpRequest) — supplyingheaders,methodandpathchanges what the handler receives. That is the fixture's data, and the card's ruling is to stop and report. Filed as A typed IHttpRequest test builder — 4 ledgered TS2345 in packages/rest are hand-built request literals, and the only in-repo alternative isas any#13377, which now carries all four sites of that class rather than the two previously known.The ledger
Regenerated with the repo's own tool, never hand-edited:
"src/meta-public-book-grant.test.ts": 1, "src/rest-batch-size-cap.test.ts": 1, - "src/rest.test.ts": 4 + "src/rest.test.ts": 3⭐ The regenerated diff moved only where the work was: both untouched entries are byte-identical, no number was raised, and no file reached zero, so no entry needed deleting.
The authored
_note(second commit)The ledger now carries an authored
_noterecording which card holds each remaining entry. Two rounds on this ledger have each had to re-measure that from scratch first;_noteis the field built for exactly this — unlike the generated_comment, it is authored, preserved verbatim, and never written by the generator.⭐ Written as card pointers, not readings — no TS codes, no line numbers, no counts. Those are the parts that go stale, they already live on the cards and in this PR body, and a pointer expires only when the card it names closes, by which time the ledger entry is gone too.
⭐ Preservation was measured, not assumed — it is the whole premise of the change. Regenerating leaves the file byte-identical: sha256
c88a74929f880fa55ea838c8ec8b1021ef559a4ebf88aa0930454c30321a0e33before and after,_notesha256 unchanged at1912fab68c59d2f723e3217a1bdcf597215db03fcc01605bac6c1d911c126d8a,entriesunchanged,_commentrewritten identically.Verification — all re-run on the merged head
07e46107a5, tree clean, local == remoteorigin/mainbefore the final verification round, and that mattered:dispatch-gates.mjsrefused to be trusted on the pre-merge tree, reportingSTALE TREE — this answer is derived from a tree at least 11 commit(s) behind origin/main, and 11 file(s) it derives from CHANGED across that range ... a well-formed answer about a tree nobody is on. Re-deriving after the merge surfaced one family the stale run missed —check:doc-authoring, which landed in #13355 earlier the same day. Every verdict below is from the post-merge run; exit codes captured before any pipe.pnpm --filter @objectstack/rest typecheck, exit 0:Its self-test also pins the mechanism this PR relies on: "the finding(tooling): every generated test-typecheck ledger states a cause that #5543 fixed 18 days ago, and
--updateoverwrites any correction written into the file #12624 ledger-prose pins ... preserves an authored_noteverbatim in its own key".pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2, VERDICTcommand-exit 0:Test Files 159 passed (159)·Tests 2671 passed (2671). ⭐ A type-only repair must not move behaviour, and none moved.Anti-vacuity —
tsc -p tsconfig.test.json --noEmit --listFilesputs 159packages/resttest files in the program,src/rest.test.tsamong them. The repair was measured, not merely unopposed.pnpm lint(eslint . --no-inline-config, repo-wide, not narrowed), VERDICTcommand-exit 0, no findings.pnpm check:type-check-debt --re-measureon the fully built closure (turbo run build, 70/70 successful):pnpm check:dual-build-cjs-loads: "102 published require entry point(s) across 66 package(s) load; 610 emitted CommonJS file(s) parse".Reverse verification — direction predicted first, then measured
Prediction, recorded before running: the ledger records
src/rest.test.ts: 3; reintroducing the repairedTS6133makes the file measure 4, so the EXACT ratchet must exit non-zero with a gained-errors verdict naming that file — not a silent pass, and not a "shrank" verdict.Observed, exactly that. Gate exit 1, and its own line:
Mutation and restore were both proven on disk, never by exit code — the repair was committed first, so
HEADwas a real restore point, and the script ran undertrap ... EXIT INT TERMwith absolute paths:== HEADblob4e2fe9ae11cfb3aa7b9424d7146c8f4432afd0a05e9b6fc37850f420a744b0a59bc096d11ac1269bgit checkout HEAD --(never bare)4e2fe9ae11cfb3aa7b9424d7146c8f4432afd0a0Restore proven by blob equality with the
HEADblob, plus an emptygit diff HEADand a cleangit status --porcelain.Gates
Union derived from the real change set by
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackon the merged tree — the script derived its own change set (still exactly the two paths below), provenance line confirmedobjectstack-ai/objectstackat07e46107a5, and the--repoassertion held against this checkout'sorigin.All matched families plus the convention-triggered ones ran, all exit 0:
check:cross-package-test-inputs·check:dispatcher-error-vocabulary·check:doc-authoring·check:dual-build-cjs-loads·check:logger-receiver-detach·check:objectql-double-limit·check:page-declaration-shape·check:published-files·check:slot-lookup·check:test-source-alias·check:type-source-resolution·check:where-matcher·check-ci-filter-parity·check-comment-mask-adoption·check-cross-package-test-inputs·check-keyed-text-bounds·check-plugin-teardown-shape·check-shard-attestation·check-undeclared-dep-imports·check-affected-docs·check-drift-comment·check:query-options-erasure·check:type-check-coverage·check:engine-double-contract·check:nul-bytes·check:type-check-debt --re-measure.node scripts/check-test-completeness.mjs. Run with no argument it exits 3 and says so itself: "There is no local log to hand it, so the local reading for this gate is NOT MEASURED. ⛔ It is not a red, and there is nothing here to fix." It needs a savedturbo run testlog, which only CI has.Changeset: none, and
skip-changesetis the right answer rather than the convenient oneReasoned from the rule, measured rather than recalled:
packages/rest'spackage.jsonpublishesfiles: ["dist", "README.md", "CHANGELOG.md"]. This PR touches exactly two paths —packages/rest/src/rest.test.ts(a test source, excluded from the build config, so it never reachesdist) andpackages/rest/test-typecheck-debt.json(a gate ledger, not a published file). ⇒ nothing published moves, so there is no user-visible change to describe.⛔ An empty-frontmatter changeset would be the wrong answer here, not an equivalent one:
scripts/check-empty-changeset.mjsdocuments that such a file is a real input to the changesets action and buys nothing the label does not.Generated by Claude Code