From e4409fcac06d4a5140fe7a8fb8cb9d30d9424163 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 19:39:03 +0000 Subject: [PATCH 1/2] test(organizations): the two upload-wall files pay their boot's first load at module scope Both storage-upload wall files boot the same walled stack in beforeAll, and the first bootStack in a process is 2.3 to 2.8 s slower than every later one: lazily imported drivers and better-auth entries, sql.js's WASM compile. A new test-only helper boots a throwaway app on the same composition, under the same two environment variables, at module scope, so that cost is paid during collection rather than in the clocked hook. Claude-Session: https://claude.ai/code/session_017WLmd5in9RXu7AjyHR8fKQ Co-authored-by: Claude --- .../__tests__/upload-wall-warm-up.testkit.ts | 99 +++++++++++++++++++ ...storage-upload-door-ownership.wall.test.ts | 7 ++ ...ge-upload-organization-change.wall.test.ts | 7 ++ 3 files changed, 113 insertions(+) create mode 100644 packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts diff --git a/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts b/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts new file mode 100644 index 00000000000..2352cac8ac6 --- /dev/null +++ b/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts @@ -0,0 +1,99 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Test scaffolding for the two `storage-upload-*.wall.test.ts` files: each pays + * its booted wall's FIRST load at module scope, with + * `await warmUpUploadWallBoot()`, never inside a clocked window. + * + * The convention is the repo's: "clocked windows measure behaviour, never + * loading — a test that boots a real plugin chain pays its first load at + * module top" (AGENTS.md, Build & Test). vitest clocks a file's hooks and test + * bodies and reports their sum as the file's duration — the module line the + * hourly timing table reads — while the module's own evaluation runs during + * COLLECTION, which no clock covers. + * + * Why these files need it: both boot the same walled stack in their + * `beforeAll`, and the first `bootStack` in a process is 2.3 to 2.8 s slower + * than every later one (measured per boot, 4 vCPU: 3.2 to 3.8 s against 0.9 to + * 1.2 s). The difference is first use, not the boot: the default datasource's + * driver and better-auth's entries are `import()`ed lazily from inside the + * boot, sql.js compiles its WASM, and every path runs cold. Without this, that + * cost lands in the `beforeAll`, and the timing table charges it to the file. + * + * It is `@objectstack/verify`'s `warmUpBoot` (`boot-warm-up.testkit.ts`, which + * that package does not export) with this package's boot: the same two plugins + * the files mount, under the same two environment variables, set before the + * boot and restored after it. So the lazily loaded code is loaded under the + * environment the files' own boots load it under, and a module that reads its + * environment once, when it is first loaded, reads the same values either way. + * + * ⛔ It shares nothing a case asserts on. It boots an app of its own (no + * objects), on its own in-memory database and its own storage root, with + * plugin instances of its own, and stops it before the file's first hook runs. + * What stays warm is process-level: the module registry, sql.js's compiled + * WASM and the JIT. + * + * ⛔ Call it at module scope, on a line of its own, never in a hook: vitest + * clocks a hook with `hookTimeout` exactly as it clocks a test with + * `testTimeout`. And never answer a recurrence by raising a timeout. + */ + +import { mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { bootStack } from '@objectstack/verify'; +import { StorageServicePlugin } from '@objectstack/service-storage'; +import { OrganizationsPlugin } from '../organizations-plugin.js'; + +/** The environment both files' `beforeAll` sets before its boot. */ +const WALLED_BOOT_ENV = [ + ['OS_TENANCY_POSTURE', 'isolated'], + ['OS_AUTH_MEMBERSHIP_POLICY', 'invite-only'], +] as const; + +/** + * Boot a throwaway app on the walled stack the upload-wall files boot, sign + * the seeded admin in, sign one member up, and stop. + */ +export async function warmUpUploadWallBoot(): Promise { + const restoreEnv: Array<[string, string | undefined]> = []; + for (const [name, value] of WALLED_BOOT_ENV) { + restoreEnv.push([name, process.env[name]]); + process.env[name] = value; + } + const rootDir = mkdtempSync(join(tmpdir(), 'upload-wall-warm-up-')); + try { + // A fresh configuration object per call: `bootStack`'s instance rule keys + // on identity, and nothing here may be shared with the file's own boot. + const stack = await bootStack( + { + manifest: { + id: 'com.example.uploadwallwarmup', + namespace: 'uploadwallwarmup', + version: '0.0.1', + type: 'app', + name: 'Upload Wall Warm-up', + }, + objects: [], + } as never, + { + extraPlugins: [ + new OrganizationsPlugin(), + new StorageServicePlugin({ adapter: 'local', local: { rootDir }, bindToSettings: false }), + ], + }, + ); + try { + await stack.signIn(); + await stack.signUp('upload-wall-warm-up@verify.test'); + } finally { + await stack.stop(); + } + } finally { + rmSync(rootDir, { recursive: true, force: true }); + for (const [name, value] of restoreEnv.reverse()) { + if (value === undefined) delete process.env[name]; + else process.env[name] = value; + } + } +} diff --git a/packages/plugins/organizations/src/storage-upload-door-ownership.wall.test.ts b/packages/plugins/organizations/src/storage-upload-door-ownership.wall.test.ts index e42205aeda8..1095ea4c913 100644 --- a/packages/plugins/organizations/src/storage-upload-door-ownership.wall.test.ts +++ b/packages/plugins/organizations/src/storage-upload-door-ownership.wall.test.ts @@ -52,6 +52,13 @@ import { join } from 'node:path'; import { bootStack, type VerifyStack } from '@objectstack/verify'; import { StorageServicePlugin } from '@objectstack/service-storage'; import { OrganizationsPlugin } from './organizations-plugin.js'; +import { warmUpUploadWallBoot } from './__tests__/upload-wall-warm-up.testkit.js'; + +// The walled boot's first load (lazily imported drivers and better-auth entries, +// sql.js's WASM compile) is paid here, during collection, so the `beforeAll` +// below clocks the boot and not the loading (AGENTS.md: clocked windows +// measure behaviour, never loading). See the helper for what it shares: nothing. +await warmUpUploadWallBoot(); const APP = { manifest: { diff --git a/packages/plugins/organizations/src/storage-upload-organization-change.wall.test.ts b/packages/plugins/organizations/src/storage-upload-organization-change.wall.test.ts index 73720150633..6c3a15a0271 100644 --- a/packages/plugins/organizations/src/storage-upload-organization-change.wall.test.ts +++ b/packages/plugins/organizations/src/storage-upload-organization-change.wall.test.ts @@ -40,6 +40,13 @@ import { join } from 'node:path'; import { bootStack, type VerifyStack } from '@objectstack/verify'; import { StorageServicePlugin } from '@objectstack/service-storage'; import { OrganizationsPlugin } from './organizations-plugin.js'; +import { warmUpUploadWallBoot } from './__tests__/upload-wall-warm-up.testkit.js'; + +// The walled boot's first load (lazily imported drivers and better-auth entries, +// sql.js's WASM compile) is paid here, during collection, so the `beforeAll` +// below clocks the boot and not the loading (AGENTS.md: clocked windows +// measure behaviour, never loading). See the helper for what it shares: nothing. +await warmUpUploadWallBoot(); const APP = { manifest: { From 6c2c03d7f20fa512bd4e421f140a596be6258983 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 19:52:10 +0000 Subject: [PATCH 2/2] test(organizations): the upload-wall warm-up puts the whole environment back bootStack sets NODE_ENV itself and never restores it. The warm-up now snapshots the environment before its boot and restores all of it after the stop, so each file's first hook starts from the environment it started from before: measured, every variable equal at the first hook, base copy against head. Claude-Session: https://claude.ai/code/session_017WLmd5in9RXu7AjyHR8fKQ Co-authored-by: Claude --- .../__tests__/upload-wall-warm-up.testkit.ts | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts b/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts index 2352cac8ac6..0e78e8a2efe 100644 --- a/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts +++ b/packages/plugins/organizations/src/__tests__/upload-wall-warm-up.testkit.ts @@ -22,10 +22,14 @@ * * It is `@objectstack/verify`'s `warmUpBoot` (`boot-warm-up.testkit.ts`, which * that package does not export) with this package's boot: the same two plugins - * the files mount, under the same two environment variables, set before the - * boot and restored after it. So the lazily loaded code is loaded under the - * environment the files' own boots load it under, and a module that reads its - * environment once, when it is first loaded, reads the same values either way. + * the files mount, under the same two environment variables. So the lazily + * loaded code is loaded under the environment the files' own boots load it + * under (`bootStack` sets `NODE_ENV` itself, first, in both), and a module + * that reads its environment once, when it is first loaded, reads the same + * values either way. Afterwards the WHOLE environment is put back as it was — + * the two variables, and every variable the boot set (`NODE_ENV` among them) — + * so the file's first hook starts from the environment it would have started + * from without this. * * ⛔ It shares nothing a case asserts on. It boots an app of its own (no * objects), on its own in-memory database and its own storage root, with @@ -56,11 +60,8 @@ const WALLED_BOOT_ENV = [ * the seeded admin in, sign one member up, and stop. */ export async function warmUpUploadWallBoot(): Promise { - const restoreEnv: Array<[string, string | undefined]> = []; - for (const [name, value] of WALLED_BOOT_ENV) { - restoreEnv.push([name, process.env[name]]); - process.env[name] = value; - } + const envBefore = { ...process.env }; + for (const [name, value] of WALLED_BOOT_ENV) process.env[name] = value; const rootDir = mkdtempSync(join(tmpdir(), 'upload-wall-warm-up-')); try { // A fresh configuration object per call: `bootStack`'s instance rule keys @@ -91,9 +92,11 @@ export async function warmUpUploadWallBoot(): Promise { } } finally { rmSync(rootDir, { recursive: true, force: true }); - for (const [name, value] of restoreEnv.reverse()) { - if (value === undefined) delete process.env[name]; - else process.env[name] = value; + for (const name of Object.keys(process.env)) { + if (!(name in envBefore)) delete process.env[name]; + } + for (const [name, value] of Object.entries(envBefore)) { + if (value !== undefined && process.env[name] !== value) process.env[name] = value; } } }