Repository navigation
Commit c91af8e
test(lint): load the linked @objectstack/spec dist with Node, not vite's transform (#24048)
Fixes #23900
Clause-②: no
## What
`packages/lint`'s vitest now loads the pnpm-linked `@objectstack/spec`
dist with Node instead of inlining it through vite's transform:
- `packages/lint/vitest.config.ts`: one `test.server.deps.external`
entry, `/[\\/]packages[\\/]spec[\\/]dist[\\/]/`, which matches the
module's realpath. Vitest's default `external` covers only node_modules,
and a workspace link's realpath is `packages/spec/dist/...`, so before
this every file whose graph reaches spec inlined about 33 MB of built
`.mjs`. The header now says the config carries two settings and why each
is package-wide.
- `packages/lint/src/vitest-spec-external.test.ts` (new) is the positive
control the card asks for. It checks that the spec module the tests
import (root and `/data`, resolved from `packages/lint` exactly as the
sources resolve it) is the same instance Node's own loader holds. It
loads the ESM entry the `exports` map names with `createRequire` (Node
22's require(esm) shares the ESM loader's module map) and asserts export
identity. When the dist is inlined, vite evaluates its own copy, so the
identity assertions go red.
- The two `// test-budget: 30 — whole-package import` lines on
`lazy-deps.test.ts` and `runtime-lazy-deps.test.ts` are dropped (see the
measurement below).
The import resolves through `exports` to `dist/` either way, so this
changes only who evaluates the dist, never which bytes are under test.
## Mock census (before the change)
`git grep -nE
"vi\.(mock|doMock|hoisted|unmock|importActual|importMock|spyOn)\b" --
packages/lint` at `2b274600b1`: **0** `vi.mock` / `vi.doMock` /
`vi.hoisted` sites. The only hits are two `vi.spyOn(console, ...)`,
which spy on a global and are unaffected. Control leg: the same
`vi.mock(` spelling finds 30 files in `packages/cli/src`, so the zero is
a real reading.
## Positive control: what it proves and how it goes red
Both ablations ran through `scripts/ablation-replace.mjs` on the
committed fix `be2f7c34`, with the anchor hit and the blob change proven
on disk:
| leg | config | `vitest-spec-external.test.ts` |
|---|---|---|
| fix | realpath pattern | 2/2 pass |
| ablation 1 | `external` entry deleted | 2/2 fail, at the identity
assertions (lines 48 and 54), after the `typeof` / `toBeDefined` lines
pass |
| ablation 2 | name-shaped `/@objectstack[\\/]spec/` (the trap
`packages/cli/vitest.config.ts` records) | 2/2 fail, same lines |
Restore proof: the `vitest.config.ts` blob on disk equals HEAD's
(`4ecbe245f449`), and `git diff HEAD` is empty.
## Measurement (paired, same box, under `os-verify-lock.sh`; shared-box
seconds)
| reading | before (`2b274600b1`) | after |
|---|---|---|
| package run, lock hold | 84 s (141 files / 6802 tests, green) | 53 s
at `be2f7c34`, 54 s at `77f016c5` (142 files / 6804 tests, green; +1
file / +2 cases = the control) |
| vitest `transform` / `import` | 23.74 s / 189.81 s | 8.05 s / 96.39 s
|
| `lazy-deps.test.ts` alone, two runs | 15.01 s, 15.19 s | 6.77 s, 6.79
s |
| `runtime-lazy-deps.test.ts` alone, two runs | 14.25 s, 14.63 s | 6.79
s, 6.54 s |
**Budget lines dropped, not re-measured.** Both files now run in 6.5 to
6.8 s alone, under the 10 s `FILE_BUDGET_SECONDS` line. The lines'
stated reason ("vitest's transform of ... every inlined
@objectstack/spec dist bundle") is no longer true. A budget is a CI
reading x 1.25, and no CI reading after the change exists yet to
re-measure from. If an hourly reading later puts either file over 10 s,
that reading is the measurement a re-declaration needs (ruling
`6181973363` item 2).
## Acceptance notes
- `@objectstack/formula` and `@objectstack/sdui-parser` (lint's other
two workspace deps) are still inlined. The card scopes only spec, and
they are not measured here.
- Cost recorded in the config comment: an externalised module cannot be
`vi.mock`ed. A later test that needs to mock spec has to move the entry.
- ⛔ No test deleted, no timeout raised, no move to a slower or skipped
project, no other package's config, no source change.
## Verification
- Head `e0d24934` (patch round): the control now imports `defineStack`
from `@objectstack/spec` and `ObjectSchema` from
`@objectstack/spec/data` by name. The root namespace import broke the
repo's `no-restricted-imports` rule for `@objectstack/spec`. The
identity check is unchanged.
- ESLint over the four changed files, `node --stack-size=4000
node_modules/eslint/bin/eslint.js --no-inline-config ...`: exit 1 on
`77f016c5` (one `no-restricted-imports` error at
`vitest-spec-external.test.ts:29:8`), exit 0 on `e0d24934`.
- Ablation legs re-run on `e0d24934` through
`scripts/ablation-replace.mjs`. With the `external` entry deleted, and
with the name-shaped `/@objectstack[\\/]spec/`, the control is 2/2 red
at `:48:25` and `:54:26` (`Object.is` identity). Restore: the disk blob
equals the HEAD blob `4ecbe245f449`, and `git diff HEAD` is empty.
- `pnpm --filter @objectstack/lint test` at `e0d24934`: 142/142 files,
6804/6804 tests (`VERDICT command-exit 0`, lock held 54 s).
- `pnpm --filter @objectstack/lint typecheck` (including
`check:test-typecheck`) at `e0d24934`: `VERDICT command-exit 0`; the
debt ledger is unchanged (2 files / 6 errors).
- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--ran ...` at `e0d24934`: 51 derived, 50 run with exit 0, 1 NOT-MEASURED
(`pnpm check:dual-build-cjs-loads` exited 3 because it needs a full-repo
build; CI measures it), 0 unrun. Also ran `node
scripts/check-console-intercept-disarm.mjs`: exit 0.
- No publish: `@objectstack/lint`'s `files[]` is `dist`, README,
CHANGELOG. None of the changed text is in the built `dist/` (0 hits),
while a shipped symbol (`validateStackExpressions`) has 8 hits as the
positive control.
Written by the `os-dev` cloud session
`session_019oKRRCxbLy3xARM3CH99sf`, dispatched by `domain:spec` seat 1
(claim `6224227197`).
---
_Generated by [Claude
Code](https://claude.ai/code/session_019oKRRCxbLy3xARM3CH99sf)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 077b75f commit c91af8e
4 files changed
Lines changed: 85 additions & 4 deletions
File tree
- packages/lint
- src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | 2 | | |
4 | 3 | | |
5 | 4 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | 2 | | |
4 | 3 | | |
5 | 4 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
7 | 9 | | |
8 | 10 | | |
9 | 11 | | |
| |||
15 | 17 | | |
16 | 18 | | |
17 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
18 | 45 | | |
19 | 46 | | |
0 commit comments