Skip to content

test(rest): bind exceljs through the typed loadExcelJs() in the import-integration suite - #13498

Merged
os-trump merged 2 commits into
mainfrom
claude/issue-13453-import-integration-exceljs-typing
Aug 30, 2026
Merged

test(rest): bind exceljs through the typed loadExcelJs() in the import-integration suite#13498
os-trump merged 2 commits into
mainfrom
claude/issue-13453-import-integration-exceljs-typing

Conversation

@os-trump

Copy link
Copy Markdown
Collaborator

Fixes #13453

The two fixture builders in packages/rest/src/import-integration.test.ts bound exceljs
as const ExcelJS: any = ..., 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 route were themselves unchecked against the
dependency they drive.

Both now call loadExcelJs() from src/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:

control reading note
grep -rn "const ExcelJS: any" --include=*.ts packages/rest/src before 3 see the correction below
the same grep after 1 the surviving hit is prose, not a binding
grep -rn "loadExcelJs" --include=*.ts packages/rest/src 11 non-zero, so the accessor exists in the tree measured

Correction 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 quotes
the 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, at
lines 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 the
assignment), 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 any side must red nothing. The zero is the whole point; a
green typecheck alone would prove nothing here.

Mutation: wb.xlsx.writeBuffer() to wb.xlsx.writeBuffre(), both sites, applied to the
same file in both legs.

Leg A — the typed code (this PR):

src/import-integration.test.ts(332,31): error TS2551: Property 'writeBuffre' does not exist on type 'Xlsx'. Did you mean 'writeBuffer'?
src/import-integration.test.ts(354,31): error TS2551: Property 'writeBuffre' does not exist on type 'Xlsx'. Did you mean 'writeBuffer'?

Total test-layer errors 4 to 6; errors in this file 0 to 2.

Leg B — the pre-change any code, identical mutation:

Total test-layer errors stayed at 4; errors in this file 0; the string writeBuffre
appears 0 times in the whole tsc output. The typo is invisible to the compiler on the
any side, which is exactly the defect this card records.

Blob hashes, proving both mutations and both restores on disk:

step blob
HEAD (typed) 08a02f015e10b6f8b65103933540f8a4247c26b8
leg A mutated 923b9ed16ac1ee3f58bf1727d75a6b174a1a0390
after restore A 08a02f015e10b6f8b65103933540f8a4247c26b8
pre-change base blob 927511e911f248458e78f1a8901f2d0c9e979a65
leg B mutated 30b4ef46a589f9451cae595dea23f27857658434
after restore B 08a02f015e10b6f8b65103933540f8a4247c26b8

Both legs ran from a committed restore point, under trap ... EXIT INT TERM with absolute
paths, and each ended on empty git diff HEAD and empty git status --porcelain. Neither
leg was judged by exit code. No rebuild was required and none is claimed: --listFiles
shows 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's typecheck runs tsc --noEmit and check:test-typecheck against
tsconfig.test.json, so the test layer really is compiled. Confirmed rather than assumed
via --listFiles: import-integration.test.ts is in the program (1), xlsx-module.ts is
in the program (1), and exceljs's index.d.ts is in the program (1), out of 504 files.

The debt ledger did not move

packages/rest/test-typecheck-debt.json is untouched by this PR — the diff is 1 file and
it is not that one. origin/main was fetched and merged into this branch before any
gate 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:

check:test-typecheck: OK — @objectstack/rest's test layer compiles under packages/rest/tsconfig.test.json; 1 file(s) / 2 error(s) held in test-typecheck-debt.json (shrink-only)

Changeset judgement — measured, not by analogy

Built the workspace closure, then grepped the emitted artifacts with a positive control:

symbol hits in dist/index.js + dist/index.cjs
RestServer (positive control) 73
loadExcelJs 6
from-named-sheet (unique to the changed file) 0
import-integration 0
real engine + protocol integration 0

0 in both sourcemaps too. This diff is test-layer only and reaches dist zero times,
so it takes skip-changeset — the same reading PR #13425's test-layer helper earned on
a dist grep of 0, and the opposite of PR #13452, whose production accessor reached dist
and earned a patch. loadExcelJs scoring 6 is that accessor, which this PR does not
change.

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's
own stderr names the tree it answered for — commit af3b19ada0, repo assertion
objectstack-ai/objectstack checked against this checkout's origin and holding. Change
set: 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-only
  • check-type-check-coverage --re-measure: OK — 29 ledger entries re-measured, 1547 raw tsc errors, none above its recorded number
  • check:dual-build-cjs-loads — 102 published require entry points across 66 packages load; 610 emitted CommonJS files parse
  • check-nul-bytes: OK — 7453 text files, no raw ASCII control bytes
  • check: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 0
  • 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 — all exit 0

Recorded separately, NOT folded into the green list — refusals, read as NOT MEASURED:

  • check-test-completenessPREREQUISITE NOT MET: it grades a saved turbo run test
    log 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:

Test Files  2 passed (2)
     Tests  36 passed (36)

with both target tests named individually under the verbose reporter:

✓ parses a native xlsx workbook server-side and coerces cells like csv 278ms
✓ reads xlsxBase64 without an explicit format and honors the sheet selector 36ms

Behaviour does not move; only what tsc is told.

Generated by Claude Code


Generated by Claude Code

claude added 2 commits August 30, 2026 14:22
…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
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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
  • 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 — 0 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 3800e42932cd4b78a403df8b8107661ac494db97packageMentionDocs.

@github-actions github-actions Bot added the tests label Aug 30, 2026
@os-trump os-trump added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 30, 2026 — with Claude
@os-trump
os-trump marked this pull request as ready for review August 30, 2026 15:17
@os-trump
os-trump enabled auto-merge August 30, 2026 15:18
@os-trump
os-trump added this pull request to the merge queue Aug 30, 2026
Merged via the queue into main with commit bcef1cf Aug 30, 2026
37 checks passed
@os-trump
os-trump deleted the claude/issue-13453-import-integration-exceljs-typing branch August 30, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants