test(rest): bind exceljs through the typed loadExcelJs() in the import-integration suite - #13498
Merged
os-trump merged 2 commits intoAug 30, 2026
Merged
Conversation
…t-integration suite
The two fixture builders in `import-integration.test.ts` bound exceljs as
`const ExcelJS: any = (await import('exceljs')).default ?? (await import('exceljs'))`,
so every `new ExcelJS.Workbook()`, `addWorksheet`, `addRow` and
`wb.xlsx.writeBuffer()` downstream of them sat outside the type system. The two
tests that exercise the server-side .xlsx import path were themselves unchecked
against the dependency they drive: a renamed method or a changed arity in
exceljs would not have been a compile error here.
Both now call `loadExcelJs()` from `src/xlsx-module.ts`, the package's single
typed, lazily-loaded exceljs binding. No second accessor is introduced and no
runtime behaviour changes — only what tsc is told.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvqBFLRzXdSPcbusDoED9k
…port-integration-exceljs-typing
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-trump
marked this pull request as ready for review
August 30, 2026 15:17
os-trump
enabled auto-merge
August 30, 2026 15:18
os-trump
deleted the
claude/issue-13453-import-integration-exceljs-typing
branch
August 30, 2026 15:43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #13453
The two fixture builders in
packages/rest/src/import-integration.test.tsbound exceljsas
const ExcelJS: any = ..., so everynew ExcelJS.Workbook(),addWorksheet,addRowand
wb.xlsx.writeBuffer()downstream of them sat outside the type system. The two teststhat exercise the server-side .xlsx import route were themselves unchecked against the
dependency they drive.
Both now call
loadExcelJs()fromsrc/xlsx-module.ts— the package's single typed,lazily-loaded exceljs binding, landed by PR #13452. No second accessor is introduced. The
whole diff is 1 file, +3/-2: one import line and two binding lines.
The two grep controls the card wrote for itself
Measured on this branch:
grep -rn "const ExcelJS: any" --include=*.ts packages/rest/srcbeforegrep -rn "loadExcelJs" --include=*.ts packages/rest/srcCorrection to the expected reading: the first control reports 3, not 2
The card and the dispatch both predicted exactly 2 after PR #13452 landed, and treated
any other number as instrument failure. The measured number is 3. The third hit is not
a third binding — it is
src/xlsx-module.ts:9, where the accessor's own header quotesthe old shape while explaining the defect it exists to remove.
So the grep as written is not a clean instrument: it counts a prose mention of the pattern
alongside real bindings, and it will keep reporting 1 forever. The card's underlying claim
was correct — there were exactly 2 bindings, both in
import-integration.test.ts, atlines 325 and 347 exactly as stated. Both line numbers re-verified rather than
trusted. A binding-only control is
grep -rn "const ExcelJS: any = " ...(with theassignment), which reads 2 before and 0 after.
Reverse verification — the load-bearing measurement
Direction predicted before running: the typed side must go red, and the identical
mutation on the pre-change
anyside must red nothing. The zero is the whole point; agreen typecheck alone would prove nothing here.
Mutation:
wb.xlsx.writeBuffer()towb.xlsx.writeBuffre(), both sites, applied to thesame file in both legs.
Leg A — the typed code (this PR):
Total test-layer errors 4 to 6; errors in this file 0 to 2.
Leg B — the pre-change
anycode, identical mutation:Total test-layer errors stayed at 4; errors in this file 0; the string
writeBuffreappears 0 times in the whole tsc output. The typo is invisible to the compiler on the
anyside, which is exactly the defect this card records.Blob hashes, proving both mutations and both restores on disk:
08a02f015e10b6f8b65103933540f8a4247c26b8923b9ed16ac1ee3f58bf1727d75a6b174a1a039008a02f015e10b6f8b65103933540f8a4247c26b8927511e911f248458e78f1a8901f2d0c9e979a6530b4ef46a589f9451cae595dea23f2785765843408a02f015e10b6f8b65103933540f8a4247c26b8Both legs ran from a committed restore point, under
trap ... EXIT INT TERMwith absolutepaths, and each ended on empty
git diff HEADand emptygit status --porcelain. Neitherleg was judged by exit code. No rebuild was required and none is claimed:
--listFilesshows the specifier resolves to
packages/rest/src/xlsx-module.ts(source, same package),not to any
dist, so no build artifact sits between the mutation and the reading.The "not measured" control
packages/rest'stypecheckrunstsc --noEmitandcheck:test-typecheckagainsttsconfig.test.json, so the test layer really is compiled. Confirmed rather than assumedvia
--listFiles:import-integration.test.tsis in the program (1),xlsx-module.tsisin the program (1), and exceljs's
index.d.tsis in the program (1), out of 504 files.The debt ledger did not move
packages/rest/test-typecheck-debt.jsonis untouched by this PR — the diff is 1 file andit is not that one.
origin/mainwas fetched and merged into this branch before anygate derivation, which brought PR #13466 in; the ledger moved from 3 files / 4 errors to 1
file / 2 errors as part of that merge, not by anything here, and no regeneration was
run. Verdict at the pushed commit:
Changeset judgement — measured, not by analogy
Built the workspace closure, then grepped the emitted artifacts with a positive control:
dist/index.js+dist/index.cjsRestServer(positive control)loadExcelJsfrom-named-sheet(unique to the changed file)import-integrationreal engine + protocol integration0 in both sourcemaps too. This diff is test-layer only and reaches
distzero times,so it takes
skip-changeset— the same reading PR #13425's test-layer helper earned ona dist grep of 0, and the opposite of PR #13452, whose production accessor reached
distand earned a patch.
loadExcelJsscoring 6 is that accessor, which this PR does notchange.
Gates
Union derived after the merge, with the staleness reading taken beside it rather than
relying on the banner:
git rev-list --count HEAD..origin/main= 0, and the script'sown stderr names the tree it answered for — commit
af3b19ada0, repo assertionobjectstack-ai/objectstackchecked against this checkout'soriginand holding. Changeset: 1 path.
Green, each quoted from the gate's own verdict line (exit codes captured before any pipe):
check:test-typecheck: OK— 1 file / 2 errors held, shrink-onlycheck-type-check-coverage --re-measure: OK— 29 ledger entries re-measured, 1547 raw tsc errors, none above its recorded numbercheck:dual-build-cjs-loads— 102 published require entry points across 66 packages load; 610 emitted CommonJS files parsecheck-nul-bytes: OK— 7453 text files, no raw ASCII control bytescheck:cross-package-test-inputs,check:dispatcher-error-vocabulary,check:doc-authoring,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:query-options-erasure,check:engine-double-contract,check:type-check-coverage— all exit 0check-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— all exit 0Recorded separately, NOT folded into the green list — refusals, read as NOT MEASURED:
check-test-completeness—PREREQUISITE NOT MET: it grades a savedturbo run testlog and none was named. Its own text says the local reading is NOT MEASURED and that
this is not a red. CI tees the log and passes the path, so CI behaviour is unaffected.
Tests, at the pushed commit
af3b19ada0:with both target tests named individually under the verbose reporter:
Behaviour does not move; only what tsc is told.
Generated by Claude Code
Generated by Claude Code