Skip to content

Commit 2f15284

Browse files
os-zhuangclaude
andauthored
test(devx): gate the module-top load of a dist-resolved workspace dep (clocked-window rule) (#10135)
* test(devx): gate the module-top load of a dist-resolved workspace dep Extends `check:test-source-alias` with the clocked-window rule (#10126): a test file that loads one of its package's unaliased specifiers through a dynamic `import()` / `require()` inside a function body — an `it()` body, a hook, or any nested function — with no module-scope load of the same specifier is a finding. vitest clocks hooks and test bodies only; collection is clocked against nothing, so a module-top side-effect import moves a cold transform OUT of every budget rather than into a bigger one. #10115 / PR #10120 paid for that reading with 30 ejected merge-queue builds in one night. Baseline sweep: 31 violations across 21 files in 9 packages, all fixed here the PR #10120 way (module-top `import '<specifier>'`), none quarantined or registry-exempted. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URCaKuNTuK3BKJvwqM74QU * test(devx): count the clocked-window fixture's findings on its full path `packages/clocked-load` is also a prefix of `packages/clocked-load-paid`, so the count assertion read the compliant fixture's findings as the violating one's. Found by ablating the compliance leg: the count moved to 3 for a reason that was in the assertion rather than in the gate. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URCaKuNTuK3BKJvwqM74QU * fix(devx): read a `}): Promise< { … } > {` signature as a function body The classifier's backward walk bailed on the braces, the semicolon and the newlines a multi-line signature puts between the parameter list and the body, so a module-level helper called from test bodies read as "not a function" and its file was exempted SILENTLY. Surfaced by ablating the classifier, not by the sweep: `serve-marketplace-offline-runtime-config.test.ts` sat green through it. Balanced groups are now jumped through the forward pass's `openOf` map, `=>` inside a function type is not counted as a generic closer, and the shape is pinned as its own self-test fixture. One more real violation follows, fixed the same way. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URCaKuNTuK3BKJvwqM74QU * docs(devx): state the clocked-window convention where an author meets it #10126's layer 4 asked for the sentence in AGENTS.md's testing conventions. That file sits exactly on its shrink-only line ceiling (958, headroom 0, `scripts/pm/check-skill-line-ratchet.mjs`); the sentence costs three lines and its own section has two lines of lossless rewrap headroom. Raising a ceiling takes a maintainer ruling, and truncating a maintainer-specified sentence to fit one is not this gate's call — so the doc placement stays open and is reported. Meanwhile the sentence is stated verbatim in the gate header AND in the failure text, pinned by its own self-test assertion so it cannot decay into a comment. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URCaKuNTuK3BKJvwqM74QU * docs(devx): land the clocked-window convention in AGENTS.md (ceiling 958 -> 961) Layer 4 of #10126, unblocked by a maintainer ruling. AGENTS.md sat exactly on its shrink-only line ceiling with the mandated sentence costing three lines and its section carrying two lines of lossless rewrap headroom, so it could not be paid for in place. Ruling 2026-08-20, verbatim and untranslated: 「A — 抬上限到 961 (Recommended)」 The raise is exactly +3 and nothing more; headroom is 0 again by construction, so the next author needing a line is back to compressing. The sentence lands beside the sibling test-gate conventions in § Build & Test, unedited, and the gate header's note about why it was NOT there is corrected. The ratchet's self-test pins coverage and shape, never a ceiling's numeric value, so it needed no extension; re-run green at 19 cases. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01URCaKuNTuK3BKJvwqM74QU --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent a659896 commit 2f15284

25 files changed

Lines changed: 727 additions & 8 deletions

AGENTS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ judged on the **shallowest** point a path reaches, not where it ends — a liter
118118
climbs past the package root and then descends into a sibling ends at a positive depth
119119
while addressing another package entirely.
120120

121+
Clocked windows measure behaviour, never loading — a test that boots a real plugin chain
122+
pays its first load at module top; `pnpm check:test-source-alias` gates it.
123+
121124
### Running the dev server
122125

123126
| Scenario | Command | Notes |

examples/app-crm/test/smoke.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ import { describe, it, expect } from 'vitest';
44
import stack from '../objectstack.config.js';
55
import { PipelineDashboard } from '../src/dashboards/pipeline.dashboard.js';
66

7+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
8+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
9+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
10+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
11+
// where the same shape cost 30 ejected merge-queue builds in one night.
12+
import '@objectstack/spec/ui';
13+
714
describe('app-crm minimal metadata bundle', () => {
815
it('exposes the expected manifest', () => {
916
// `manifest` is optional on the stack bundle type; this example always

examples/embed-objectql/test/embed.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
import { describe, it, expect } from 'vitest';
44
import { runEmbeddedEngine } from '../src/index.js';
55

6+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
7+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
8+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
9+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
10+
// where the same shape cost 30 ejected merge-queue builds in one night.
11+
import '@objectstack/objectql/core';
12+
613
describe('embed @objectstack/objectql/core (ADR-0076)', () => {
714
it('runs the engine standalone and round-trips CRUD via the lean entry', async () => {
815
const active = await runEmbeddedEngine();

packages/cli/src/commands/dev-default-db.test.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,21 @@
1212
* cross-command agreement is pinned by `unified-db-resolution.pin.test.ts`.
1313
*/
1414

15-
import { describe, it, expect, beforeAll, beforeEach, afterEach } from 'vitest';
15+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
1616
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
1717
import { tmpdir } from 'node:os';
1818
import path from 'path';
1919
import { resolveDevDatabase } from './dev.js';
2020

21-
// The dev seam lazy-imports @objectstack/runtime (oclif startup weight, #5726);
22-
// the FIRST import cold-loads that graph and can exceed vitest's 5s default on
23-
// a cold worker — warm it once, like standalone-stack.test.ts's BOOT_TIMEOUT.
24-
beforeAll(async () => { await import('@objectstack/runtime'); }, 60_000);
21+
// [#10126] The dev seam lazy-imports @objectstack/runtime (oclif startup weight,
22+
// #5726), and the FIRST import cold-loads that whole graph. This file used to warm
23+
// it in a `beforeAll` with a 60s budget; a hook is still a CLOCKED window, and any
24+
// budget the cost is moved INTO can be exhausted by a heavier shard — which is how
25+
// #10115 / PR #10120 ejected a file from the merge queue four times in one night.
26+
// A module-top side-effect import pays the transform during COLLECTION instead, and
27+
// vitest clocks hooks and test bodies only. See `scripts/check-test-source-alias.mjs`
28+
// (the clocked-window rule), which now gates this shape.
29+
import '@objectstack/runtime';
2530

2631
let cwd: string;
2732
beforeEach(() => { cwd = mkdtempSync(path.join(tmpdir(), 'os-dev-db-')); });

packages/cli/src/commands/doctor-ledger-dir-authority.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ import Doctor, {
5555
installedPackageLedgerSkippedEntriesCheck,
5656
} from './doctor.js';
5757

58+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
59+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
60+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
61+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
62+
// where the same shape cost 30 ejected merge-queue builds in one night.
63+
import '@objectstack/cloud-connection';
64+
5865
const HERE = path.dirname(fileURLToPath(import.meta.url));
5966
/** `packages/cli` — the oclif root the real command is loaded against below. */
6067
const CLI_ROOT = path.resolve(HERE, '..', '..');

packages/cli/src/commands/doctor-ledger-posture-independence.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,13 @@ import { fileURLToPath } from 'node:url';
6969

7070
import Doctor from './doctor.js';
7171

72+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
73+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
74+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
75+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
76+
// where the same shape cost 30 ejected merge-queue builds in one night.
77+
import '@objectstack/cloud-connection';
78+
7279
const HERE = path.dirname(fileURLToPath(import.meta.url));
7380
/** `packages/cli` — the oclif root the real command is loaded against below. */
7481
const CLI_ROOT = path.resolve(HERE, '..', '..');

packages/cli/src/commands/doctor-ledger-read-failure.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ import Doctor, {
9393
installedPackageLedgerReaderFailureCheck,
9494
} from './doctor.js';
9595

96+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
97+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
98+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
99+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
100+
// where the same shape cost 30 ejected merge-queue builds in one night.
101+
import '@objectstack/cloud-connection';
102+
96103
const HERE = path.dirname(fileURLToPath(import.meta.url));
97104
/** `packages/cli` — the oclif root the real command is loaded against below. */
98105
const CLI_ROOT = path.resolve(HERE, '..', '..');

packages/cli/src/utils/platform-migrations-arming.integration.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ import { SqlDriver } from '@objectstack/driver-sql';
4747
import { GLOBAL_TENANT, SEQUENCES_TABLE, ORGANIZATION_TABLE } from '@objectstack/metadata-protocol';
4848
import { bootSchemaStack } from './schema-migrate.js';
4949

50+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
51+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
52+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
53+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
54+
// where the same shape cost 30 ejected merge-queue builds in one night.
55+
import '@objectstack/objectql';
56+
import '@objectstack/runtime';
57+
5058
const ORG_ID = 'org_x';
5159
/** The `__global__` counter the seed loader ran ahead to before the org existed. */
5260
const SEEDED_LAST_VALUE = 38;

packages/cli/test/serve-marketplace-offline-install.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
import { describe, expect, it } from 'vitest';
3232
import Serve from '../src/commands/serve.js';
3333

34+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
35+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
36+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
37+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
38+
// where the same shape cost 30 ejected merge-queue builds in one night.
39+
import '@objectstack/cloud-connection';
40+
3441
/** Minimal stand-in for a loaded plugin: what the resolver actually reads. */
3542
function plugin(name: string, ctorName: string): { name: string } {
3643
const Ctor = { [ctorName]: class { name: string; constructor(n: string) { this.name = n; } } }[ctorName]!;

packages/cli/test/serve-marketplace-offline-runtime-config.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ import { join } from 'node:path';
6161
import { tmpdir } from 'node:os';
6262
import Serve from '../src/commands/serve.js';
6363

64+
// [#10126] Pay the first transform of these dist-resolved workspace deps at MODULE
65+
// LOAD. Each is reached below through a dynamic `import()` inside an `it()` body or a
66+
// hook -- both of which vitest clocks, while collection is clocked against nothing. See
67+
// `scripts/check-test-source-alias.mjs` (the clocked-window rule) and #10115 / PR #10120,
68+
// where the same shape cost 30 ejected merge-queue builds in one night.
69+
import '@objectstack/cloud-connection';
70+
6471
interface RouteRecord { method: string; path: string }
6572

6673
interface HonoShapedApp {

0 commit comments

Comments
 (0)