diff --git a/scripts/test-parallel.mjs b/scripts/test-parallel.mjs index 9add62dfc7d..1572d174852 100644 --- a/scripts/test-parallel.mjs +++ b/scripts/test-parallel.mjs @@ -117,7 +117,7 @@ if (rawCli.showHelp) { " --plan Print the resolved execution plan and exit", " --ci-manifest Print the planner-backed CI execution manifest as JSON and exit", " --explain Explain how a file is classified and run, then exit", - " --surface Select a surface: unit, extensions, channels, gateway", + " --surface Select a surface: unit, extensions, channels, contracts, gateway", " --files Add targeted files or path patterns (repeatable)", " --mode Override runtime mode", " --profile Override execution intent: normal, max, serial", diff --git a/scripts/test-planner/planner.mjs b/scripts/test-planner/planner.mjs index 651ea22fbcd..a363a6d7196 100644 --- a/scripts/test-planner/planner.mjs +++ b/scripts/test-planner/planner.mjs @@ -97,13 +97,13 @@ const normalizeSurfaces = (values = []) => [ ), ]; -const EXPLICIT_PLAN_SURFACES = new Set(["unit", "extensions", "channels", "gateway"]); +const EXPLICIT_PLAN_SURFACES = new Set(["unit", "extensions", "channels", "contracts", "gateway"]); const validateExplicitSurfaces = (surfaces) => { const invalidSurfaces = surfaces.filter((surface) => !EXPLICIT_PLAN_SURFACES.has(surface)); if (invalidSurfaces.length > 0) { throw new Error( - `Unsupported --surface value(s): ${invalidSurfaces.join(", ")}. Supported surfaces: unit, extensions, channels, gateway.`, + `Unsupported --surface value(s): ${invalidSurfaces.join(", ")}. Supported surfaces: unit, extensions, channels, contracts, gateway.`, ); } }; @@ -125,6 +125,9 @@ const buildRequestedSurfaces = (request, env) => { if (env.OPENCLAW_TEST_INCLUDE_CHANNELS === "1") { surfaces.push("channels"); } + if (env.OPENCLAW_TEST_INCLUDE_CONTRACTS === "1") { + surfaces.push("contracts"); + } if (env.OPENCLAW_TEST_INCLUDE_GATEWAY === "1") { surfaces.push("gateway"); } @@ -288,6 +291,9 @@ const resolveMaxWorkersForUnit = (unit, context) => { if (unit.surface === "channels") { return budget.channelSharedWorkers ?? budget.unitSharedWorkers; } + if (unit.surface === "contracts") { + return budget.unitSharedWorkers; + } if (unit.surface === "gateway") { return budget.gatewayWorkers; } @@ -383,6 +389,7 @@ const buildDefaultUnits = (context, request) => { const selectedSurfaceSet = new Set(selectedSurfaces); const unitOnlyRun = selectedSurfaceSet.size === 1 && selectedSurfaceSet.has("unit"); const channelsOnlyRun = selectedSurfaceSet.size === 1 && selectedSurfaceSet.has("channels"); + const contractsOnlyRun = selectedSurfaceSet.size === 1 && selectedSurfaceSet.has("contracts"); const extensionsOnlyRun = selectedSurfaceSet.size === 1 && selectedSurfaceSet.has("extensions"); const { @@ -612,6 +619,19 @@ const buildDefaultUnits = (context, request) => { } } + if (selectedSurfaceSet.has("contracts")) { + units.push( + createExecutionUnit(context, { + id: "contracts", + surface: "contracts", + isolate: false, + serialPhase: contractsOnlyRun ? undefined : "contracts", + args: ["vitest", "run", "--config", "vitest.contracts.config.ts", ...noIsolateArgs], + reasons: ["contracts-shared"], + }), + ); + } + if (selectedSurfaceSet.has("extensions")) { for (const file of catalog.extensionForkIsolatedFiles) { units.push( diff --git a/test/scripts/test-parallel.test.ts b/test/scripts/test-parallel.test.ts index 1330210faa7..3d8d6e0691a 100644 --- a/test/scripts/test-parallel.test.ts +++ b/test/scripts/test-parallel.test.ts @@ -483,6 +483,13 @@ describe("scripts/test-parallel lane planning", () => { ); }); + it("supports the explicit contracts surface", () => { + const output = runPlannerPlan(["--plan", "--surface", "contracts"]); + + expect(output).toContain("contracts filters=all"); + expect(output).toContain("surface=contracts"); + }); + it("rejects wrapper --files values that look like options", () => { expect(() => runPlannerPlan(["--plan", "--files", "--config"])).toThrowError( /Invalid --files value/u,