Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 38 additions & 21 deletions packages/cli/test/lint-per-package-authoring-parity.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 60 — spawns the real producer once per single-cause fixture: five CLI spawns in one beforeAll, each a distinct triple (`os build`, `os lint`, `os lint --strict` over the flip fixture; `os build`, `os lint` over the single-package control); slowest CI reading 43.77 s (run 40392443783), taken with nine spawns before the repeats were shared of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* #18778, the BEHAVIOURAL half — `os lint` and `os build` report the same
Expand Down Expand Up @@ -211,6 +212,17 @@ export default defineStack({

const dirs = { flip: '', single: '' };

/** A cold `tsx` spawn of the CLI source entry, the per-case allowance this file always gave one. */
const SPAWN_TIMEOUT_MS = 180_000;

/**
* One run per distinct (command, flags, fixture) triple. The cases below used
* to spawn `os build --json` on the flip fixture three times and `os lint
* --json` on it three times; every case now reads the one run of its triple,
* spawned in sequence in the `beforeAll` below.
*/
const runs = {} as Record<'buildFlip' | 'lintFlip' | 'lintStrictFlip' | 'buildSingle' | 'lintSingle', Run>;

function plant(config: string): string {
const dir = mkdtempSync(join(tmpdir(), 'os-lintpp-'));
mkdirSync(join(dir, 'src'), { recursive: true });
Expand All @@ -225,31 +237,36 @@ function plant(config: string): string {
}

describe('#18778 — `os lint` and `os build` report the same per-package finding set', () => {
beforeAll(() => {
beforeAll(async () => {
dirs.flip = plant(CONFIG_FLIP);
dirs.single = plant(CONFIG_SINGLE);
});
runs.buildFlip = await runCli(['build', '--json'], dirs.flip);
runs.lintFlip = await runCli(['lint', '--json'], dirs.flip);
runs.lintStrictFlip = await runCli(['lint', '--json', '--strict'], dirs.flip);
runs.buildSingle = await runCli(['build', '--json'], dirs.single);
runs.lintSingle = await runCli(['lint', '--json'], dirs.single);
}, 5 * SPAWN_TIMEOUT_MS);

afterAll(() => {
for (const dir of Object.values(dirs)) if (dir) rmSync(dir, { recursive: true, force: true });
});

it('the fixture reaches the pass at all, and the UNION sees nothing — `os build` raises exactly the survivor', async () => {
it('the fixture reaches the pass at all, and the UNION sees nothing — `os build` raises exactly the survivor', () => {
// Asserted BEFORE any claim about parity: a fixture that never reaches the
// per-package pass makes every comparison below vacuous, and a fixture whose
// union run raises the same finding makes the comparison an echo count.
const build = await runCli(['build', '--json'], dirs.flip);
const build = runs.buildFlip;
expect(build.code, `os build --json failed:\n${build.stdout}${build.stderr}`).toBe(0);
const warnings = payloadOf(build, 'os build --json').warnings as unknown[];
expect(buildPerPackage(warnings).length).toBeGreaterThan(0);
// Nothing else: every warning on this fixture is a per-package survivor.
expect(warnings.length).toBe(buildPerPackage(warnings).length);
}, 180_000);
});

it('`os lint` reports every per-package finding `os build` does', async () => {
it('`os lint` reports every per-package finding `os build` does', () => {
// The pin. On `origin/main` 7572329069 this read `build: 1, lint: 0`.
const build = await runCli(['build', '--json'], dirs.flip);
const lint = await runCli(['lint', '--json'], dirs.flip);
const build = runs.buildFlip;
const lint = runs.lintFlip;
expect(build.code, `os build --json failed:\n${build.stdout}${build.stderr}`).toBe(0);
expect(lint.code, `os lint --json failed:\n${lint.stdout}${lint.stderr}`).toBe(0);

Expand All @@ -260,25 +277,25 @@ describe('#18778 — `os lint` and `os build` report the same per-package findin
missing,
'these per-package findings ride `os build` and `os lint` cannot see them — the #18778 false-clean set',
).toEqual([]);
}, 180_000);
});

it('…and nothing per-package rides `os lint` that `os build` does not report either', async () => {
it('…and nothing per-package rides `os lint` that `os build` does not report either', () => {
// Parity is an equality. A lint that over-reports is its own defect — an
// author fixing a finding the command that SHIPS never raises.
const build = await runCli(['build', '--json'], dirs.flip);
const lint = await runCli(['lint', '--json'], dirs.flip);
const build = runs.buildFlip;
const lint = runs.lintFlip;
const inBuild = new Set(buildPerPackage(payloadOf(build, 'os build --json').warnings as unknown[]));
expect(lintPerPackage(payloadOf(lint, 'os lint --json').issues as unknown[]).filter((w) => !inBuild.has(w))).toEqual([]);
}, 180_000);
});

it('⚠️ THE NARROWING — `os lint --strict` now EXITS 1 on a project it exited 0 for', async () => {
it('⚠️ THE NARROWING — `os lint --strict` now EXITS 1 on a project it exited 0 for', () => {
// The Clause-② evidence, pinned so it can neither regress silently nor widen
// silently. `--strict` is documented as "treat warnings as errors", and a
// per-package advisory is a warning this door could not see before, so the
// verdict moves with it. ⛔ The DEFAULT face is deliberately NOT asserted to
// move: no `error`-severity per-package-only finding was exhibited on this
// fixture, and a pin asserting one would be asserting something unmeasured.
const strict = await runCli(['lint', '--json', '--strict'], dirs.flip);
const strict = runs.lintStrictFlip;
const payload = payloadOf(strict, 'os lint --json --strict');
expect(payload.strict).toBe(true);
expect(payload.failing).toBe(1);
Expand All @@ -287,21 +304,21 @@ describe('#18778 — `os lint` and `os build` report the same per-package findin

// …and the same project without `--strict` still exits 0, so what moved is
// the strict verdict and not the default one.
const plain = await runCli(['lint', '--json'], dirs.flip);
const plain = runs.lintFlip;
expect(plain.code).toBe(0);
expect(payloadOf(plain, 'os lint --json').passed).toBe(true);
}, 180_000);
});

it('CONTROL — a single-package project raises NO per-package finding on either door', async () => {
it('CONTROL — a single-package project raises NO per-package finding on either door', () => {
// "Present" must be distinguishable from "always present": the prefix this
// file matches on is not something either command emits unconditionally, and
// `os lint --strict` still exits 1 there for the ORDINARY warning, which is
// how the case above is read as a change and not as a constant.
const build = await runCli(['build', '--json'], dirs.single);
const lint = await runCli(['lint', '--json'], dirs.single);
const build = runs.buildSingle;
const lint = runs.lintSingle;
expect(build.code, `os build --json failed:\n${build.stdout}${build.stderr}`).toBe(0);
expect(lint.code, `os lint --json failed:\n${lint.stdout}${lint.stderr}`).toBe(0);
expect(buildPerPackage(payloadOf(build, 'os build --json').warnings as unknown[])).toEqual([]);
expect(lintPerPackage(payloadOf(lint, 'os lint --json').issues as unknown[])).toEqual([]);
}, 180_000);
});
});
1 change: 1 addition & 0 deletions packages/cli/test/package-union-readers.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 50 — spawns the real producer once per single-cause fixture: nine CLI spawns across three beforeAll hooks, each a distinct triple (`os build`, `os validate`, `os lint --strict`, `os i18n check`, `os i18n extract` over five fixtures); slowest CI reading 32.22 s (run 40447801748) of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* #22238 / #22189 — the CLI readers that judged only a multi-package
Expand Down
1 change: 1 addition & 0 deletions packages/cli/test/picklist-reference-doors.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 80 — spawns the real producer once per single-cause fixture: 11 CLI spawns over four fixtures, each a distinct command, face or fixture (`os validate` json and text, `os build`, `os lint`); slowest CI reading 57.37 s (run 40447801748) of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* The `picklist` kind through the three authoring doors, over the real CLI.
Expand Down
1 change: 1 addition & 0 deletions packages/cli/test/stack-conversion-record-door.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 180 — spawns the real producer once per single-cause fixture: 24 CLI spawns, one per case leg, each a distinct (command, flags, fixture) triple across `os validate` / `os build` / `os lint` over eight fixtures; slowest CI reading 141.61 s (run 40392443783) of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* The ADR-0087 conversions a stack PRODUCER applied reach `os validate` and
Expand Down
1 change: 1 addition & 0 deletions packages/cli/test/stack-provenance-door.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 80 — spawns the real producer once per single-cause fixture: 12 CLI spawns, `os validate` and `os build` once each over six fixtures, every one a distinct triple; slowest CI reading 60.77 s (run 40392443783) of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* `os validate` and `os build` accept one authoring shape (#20367 ruling B).
Expand Down
1 change: 1 addition & 0 deletions packages/cli/test/union-fold-command-parity.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 50 — spawns the real producer once per single-cause fixture: nine CLI spawns, `os validate` / `os lint` / `os build` once each over three fixtures, every one a distinct triple; slowest CI reading 33.65 s (run 40392443783) of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* #17069 — the three authoring commands judge the SAME STACK, on the ADR-0130
Expand Down
50 changes: 33 additions & 17 deletions packages/cli/test/validate-per-package-authoring-parity.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 40 — spawns the real producer once per single-cause fixture: four CLI spawns in one beforeAll, each a distinct triple (`os build`, `os validate` over the multi-package fixture and over the single-package control); slowest CI reading 28.80 s (run 40392443783), taken with seven spawns before the repeats were shared of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* #18677, the BEHAVIOURAL half — `os validate` and `os build` report the same
Expand Down Expand Up @@ -230,6 +231,17 @@ export default defineStack({

const dirs = { multi: '', single: '' };

/** A cold `tsx` spawn of the CLI source entry, the per-case allowance this file always gave one. */
const SPAWN_TIMEOUT_MS = 180_000;

/**
* One run per distinct (command, flags, fixture) triple. The cases below used
* to spawn `os build --json` on the multi-package fixture three times and `os
* validate --json` on it twice; every case now reads the one run of its
* triple, spawned in sequence in the `beforeAll` below.
*/
const runs = {} as Record<'buildMulti' | 'validateMulti' | 'buildSingle' | 'validateSingle', Run>;

function plant(config: string): string {
const dir = mkdtempSync(join(tmpdir(), 'os-ppparity-'));
mkdirSync(join(dir, 'src'), { recursive: true });
Expand All @@ -244,20 +256,24 @@ function plant(config: string): string {
}

describe('#18677 — `os validate` and `os build` report the same per-package advisory set', () => {
beforeAll(() => {
beforeAll(async () => {
dirs.multi = plant(CONFIG_MULTI);
dirs.single = plant(CONFIG_SINGLE);
});
runs.buildMulti = await runCli(['build', '--json'], dirs.multi);
runs.validateMulti = await runCli(['validate', '--json'], dirs.multi);
runs.buildSingle = await runCli(['build', '--json'], dirs.single);
runs.validateSingle = await runCli(['validate', '--json'], dirs.single);
}, 4 * SPAWN_TIMEOUT_MS);

afterAll(() => {
for (const dir of Object.values(dirs)) if (dir) rmSync(dir, { recursive: true, force: true });
});

it('the multi-package fixture reaches the pass at all — and its survivor is NOT an echo', async () => {
it('the multi-package fixture reaches the pass at all — and its survivor is NOT an echo', () => {
// Asserted BEFORE any claim about parity: a fixture that never reaches the
// per-package pass makes every comparison below vacuous, which is the exact
// way this defect stayed invisible.
const build = await runCli(['build', '--json'], dirs.multi);
const build = runs.buildMulti;
expect(build.code, `os build --json failed:\n${build.stdout}${build.stderr}`).toBe(0);
const warnings = payloadOf(build, 'os build --json').warnings as unknown[];
expect(perPackageWarnings(warnings).length).toBeGreaterThan(0);
Expand All @@ -276,12 +292,12 @@ describe('#18677 — `os validate` and `os build` report the same per-package ad
PER_PACKAGE_WHERE.test(named(industryWarnings[0])),
'the `industry` finding is being raised by the UNION run — the survivor would be an echo',
).toBe(true);
}, 180_000);
});

it('`os validate` reports every per-package advisory `os build` does', async () => {
it('`os validate` reports every per-package advisory `os build` does', () => {
// The pin. On `origin/main` 09e16a574 this read `build: 1, validate: 0`.
const build = await runCli(['build', '--json'], dirs.multi);
const validate = await runCli(['validate', '--json'], dirs.multi);
const build = runs.buildMulti;
const validate = runs.validateMulti;
expect(build.code, `os build --json failed:\n${build.stdout}${build.stderr}`).toBe(0);
expect(validate.code, `os validate --json failed:\n${validate.stdout}${validate.stderr}`).toBe(0);

Expand All @@ -294,29 +310,29 @@ describe('#18677 — `os validate` and `os build` report the same per-package ad
missingFromValidate,
'these per-package findings ride `os build` and `os validate` cannot see them — the #18677 false-clean set',
).toEqual([]);
}, 180_000);
});

it('…and nothing per-package rides `os validate` that `os build` does not report either', async () => {
it('…and nothing per-package rides `os validate` that `os build` does not report either', () => {
// The reverse end. Parity is an equality, and a validate that over-reports
// is its own defect — an author fixing a finding the command that SHIPS
// never raises.
const build = await runCli(['build', '--json'], dirs.multi);
const validate = await runCli(['validate', '--json'], dirs.multi);
const build = runs.buildMulti;
const validate = runs.validateMulti;
const bw = payloadOf(build, 'os build --json').warnings as unknown[];
const vw = payloadOf(validate, 'os validate --json').warnings as unknown[];

const inBuild = new Set(perPackageWarnings(bw));
expect(perPackageWarnings(vw).filter((w) => !inBuild.has(w))).toEqual([]);
}, 180_000);
});

it('CONTROL — a single-package project raises NO per-package finding on either door', async () => {
it('CONTROL — a single-package project raises NO per-package finding on either door', () => {
// "Present" must be distinguishable from "always present": the prefix this
// file matches on is not something either command emits unconditionally.
const build = await runCli(['build', '--json'], dirs.single);
const validate = await runCli(['validate', '--json'], dirs.single);
const build = runs.buildSingle;
const validate = runs.validateSingle;
expect(build.code, `os build --json failed:\n${build.stdout}${build.stderr}`).toBe(0);
expect(validate.code, `os validate --json failed:\n${validate.stdout}${validate.stderr}`).toBe(0);
expect(perPackageWarnings(payloadOf(build, 'os build --json').warnings as unknown[])).toEqual([]);
expect(perPackageWarnings(payloadOf(validate, 'os validate --json').warnings as unknown[])).toEqual([]);
}, 180_000);
});
});
1 change: 1 addition & 0 deletions packages/cli/test/validate-view-container-name.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
// test-budget: 30 — spawns the real producer once per single-cause fixture: four CLI spawns, `os validate` json and text over three fixtures, every one a distinct triple; slowest CI reading 20.34 s (run 40392443783) of the three scheduled CI runs after the oclif test manifest (PR #26256: 40392443783, 40424746941, 40447801748), x 1.25, rounded up

/**
* [#20331] `os validate` refuses a `views:` container whose own `name`
Expand Down
Loading