mirror of
https://github.com/morluto/rea.git
synced 2026-10-11 21:39:55 +00:00
perf(test): reuse CLI boundary worker module graphs
Share CLI boundary module evaluation in bounded forks while preserving fresh command instances and child processes. Keep module-mocked cleanup tests and source/compiled product catalog verification isolated, and update focused artifact selection. Flameox full cohort with V8 coverage: 102.8s to 96.6s; 290 passed and two existing skips. Statement, function and branch coverage maps and hit sets match across all 1,153 source files. After syncing main, 75 focused tests, typecheck, lint, docs checks and formatting pass; all 834 test files are discovered exactly once.
This commit is contained in:
+13
-6
@@ -927,7 +927,7 @@ behavior, and complete CI evidence before merging.
|
|||||||
| `npm run test:focused -- PATH...` | Exact existing test files; compiled boundaries build first, and unmatched paths fail |
|
| `npm run test:focused -- PATH...` | Exact existing test files; compiled boundaries build first, and unmatched paths fail |
|
||||||
| `npm run test:changed` | Source tests affected since the merge base with `origin/main`, including committed and dirty changes |
|
| `npm run test:changed` | Source tests affected since the merge base with `origin/main`, including committed and dirty changes |
|
||||||
| `npm run test:fast` | All domain, service, adapter, composition, conformance, and evaluation tests without build |
|
| `npm run test:fast` | All domain, service, adapter, composition, conformance, and evaluation tests without build |
|
||||||
| `npm run test:boundary` | Boundary, MCP boundary, process boundary, and process-global projects |
|
| `npm run test:boundary` | Boundary, CLI boundary, MCP boundary, process boundary, and process-global projects |
|
||||||
| `npm run test:mcp` | MCP boundary project |
|
| `npm run test:mcp` | MCP boundary project |
|
||||||
| `npm run test:acceptance` | Complete compiled CLI and MCP acceptance workflows |
|
| `npm run test:acceptance` | Complete compiled CLI and MCP acceptance workflows |
|
||||||
| `npm run test:watch` | Dirty source tests in watch mode, without build |
|
| `npm run test:watch` | Dirty source tests in watch mode, without build |
|
||||||
@@ -989,11 +989,18 @@ Vitest projects use up to two workers, bounded by host parallelism.
|
|||||||
`process-boundary` runs later with serial files because process-tree sampling
|
`process-boundary` runs later with serial files because process-tree sampling
|
||||||
shares host resources. Acceptance and process-global cases use isolated forks
|
shares host resources. Acceptance and process-global cases use isolated forks
|
||||||
without serial scheduling. Pure domain/service, composition, conformance,
|
without serial scheduling. Pure domain/service, composition, conformance,
|
||||||
evaluation, and MCP boundary projects share module graphs; their tests avoid
|
evaluation, CLI boundary, and MCP boundary projects share module graphs. Their
|
||||||
process-global state and keep resource cleanup test-scoped. Each MCP session
|
tests avoid process-global state and keep resource cleanup test-scoped. Each
|
||||||
still owns its resources. Adapter, non-MCP boundary, acceptance, and
|
MCP session still owns its resources, and CLI cases retain fresh command
|
||||||
process-global projects retain per-file isolation. See `vitest.config.ts` for
|
instances or subprocesses. CLI module mocks belong in `tests/process-global/`
|
||||||
current settings.
|
so they keep per-file isolation. Product catalog verification stays with the
|
||||||
|
isolated filesystem boundary tests because it loads both source and compiled
|
||||||
|
module graphs. Adapter, other boundary, acceptance, and process-global projects
|
||||||
|
retain per-file isolation. See `vitest.config.ts` for current settings.
|
||||||
|
|
||||||
|
The reused CLI boundary workers cap V8 old space at 384 MiB, based on their
|
||||||
|
profiled allocation and cleanup behavior. This encourages collection between
|
||||||
|
files; spawned REA processes retain their own heap settings.
|
||||||
|
|
||||||
Vitest worker limits do not bound subprocesses launched within a test. Bound
|
Vitest worker limits do not bound subprocesses launched within a test. Bound
|
||||||
those batches separately so repeated CLI validation cannot oversubscribe the
|
those batches separately so repeated CLI validation cannot oversubscribe the
|
||||||
|
|||||||
+2
-2
@@ -124,14 +124,14 @@
|
|||||||
"test:local": "node scripts/run-development-tests.mjs local",
|
"test:local": "node scripts/run-development-tests.mjs local",
|
||||||
"test:fast": "vitest run --project domain --project services --project adapters --project composition --project conformance --project evaluation",
|
"test:fast": "vitest run --project domain --project services --project adapters --project composition --project conformance --project evaluation",
|
||||||
"pretest:boundary": "npm run test:prepare",
|
"pretest:boundary": "npm run test:prepare",
|
||||||
"test:boundary": "vitest run --project boundary --project process-boundary --project mcp-boundary --project process-global",
|
"test:boundary": "vitest run --project boundary --project cli-boundary --project process-boundary --project mcp-boundary --project process-global",
|
||||||
"pretest:mcp": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:skills artifacts:mcp-catalog",
|
"pretest:mcp": "node scripts/check-dependency-install.mjs && node scripts/run-exclusive.mjs artifacts turbo run artifacts:skills artifacts:mcp-catalog",
|
||||||
"test:mcp": "vitest run --project mcp-boundary",
|
"test:mcp": "vitest run --project mcp-boundary",
|
||||||
"pretest:acceptance": "npm run build:cached",
|
"pretest:acceptance": "npm run build:cached",
|
||||||
"test:acceptance": "vitest run --project acceptance",
|
"test:acceptance": "vitest run --project acceptance",
|
||||||
"test:changed": "node scripts/run-development-tests.mjs changed",
|
"test:changed": "node scripts/run-development-tests.mjs changed",
|
||||||
"pretest:integration": "npm run test:prepare",
|
"pretest:integration": "npm run test:prepare",
|
||||||
"test:integration": "vitest run --project boundary --project process-boundary --project mcp-boundary --project process-global --project acceptance",
|
"test:integration": "vitest run --project boundary --project cli-boundary --project process-boundary --project mcp-boundary --project process-global --project acceptance",
|
||||||
"pretest:coverage": "npm run test:prepare",
|
"pretest:coverage": "npm run test:prepare",
|
||||||
"test:coverage": "vitest run --coverage.enabled --coverage.provider=v8",
|
"test:coverage": "vitest run --coverage.enabled --coverage.provider=v8",
|
||||||
"test:ci": "npm run test:coverage -- --reporter=default --reporter=junit --outputFile.junit=test-results.xml",
|
"test:ci": "npm run test:coverage -- --reporter=default --reporter=junit --outputFile.junit=test-results.xml",
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ const artifactConsumers = {
|
|||||||
"tests/boundary/mcp/contractPresentation.test.ts",
|
"tests/boundary/mcp/contractPresentation.test.ts",
|
||||||
"tests/boundary/mcp/toolSchemaValidity.test.ts",
|
"tests/boundary/mcp/toolSchemaValidity.test.ts",
|
||||||
],
|
],
|
||||||
"artifacts:product-catalog": ["tests/boundary/cli/productCatalog.test.ts"],
|
"artifacts:product-catalog": [
|
||||||
|
"tests/boundary/filesystem/productCatalog.test.ts",
|
||||||
|
],
|
||||||
"artifacts:managed-evidence": [
|
"artifacts:managed-evidence": [
|
||||||
"tests/boundary/filesystem/setupSkill.test.ts",
|
"tests/boundary/filesystem/setupSkill.test.ts",
|
||||||
],
|
],
|
||||||
|
|||||||
+17
-17
@@ -1,33 +1,33 @@
|
|||||||
import { Cli } from "incur";
|
import { Cli } from "incur";
|
||||||
import { expect, it, vi } from "vitest";
|
import { expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import type { BrowserScenarioCapturePort } from "../../../src/application/BrowserScenarioCapturePort.js";
|
import type { BrowserScenarioCapturePort } from "../../src/application/BrowserScenarioCapturePort.js";
|
||||||
import { createBrowserScenarioEvidence } from "../../../src/application/BrowserScenarioEvidence.js";
|
import { createBrowserScenarioEvidence } from "../../src/application/BrowserScenarioEvidence.js";
|
||||||
import type { BrowserScenarioSessionPort } from "../../../src/browser/BrowserScenarioSessionPort.js";
|
import type { BrowserScenarioSessionPort } from "../../src/browser/BrowserScenarioSessionPort.js";
|
||||||
import { PlaywrightBrowserScenarioProvider } from "../../../src/browser/PlaywrightBrowserScenarioProvider.js";
|
import { PlaywrightBrowserScenarioProvider } from "../../src/browser/PlaywrightBrowserScenarioProvider.js";
|
||||||
import { PlaywrightScenarioBrowserCleanupOwner } from "../../../src/browser/PlaywrightScenarioBrowser.js";
|
import { PlaywrightScenarioBrowserCleanupOwner } from "../../src/browser/PlaywrightScenarioBrowser.js";
|
||||||
import { registerBrowserScenarioCommands } from "../../../src/cliBrowserScenarioCommands.js";
|
import { registerBrowserScenarioCommands } from "../../src/cliBrowserScenarioCommands.js";
|
||||||
import { sanitizeBrowserUrl } from "../../../src/domain/browserObservation.js";
|
import { sanitizeBrowserUrl } from "../../src/domain/browserObservation.js";
|
||||||
import {
|
import {
|
||||||
browserScenarioSchema,
|
browserScenarioSchema,
|
||||||
type BrowserScenario,
|
type BrowserScenario,
|
||||||
} from "../../../src/domain/browserScenario.js";
|
} from "../../src/domain/browserScenario.js";
|
||||||
import type { BrowserScenarioAction } from "../../../src/domain/browserScenarioValues.js";
|
import type { BrowserScenarioAction } from "../../src/domain/browserScenarioValues.js";
|
||||||
import { browserStepArtifactsSchema } from "../../../src/domain/browserScenarioCaptureValues.js";
|
import { browserStepArtifactsSchema } from "../../src/domain/browserScenarioCaptureValues.js";
|
||||||
import { silentLogger } from "../../../src/logger.js";
|
import { silentLogger } from "../../src/logger.js";
|
||||||
import {
|
import {
|
||||||
AnalysisCancelledError,
|
AnalysisCancelledError,
|
||||||
AnalysisTimeoutError,
|
AnalysisTimeoutError,
|
||||||
} from "../../../src/domain/analysisErrorCore.js";
|
} from "../../src/domain/analysisErrorCore.js";
|
||||||
import { BrowserObservationError } from "../../../src/domain/browserObservationError.js";
|
import { BrowserObservationError } from "../../src/domain/browserObservationError.js";
|
||||||
import { parseEvidence } from "../../../src/domain/evidence.js";
|
import { parseEvidence } from "../../src/domain/evidence.js";
|
||||||
import { jsonObjectSchema } from "../../../src/domain/jsonValue.js";
|
import { jsonObjectSchema } from "../../src/domain/jsonValue.js";
|
||||||
import { ok } from "../../../src/domain/result.js";
|
import { ok } from "../../src/domain/result.js";
|
||||||
|
|
||||||
const state = vi.hoisted(() => ({
|
const state = vi.hoisted(() => ({
|
||||||
provider: undefined as BrowserScenarioCapturePort | undefined,
|
provider: undefined as BrowserScenarioCapturePort | undefined,
|
||||||
}));
|
}));
|
||||||
vi.mock("../../../src/composition/browserScenario.js", () => ({
|
vi.mock("../../src/composition/browserScenario.js", () => ({
|
||||||
createBrowserScenarioProvider: () => state.provider,
|
createBrowserScenarioProvider: () => state.provider,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -69,12 +69,25 @@ const TEST_PROJECTS = [
|
|||||||
name: "boundary",
|
name: "boundary",
|
||||||
include: ["tests/boundary/**/*.test.ts"],
|
include: ["tests/boundary/**/*.test.ts"],
|
||||||
exclude: [
|
exclude: [
|
||||||
|
"tests/boundary/cli/**/*.test.ts",
|
||||||
"tests/boundary/mcp/**/*.test.ts",
|
"tests/boundary/mcp/**/*.test.ts",
|
||||||
"tests/boundary/process/**/*.test.ts",
|
"tests/boundary/process/**/*.test.ts",
|
||||||
],
|
],
|
||||||
pool: "forks" as const,
|
pool: "forks" as const,
|
||||||
maxWorkers: MAX_TEST_WORKERS,
|
maxWorkers: MAX_TEST_WORKERS,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "cli-boundary",
|
||||||
|
include: ["tests/boundary/cli/**/*.test.ts"],
|
||||||
|
pool: "forks" as const,
|
||||||
|
maxWorkers: MAX_TEST_WORKERS,
|
||||||
|
// CLI tests create fresh command instances or subprocesses and own their
|
||||||
|
// cleanup. Reuse the immutable graph; module mocks belong in process-global.
|
||||||
|
isolate: false,
|
||||||
|
// Long-lived workers should collect temporary command/schema allocations
|
||||||
|
// before their two heaps compete with the real CLI child processes.
|
||||||
|
execArgv: ["--max-old-space-size=384"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// Process-tree observations share host sampling resources; keep this small
|
// Process-tree observations share host sampling resources; keep this small
|
||||||
// lane serial while the independent projects run together.
|
// lane serial while the independent projects run together.
|
||||||
|
|||||||
Reference in New Issue
Block a user