From 32ad41617659dbf6f60449a0b0e3d489c4331576 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 07:47:22 +0000 Subject: [PATCH 1/2] test(cli): spawn the source CLI with process.execPath in three 10-13 s files create-objectstack-stack-reach, translation-contributed-nav-validate-door and i18n-extract-companion-orphan spawned bin/run-dev.js through node_modules/.bin/tsx, a launcher that is its own node process in front of the CLI. Spawn it with process.execPath instead; argv, cwd, env and timeouts are unchanged. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01FEkQ5mugTWnXsnz9LD9BMM --- .../cli/test/create-objectstack-stack-reach.test.ts | 11 ++++++++--- .../cli/test/i18n-extract-companion-orphan.test.ts | 11 ++++++++--- .../translation-contributed-nav-validate-door.test.ts | 11 ++++++++--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/packages/cli/test/create-objectstack-stack-reach.test.ts b/packages/cli/test/create-objectstack-stack-reach.test.ts index 29d5f943b59..20826d8cb06 100644 --- a/packages/cli/test/create-objectstack-stack-reach.test.ts +++ b/packages/cli/test/create-objectstack-stack-reach.test.ts @@ -63,14 +63,19 @@ import { GENERATOR_SCAFFOLD_TARGETS } from '../src/commands/generate.js'; import { childEnv } from './helpers/serve-process.js'; const HERE = resolve(fileURLToPath(import.meta.url), '..'); +/** + * Spawned by this process's own `node`, not through the `tsx` binary: the entry, its + * `src/` and its pinned `NODE_ENV=development` are the same either way, and the + * `.bin/tsx` launcher only adds a second node process in front of the CLI, about half + * of every spawn's wall (#23181). + */ const CLI = resolve(HERE, '../bin/run-dev.js'); -const TSX = resolve(HERE, '../../../node_modules/.bin/tsx'); // One `resolve(HERE, …)` call per line: `check:cross-package-test-inputs` // reconstructs this read by SOURCE SCAN. const ON_RAMP_BIN = resolve(HERE, '../../..', 'packages/create-objectstack/bin/create-objectstack.js'); -/** One plain-node scaffold, then three oclif + tsx cold starts, sequential. */ +/** One plain-node scaffold, then three oclif cold starts of the source CLI, sequential. */ const RUN_TIMEOUT_MS = 240_000; const PROJECT = 'my-app'; @@ -106,7 +111,7 @@ function run(file: string, args: string[], cwd: string): Promise { }); } -const os = (args: string[], cwd: string) => run(TSX, [CLI, ...args], cwd); +const os = (args: string[], cwd: string) => run(process.execPath, [CLI, ...args], cwd); const out = (r: Run) => r.stdout + r.stderr; const target = (type: string) => { diff --git a/packages/cli/test/i18n-extract-companion-orphan.test.ts b/packages/cli/test/i18n-extract-companion-orphan.test.ts index 08892babfc9..a53f85fb6cc 100644 --- a/packages/cli/test/i18n-extract-companion-orphan.test.ts +++ b/packages/cli/test/i18n-extract-companion-orphan.test.ts @@ -80,8 +80,13 @@ import { fileURLToPath } from 'node:url'; import { childEnv } from './helpers/serve-process.js'; const HERE = resolve(fileURLToPath(import.meta.url), '..'); +/** + * Spawned by this process's own `node`, not through the `tsx` binary: the entry, its + * `src/` and its pinned `NODE_ENV=development` are the same either way, and the + * `.bin/tsx` launcher only adds a second node process in front of the CLI, about half + * of every spawn's wall (#23181). + */ const CLI = resolve(HERE, '../bin/run-dev.js'); -const TSX = resolve(HERE, '../../../node_modules/.bin/tsx'); const CLI_PACKAGE_ROOT = resolve(HERE, '..'); /** One object (2 leaves) + one app (1 leaf); the registry baseline rides along. */ @@ -146,7 +151,7 @@ function runExtract( ): { stdout: string; dir: string; files: string[] } { const dir = join(outRoot, name); const stdout = execFileSync( - TSX, + process.execPath, [CLI, 'i18n', 'extract', config, '--locales=ja-JP', '--source-hashes', '--fill=default', ...flags, `--out=${dir}`], { encoding: 'utf8', env: childEnv(), timeout: 180_000 }, ); @@ -210,7 +215,7 @@ describe('os i18n extract — the provenance companion accompanies a module (#16 const stdout = plain( execFileSync( - TSX, + process.execPath, [ CLI, 'i18n', 'extract', APPS_ONLY, '--locales=ja-JP', '--source-hashes', '--fill=default', '--no-metadata-forms', '--check', `--out=${dir}`, diff --git a/packages/cli/test/translation-contributed-nav-validate-door.test.ts b/packages/cli/test/translation-contributed-nav-validate-door.test.ts index 3c13da23105..12d9da968b6 100644 --- a/packages/cli/test/translation-contributed-nav-validate-door.test.ts +++ b/packages/cli/test/translation-contributed-nav-validate-door.test.ts @@ -18,7 +18,7 @@ * * Integration tier: it spawns the source CLI (`packages/cli/vitest-tiers.ts`). * Two spawns, one per fixture. The CLI runs through `bin/run-dev.js` (source, - * via tsx), and `@objectstack/spec` resolves through `exports` to `dist/`. + * spawned by this process's own `node`), and `@objectstack/spec` resolves through `exports` to `dist/`. */ import { afterAll, beforeAll, describe, expect, it } from 'vitest'; @@ -31,8 +31,13 @@ import { childEnv } from './helpers/serve-process.js'; import { writeDefineStackConfig } from './helpers/define-stack-fixture.js'; const HERE = resolve(fileURLToPath(import.meta.url), '..'); +/** + * Spawned by this process's own `node`, not through the `tsx` binary: the entry, its + * `src/` and its pinned `NODE_ENV=development` are the same either way, and the + * `.bin/tsx` launcher only adds a second node process in front of the CLI, about half + * of every spawn's wall (#23181). + */ const CLI = resolve(HERE, '../bin/run-dev.js'); -const TSX = resolve(HERE, '../../../node_modules/.bin/tsx'); /** A service module contributing `nav_case` into an app another package owns. */ const stackOf = (navCase: Record) => ({ @@ -77,7 +82,7 @@ interface Run { function runCli(args: string[], cwd: string): Promise { return new Promise((resolvePromise) => { execFile( - TSX, + process.execPath, [CLI, ...args], { cwd, maxBuffer: 16 * 1024 * 1024, env: childEnv({ NO_COLOR: '1' }) }, (err, stdout, stderr) => { From 0877f01c093cdaad27414916c7d9bc288b008f15 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 08:03:08 +0000 Subject: [PATCH 2/2] test(cli): budget the seven 10-13 s cli files whose floor is distinct real work authoring-rule-command-parity, hook-timeout-override-refusal and the three doctor files (ledger-read-failure, ledger-posture-independence, node-env-default) spawn or run the real producer once per single-cause fixture with no repeated triple; create-objectstack-stack-reach and i18n-extract-companion-orphan keep four distinct spawns after the process.execPath switch. Each takes a line-2 test-budget header sized from its slowest of the five scheduled CI runs x 1.25. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01FEkQ5mugTWnXsnz9LD9BMM --- .../cli/src/commands/doctor-ledger-posture-independence.test.ts | 1 + packages/cli/src/commands/doctor-ledger-read-failure.test.ts | 1 + packages/cli/src/commands/doctor-node-env-default.test.ts | 1 + packages/cli/test/authoring-rule-command-parity.test.ts | 1 + packages/cli/test/create-objectstack-stack-reach.test.ts | 1 + packages/cli/test/hook-timeout-override-refusal.test.ts | 1 + packages/cli/test/i18n-extract-companion-orphan.test.ts | 1 + 7 files changed, 7 insertions(+) diff --git a/packages/cli/src/commands/doctor-ledger-posture-independence.test.ts b/packages/cli/src/commands/doctor-ledger-posture-independence.test.ts index db9f76e298d..93969f7a191 100644 --- a/packages/cli/src/commands/doctor-ledger-posture-independence.test.ts +++ b/packages/cli/src/commands/doctor-ledger-posture-independence.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: twenty in-process os doctor runs, one per posture, ledger fixture and flag, each shelling out to pnpm -v, tsc -v and git --version and bundling its own config, the first also paying the cold config-loader load; slowest CI reading 12.2 s (run 41255489006) of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * `os doctor` reports an unreadable installed-package ledger under EVERY diff --git a/packages/cli/src/commands/doctor-ledger-read-failure.test.ts b/packages/cli/src/commands/doctor-ledger-read-failure.test.ts index 6a120e5cea8..e4cfce7e985 100644 --- a/packages/cli/src/commands/doctor-ledger-read-failure.test.ts +++ b/packages/cli/src/commands/doctor-ledger-read-failure.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: fifteen in-process os doctor runs, one per ledger fixture or flag (three of them on a module graph re-imported after vi.resetModules to swap the ledger reader), each shelling out to pnpm -v, tsc -v and git --version and bundling its own config, the first also paying the cold config-loader load; the fourteen row-builder cases are pure; slowest CI reading 12.3 s (run 41199450735) of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * `os doctor` does not print `✓ Unique scope` when it could not read the diff --git a/packages/cli/src/commands/doctor-node-env-default.test.ts b/packages/cli/src/commands/doctor-node-env-default.test.ts index 77d6ac23678..37b9dd379d5 100644 --- a/packages/cli/src/commands/doctor-node-env-default.test.ts +++ b/packages/cli/src/commands/doctor-node-env-default.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: fifteen in-process os doctor runs, one per NODE_ENV value, project shape and flag, each shelling out to pnpm -v, tsc -v and git --version and bundling its own config, the first also paying the cold config-loader load; the twenty-one row-builder cases are pure; slowest CI reading 11.4 s (run 41271604267) of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * `os doctor`'s unset-`NODE_ENV` row (#5673). diff --git a/packages/cli/test/authoring-rule-command-parity.test.ts b/packages/cli/test/authoring-rule-command-parity.test.ts index dd27e50cf03..02cd06334b0 100644 --- a/packages/cli/test/authoring-rule-command-parity.test.ts +++ b/packages/cli/test/authoring-rule-command-parity.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: three spawns of the source CLI (os lint, os validate, os build) over one planted-defect stack, every one a distinct triple whose exit code is the contract; the nine rule cases run in process; slowest CI reading 12.5 s (run 41271604267) of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * The BEHAVIOURAL half of #4409, next to the structural ratchet in diff --git a/packages/cli/test/create-objectstack-stack-reach.test.ts b/packages/cli/test/create-objectstack-stack-reach.test.ts index 20826d8cb06..ec07e945286 100644 --- a/packages/cli/test/create-objectstack-stack-reach.test.ts +++ b/packages/cli/test/create-objectstack-stack-reach.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: one on-ramp scaffold child and three spawns of the source CLI (os g object, os g flow, os validate), chained over the one scaffolded project, every one a distinct triple; slowest CI reading 12.4 s (run 41255489006), taken through the tsx launcher this file no longer uses, of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * PIN (#20333) — `npm create objectstack` → `os g flow` → `os validate` diff --git a/packages/cli/test/hook-timeout-override-refusal.test.ts b/packages/cli/test/hook-timeout-override-refusal.test.ts index f039093fa7f..7fcd4061e85 100644 --- a/packages/cli/test/hook-timeout-override-refusal.test.ts +++ b/packages/cli/test/hook-timeout-override-refusal.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: four vitest list children of this package (--hookTimeout, --teardownTimeout, no override, --testTimeout), every one a distinct config-load question; slowest CI reading 11.3 s (run 41255489006) of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * `--hookTimeout` must never return a GREEN from this package again (#18788). diff --git a/packages/cli/test/i18n-extract-companion-orphan.test.ts b/packages/cli/test/i18n-extract-companion-orphan.test.ts index a53f85fb6cc..d0d6d6788a6 100644 --- a/packages/cli/test/i18n-extract-companion-orphan.test.ts +++ b/packages/cli/test/i18n-extract-companion-orphan.test.ts @@ -1,4 +1,5 @@ // Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. +// test-budget: 20 — spawns the real producer once per single-cause fixture: four spawns of the source CLI (os i18n extract on the apps-only stack, its --check over a seeded legacy companion, and the full stack under --objects-only and --no-objects-only), every one a distinct triple; slowest CI reading 11.3 s (run 41271604267), taken through the tsx launcher this file no longer uses, of the five scheduled CI runs 41199450735, 41217827347, 41237094739, 41255489006, 41271604267, x 1.25, rounded up /** * The provenance companion accompanies the bundle modules beside it, and its