Skip to content

Commit 43d75ef

Browse files
test(service-datasource): the pool-support and driver-factory suites run under 10 s (two #23184 rows) (#23711)
Refs #23184 (service-datasource rows: datasource-pool-support, default-datasource-driver-factory) Clause-②: no ## Rows answered Both rows of the card's `@objectstack/service-datasource` list: - `src/__tests__/datasource-pool-support.test.ts`, listed at 17.6 s (run `38294929860`); - `src/__tests__/default-datasource-driver-factory.test.ts`, listed at 10.6 s (run `38217670691`). The pin is the next refresh PR's list: it should name neither file. The card stays open for its other rows: the three remaining `plugin-auth` rows (org-create-posture-gate, implicit-account-linking, dev-admin-seed-credential-gate) and the `plugin-security` and `organizations` rows. The diff is tests only: 5 module-top side-effect import lines and their comments in the two test files, +44 / -0. No production file, option, constant, timeout or export changes. Every `it(`, `describe(` and `expect(` line in both files is byte-identical to the base and in the same order. ## Where the time went A probe at the base (temporary, deleted; two runs per file, each in a fresh vitest worker) timed every load the files' cases trigger, in the order they trigger them: | load, in case order | pool-support order | driver-factory order | |:--|--:|--:| | `@objectstack/core`, first load | 8.9 / 7.7 s | 7.1 / 9.5 s | | `@objectstack/driver-sql` (knex) | 1.32 / 0.54 s | 0.57 / 0.80 s | | `@objectstack/driver-memory`, after core | 0.46 / 0.25 s | 0.26 / 0.32 s | | `@objectstack/driver-mongodb`, after core | 0.17 / 0.16 s | 0.14 / 0.24 s | | `@objectstack/driver-sqlite-wasm`, after driver-sql | n/a | 0.04 / 0.04 s | | the behaviour itself: each `create()`, the wasm connect, sync and round trip | 2 to 18 ms each | about 0.1 s first, 10 ms after | So nearly all of each file's clocked wall was one module load. The factory reaches every driver through a lazy `await import()`, and every driver imports `@objectstack/core`. This package's `vitest.config.ts` aliases `@objectstack/core` to `packages/core/src/index.ts`, so the first case to build a real driver paid a cold vite transform of core's whole source graph inside its clocked window. In `datasource-pool-support` that was `memory WITHOUT a pool still builds exactly as before` (8.1 s of the file's 9.3 s). In `default-datasource-driver-factory` it was `builds a file-backed SqliteWasmDriver that connects and round-trips` (11.4 s of 12.4 s). No case waits on a timer, a retry back-off, an idle or acquire timeout, or a live database. Every postgres, mysql and mongodb case builds a driver without connecting. ## What changed Each file now pays that load at module top, in collection, following the AGENTS.md convention that clocked windows measure behaviour, never loading (the clocked-window rule of `check-test-source-alias`). The factory's own lazy imports stay where they are; the module cache hands them the instances already loaded. - `datasource-pool-support.test.ts`: `import '@objectstack/core'` and `import '@objectstack/driver-sql'`. - `default-datasource-driver-factory.test.ts`: the same two, plus `import '@objectstack/driver-sqlite-wasm'`. Three drivers are left out on purpose, and each still loads inside its first case: - `@objectstack/driver-memory` (0.2 to 0.5 s once core is loaded): every module binding of it is a ruled census entry. A first cut that imported it here turned `check:driver-memory-census` red, because a new binding needs a maintainer ruling. - `@objectstack/driver-mongodb` (0.1 to 0.3 s): this package's tests reach it only through the factory, so a test-file import is a new unaliased artifact import. The same first cut turned `check:test-source-alias` red. Aliasing it would change a config file outside this card's surface. - `@objectstack/driver-turso`: the turso missing-package case stages its absence without `vi.resetModules()`, so the factory's own lazy import must be that package's first. The `sqlite-wasm` absence case resets the module registry before it mocks, so loading that package at module top is the same condition the construction suites already created for it. ## Measurements Each figure is vitest's per-file duration (JSON reporter `endTime - startTime`, the module-line duration the refresh reads): `pnpm exec vitest run --maxWorkers=2 FILE --reporter=verbose --reporter=json`, in `packages/services/service-datasource`, under `os-verify-lock`, on a shared 4-vCPU box. The final before and after runs were interleaved at the final head, with the before leg being the base file copied to a temporary name (deleted afterwards), so both legs saw the same load. | file | before, base `f1e21c4f45` alone (load 1.3 to 1.6) | before, interleaved at `a573f9c57a` (load 1.6 to 3.0) | after, interleaved at `a573f9c57a` | median after | |:--|:--|:--|:--|--:| | datasource-pool-support | 9312 / 8973 / 9337 ms | 8967 / 8577 / 8287 ms | 611 / 572 / 704 ms | **0.61 s** | | default-datasource-driver-factory | 12412 / 9129 / 9501 ms | 9082 / 10044 / 9393 ms | 751 / 711 / 750 ms | **0.75 s** | **The load is moved, not removed.** vitest's whole-file `Duration` (collection plus run) is unchanged within noise: pool-support 12.70 / 11.50 / 11.73 s before against 12.05 / 12.18 / 12.38 s after, and driver-factory 12.48 / 13.40 / 13.06 s before against 13.19 / 12.48 / 13.44 s after. The `import` phase grew from about 3 s to about 11 to 12.5 s per file. What the change buys is that no test or hook clock contains a compiler run any more. It does not make the package's test job faster. **CI projection.** The per-file CI captures of recent hourly runs are NOT MEASURED. The `test-core-timing-table` artifact of hourly run `38773780951` redirects to `productionresultssa5.blob.core.windows.net`, which this container's egress proxy refuses (CONNECT 403). The ratios therefore come from the card's own readings against the interleaved before medians: pool-support 17.6 s against 8.58 s is a ratio of 2.05, which projects to **1.25 s**; driver-factory 10.6 s against 9.39 s is 1.13, which projects to **0.85 s**. At a 4.0 ratio, the worst post-landing ratio an earlier slice of this card read, they project to 2.4 s and 3.0 s. ## Proof that every case still runs and still asserts the same - **Case lists:** 72 of 72 and 50 of 50 passed in every run, before and after. - **Static lines:** the `it(` / `it.each(` / `describe(` / `expect(` lines are byte-identical to the base and in order: 72 / 0 / 8 / 177 for pool-support, and 45 / 1 / 10 / 105 for driver-factory. - **Runtime assertions:** a temporary copy of each file recorded `expect.getState().assertionCalls` per case, at the base and at the head. The per-case counts are identical: 210 assertions over 72 cases, and 128 over 50 cases. No case asserts nothing. - **Same module instances (temporary probe, deleted):** with `@objectstack/core`, `@objectstack/driver-sql` and `@objectstack/driver-sqlite-wasm` imported at module top, the factory's `sqlite`, `postgres`, `mysql` and `sqlite-wasm` drivers are each `instanceof` the class the test file imported (4 of 4). The first memory `create()` then took 241 ms, against 8 s with core not yet loaded. - **No mutation is owed.** The change moves where a module load is paid. It changes no tested behaviour, and no case asserts timing, so reverting it reddens nothing. The interleaved before leg is that revert, measured. ## Tests and gates (final head `a573f9c57a`) - `pnpm --filter @objectstack/service-datasource run typecheck`: exit 0. `tsc --listFilesOnly` lists both changed files in the package's program. - The whole `@objectstack/service-datasource` suite with `--maxWorkers=2`: 45 of 45 files, 838 of 838 tests passed. - ESLint on the 2 changed files with `--no-inline-config`: exit 0. The control-byte scan of both files found 0 hits. - `skip-changeset`: the package ships `dist`, `README.md` and `CHANGELOG.md`. The comment marker of this change has 0 hits in its built `dist`, and the positive control `createDefaultDatasourceDriverFactory` has 4. - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 52 commands, the same 52 as the seat's lead. All 52 exit 0 at `a573f9c57a`, each run separately with the exit code captured before any pipe, and `--ran` reports 52 derived, 52 run, 0 NOT-MEASURED and 0 UNRUN. `check:dual-build-cjs-loads` ran after a full `turbo run build` (75 of 75 tasks). A first sweep at the first cut (`ab97ec143f`) had `check:driver-memory-census` and `check:test-source-alias` red, which is what narrowed the import list (above); every other family was green there too. - `check:engine-double-contract` printed its repo-wide census line verbatim: `UNRECOGNISED [engine-double-contract]: 22 construct(s) in packages, examples declare a scanned verb (delete, update, findOne) alongside engine siblings, and this gate could not read the implementation -- so they are in NEITHER the pinned population nor the ledger.` Its output names neither changed file, and this diff adds no construct. - The full lint farm, Test Core, the dogfood jobs and the type-check lanes belong to CI. ## Acceptance notes - **The core transform recurs per file.** About 7 to 9.5 s of cold transform of `@objectstack/core`'s source is paid by every test file in this package whose cases load a driver, once per worker, because the package's vitest config aliases `@objectstack/core` to source. The alias is the intended repair of `check:test-source-alias`, and that gate's header names aliased dependencies as outside its clocked-window population ("widening the population is a different card"), which is also why the gate was green over these two files at `69351e985a` (measured, exit 0). This is an observation, not a defect, and no carrier is named. - **A stale reading in `vitest.config.ts`.** The config's `testTimeout` comment cites `sqlite WITHOUT a pool` as about 1.1 s idle, paying the driver-sql import. After this change that case runs in 28 to 43 ms. The 60 s timeout itself is untouched (no timeout was raised or lowered), and the comment is outside this card's surface. Noted, not filed. - The per-file CI captures cannot be read from a cloud container (blob-storage egress is refused), as the previous slice also recorded. This is an environment fact, not a repo defect. --- _Generated by [Claude Code](https://claude.ai/code/session_017WLmd5in9RXu7AjyHR8fKQ)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 53e3638 commit 43d75ef

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

‎packages/services/service-datasource/src/__tests__/datasource-pool-support.test.ts‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ import {
6565
import { DatasourceAdminService, type StoredDatasource } from '../datasource-admin-service.js';
6666
import type { IDatasourceDriverFactory } from '../contracts/datasource-driver-factory.js';
6767
import type { IDataDriver } from '@objectstack/spec/contracts';
68+
// [#23184] The first load of what the drivers stand on is paid HERE, at module
69+
// load, and not inside the first clocked case: clocked windows measure
70+
// behaviour, never loading (AGENTS.md, Build & Test; the clocked-window rule of
71+
// `check-test-source-alias`). The factory reaches every driver through a lazy
72+
// `await import()`, and every driver imports `@objectstack/core`, which this
73+
// package's vitest config aliases to its SOURCE. So the first `create()` to get
74+
// past the pool gate (`memory WITHOUT a pool`) used to pay a cold transform of
75+
// core's whole module graph: 7-9 s of this file's ~9 s of clocked wall on a
76+
// 4 vCPU dev container, against milliseconds of construction. `driver-sql`
77+
// (knex; the `sqlite`, `postgres` and `mysql` arms) is the next 0.5-1.3 s.
78+
// The module cache hands the drivers these same instances, so nothing a case
79+
// runs is different. Two drivers are deliberately NOT listed and still load in
80+
// their first case (0.2-0.5 s each once core is loaded): `driver-memory`,
81+
// whose every module binding is a ruled census entry
82+
// (`check:driver-memory-census`), and `driver-mongodb`, which this package's
83+
// tests resolve through `dist/` only from the factory, so a test-file import
84+
// would be a new unaliased artifact import (`check:test-source-alias`).
85+
import '@objectstack/core';
86+
import '@objectstack/driver-sql';
6887

6988
describe('#5714 — which driver arms read a declared `pool`', () => {
7089
it('names the two sqlite arms, `memory` and `turso` as unable to honour it (#5931 / #7243)', () => {

‎packages/services/service-datasource/src/__tests__/default-datasource-driver-factory.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,31 @@ import {
2323
} from '../default-datasource-driver-factory.js';
2424
import { isUnbuiltWorkspaceFailure } from '../connect-failure-remedy.js';
2525
import { MissingDriverPackageError } from '../missing-driver-package-error.js';
26+
// [#23184] The first load of what the drivers stand on is paid HERE, at module
27+
// load, and not inside the first clocked case: clocked windows measure
28+
// behaviour, never loading (AGENTS.md, Build & Test; the clocked-window rule of
29+
// `check-test-source-alias`). The factory reaches every driver through a lazy
30+
// `await import()`, and every driver imports `@objectstack/core`, which this
31+
// package's vitest config aliases to its SOURCE. So the first case to build a
32+
// real driver (the file-backed `sqlite-wasm` round trip) used to pay a cold
33+
// transform of core's whole module graph: 7-9 s of this file's ~9.5 s of
34+
// clocked wall on a 4 vCPU dev container, against about 0.1 s of round trip.
35+
// `driver-sql` (knex, which `driver-sqlite-wasm` builds on) is the next
36+
// 0.5-1.3 s. The module cache hands the drivers these same instances, so
37+
// nothing a case runs is different. Three drivers are deliberately NOT listed:
38+
// `driver-memory`, whose every module binding is a ruled census entry
39+
// (`check:driver-memory-census`), and `driver-mongodb`, which this package's
40+
// tests resolve through `dist/` only from the factory, so a test-file import
41+
// would be a new unaliased artifact import (`check:test-source-alias`); each
42+
// still loads in its first case (0.2-0.5 s once core is loaded). And ⛔
43+
// `driver-turso`, because the turso missing-package case below stages its
44+
// absence WITHOUT `vi.resetModules()`, so the factory's own lazy import must be
45+
// that package's first. The `sqlite-wasm` absence case resets the module
46+
// registry before it mocks, so loading that package here first is the same
47+
// condition the construction suites already created for it.
48+
import '@objectstack/core';
49+
import '@objectstack/driver-sql';
50+
import '@objectstack/driver-sqlite-wasm';
2651

2752
const factory = () => createDefaultDatasourceDriverFactory({ dev: false });
2853

0 commit comments

Comments
 (0)