diff --git a/src/application/ReconstructionObligationCandidates.test.ts b/src/application/ReconstructionObligationCandidates.test.ts index df7fc6e41e..cc15e6b290 100644 --- a/src/application/ReconstructionObligationCandidates.test.ts +++ b/src/application/ReconstructionObligationCandidates.test.ts @@ -19,7 +19,7 @@ import { PROCESS_PROVIDER } from "../domain/process/processEvidenceProvider.js"; import { parseProcessCapture } from "../domain/process/processCaptureParsing.js"; import { digestProcessCommitment, - parseProcessScenario, + processScenarioSchema, processComparisonContract, processScenarioCommitment, } from "../domain/process/processScenario.js"; @@ -169,7 +169,7 @@ describe("reconstruction obligation candidates", () => { }); it("does not bind an unknown process image to a packaged artifact obligation", () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "/path/whose-launch-identity-is-unknown", }); const base = emptyUnverifiedProcessCapture(); diff --git a/src/domain/process/processCapture.comparison.test.ts b/src/domain/process/processCapture.comparison.test.ts index 1ffb5d2f12..3882aa7714 100644 --- a/src/domain/process/processCapture.comparison.test.ts +++ b/src/domain/process/processCapture.comparison.test.ts @@ -1,6 +1,6 @@ import { expect, it } from "vitest"; import { - parseProcessScenario, + processScenarioSchema, processScenarioCommitment, processComparisonContract, digestProcessCommitment, @@ -332,7 +332,7 @@ it.each([ it("refuses mixed terminal observation versions even with PID and port rules disabled", () => { const base = emptyCapture(); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "/usr/bin/true", normalization: { pids: false, ports: false }, }); diff --git a/src/domain/process/processScenario.test.ts b/src/domain/process/processScenario.test.ts index 6c32e5b3b4..69141e5ff9 100644 --- a/src/domain/process/processScenario.test.ts +++ b/src/domain/process/processScenario.test.ts @@ -5,7 +5,6 @@ import { Ajv2020 } from "ajv/dist/2020.js"; import { SESSION_TOOL_CONTRACTS } from "../../contracts/sessionToolContracts.js"; import { digestProcessCommitment, - parseProcessScenario, PROCESS_TERMINAL_CELL_BUDGET, processComparisonContract, processScenarioCommitment, @@ -32,7 +31,7 @@ it("advertises the same unsupported PTY environment name as runtime admission", }); it("defaults the finalization interval to zero without changing committed identity", () => { - const scenario = parseProcessScenario(baseScenario); + const scenario = processScenarioSchema.parse(baseScenario); expect(scenario, "parsed scenario carries the default").toMatchObject({ finalization_ms: 0, @@ -49,13 +48,13 @@ it("defaults the finalization interval to zero without changing committed identi it("accepts an explicit zero finalization interval", () => { expect( - parseProcessScenario({ ...baseScenario, finalization_ms: 0 }), + processScenarioSchema.parse({ ...baseScenario, finalization_ms: 0 }), "zero is the immediate-kill default, not an invalid budget", ).toMatchObject({ finalization_ms: 0 }); }); it("commits a positive finalization interval in both identity projections", () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ ...baseScenario, finalization_ms: 500, }); @@ -74,14 +73,14 @@ it.each([-1, 1.5, Number.MAX_SAFE_INTEGER + 1])( "rejects the finalization interval %j", (finalization_ms) => { expect(() => - parseProcessScenario({ ...baseScenario, finalization_ms }), + processScenarioSchema.parse({ ...baseScenario, finalization_ms }), ).toThrow(); }, ); it("accepts a combined lifecycle budget up to the safe-integer limit", () => { const limit = Number.MAX_SAFE_INTEGER; - const accepted = parseProcessScenario({ + const accepted = processScenarioSchema.parse({ ...baseScenario, timeout_ms: limit - 100, idle_timeout_ms: 1, @@ -94,7 +93,7 @@ it("accepts a combined lifecycle budget up to the safe-integer limit", () => { "a total exactly at the representable limit is accepted", ).toBe(limit); expect( - parseProcessScenario(baseScenario), + processScenarioSchema.parse(baseScenario), "the default scenario stays far below the limit", ).toMatchObject({ timeout_ms: 30_000, settle_ms: 100, finalization_ms: 0 }); }); @@ -119,7 +118,11 @@ it.each([ ], ])("rejects %s with a representability message", (_label, budget) => { const parse = () => - parseProcessScenario({ ...baseScenario, idle_timeout_ms: 1, ...budget }); + processScenarioSchema.parse({ + ...baseScenario, + idle_timeout_ms: 1, + ...budget, + }); expect(parse, "the combined budget is rejected").toThrow( "timeout_ms + finalization_ms + settle_ms", @@ -130,7 +133,7 @@ it.each([ }); it("keeps scenario identity without finalization while versioning corrected port semantics", () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "/usr/bin/true", arguments: ["-x"], working_directory: "/tmp", @@ -172,7 +175,9 @@ it("keeps scenario identity without finalization while versioning corrected port }); it("admits the default and the exact combined terminal-cell budget", () => { - expect(parseProcessScenario({ executable: "/bin/true" }).terminal).toEqual({ + expect( + processScenarioSchema.parse({ executable: "/bin/true" }).terminal, + ).toEqual({ columns: 80, rows: 24, scrollback: 1_000, diff --git a/src/domain/process/processScenario.ts b/src/domain/process/processScenario.ts index 11af5318ca..2f5f8bd2f5 100644 --- a/src/domain/process/processScenario.ts +++ b/src/domain/process/processScenario.ts @@ -347,7 +347,3 @@ const eventsOutOfOrder = ( /** Parsed instructions and resource bounds for one process experiment. */ export type ProcessScenario = z.infer; - -/** Parse untrusted process scenario input and apply safe default budgets. */ -export const parseProcessScenario = (input: unknown): ProcessScenario => - processScenarioSchema.parse(input); diff --git a/src/process/capture/FilesystemCoverage.test.ts b/src/process/capture/FilesystemCoverage.test.ts index 809f0cd578..61bb62386a 100644 --- a/src/process/capture/FilesystemCoverage.test.ts +++ b/src/process/capture/FilesystemCoverage.test.ts @@ -10,7 +10,7 @@ import { } from "node:fs/promises"; import { join } from "node:path"; import { expect, it } from "vitest"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js"; import { snapshotRoots } from "./FilesystemSnapshot.js"; import { classifyFilesystemEffects } from "./ProcessFilesystemEffects.js"; @@ -27,7 +27,7 @@ it.each(["after", "before"] as const)( await writeFile(join(root, "a1.txt"), "first"); await writeFile(join(root, "a2.txt"), "second"); await writeFile(join(root, "z.txt"), "target"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -68,7 +68,7 @@ it("preserves proven deletion in an exhausted root while another root is partial await writeFile(join(complete, "removed.txt"), "removed"); await writeFile(join(partial, "first.txt"), "first"); await writeFile(join(partial, "second.txt"), "second"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [complete, partial], @@ -88,7 +88,7 @@ it("preserves proven deletion in an exhausted root while another root is partial it("distinguishes unavailable content hashes from completed path enumeration", async () => { const root = await createTestTempDirectory("rea-fs-hash-coverage-"); await writeFile(join(root, "removed.txt"), "larger than the byte budget"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -115,7 +115,7 @@ it.skipIf(process.platform === "win32")( await writeFile(visible, "visible"); await mkdir(blocked); await chmod(blocked, 0); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -155,7 +155,7 @@ it.skipIf(process.platform === "win32")( await writeFile(unreadable, "permission denied"); await writeFile(readable, "still observed"); await chmod(unreadable, 0); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -219,7 +219,7 @@ it.each([ const file = join(root, "b.txt"); await writeFile(file, "before"); if (beforeOmitted) await writeFile(budgetFile, "budget"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -255,7 +255,7 @@ it("preserves observed content and metadata changes without treating missing has const root = await createTestTempDirectory("rea-fs-observed-changes-"); for (const name of ["changed", "stable", "unhashed", "retyped"]) await writeFile(join(root, name), "before"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -276,7 +276,7 @@ it("preserves observed content and metadata changes without treating missing has expect(effects.find(({ path }) => path === "root_0:retyped")?.status).toBe( "modified", ); - const noHashes = parseProcessScenario({ + const noHashes = processScenarioSchema.parse({ ...scenario, limits: { file_bytes: 1 }, }); @@ -300,7 +300,7 @@ it.skipIf(process.platform === "win32")( const root = await createTestTempDirectory("rea-fs-mode-change-"); const file = join(root, "file"); await writeFile(file, "before", { mode: 0o600 }); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [file], @@ -324,7 +324,7 @@ it.skipIf(process.platform === "win32")( await writeFile(join(root, "b.txt"), "unused"); await symlink("a.txt", join(root, "stable-link")); await symlink("a.txt", join(root, "moved-link")); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -355,7 +355,7 @@ it.skipIf(process.platform === "win32")( // Equal length, so only the target spelling distinguishes the links; // "bbb" does not exist, so the replacement link is broken. await symlink("aaa/../target", join(root, "link")); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -381,7 +381,7 @@ it.skipIf(process.platform === "win32")( it("preserves creation when the selected root was observed missing before capture", async () => { const root = await createTestTempDirectory("rea-fs-missing-root-"); const file = join(root, "created.txt"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [file], @@ -410,7 +410,7 @@ it.skipIf(process.platform === "win32")( await mkdir(join(root, "denied")); await chmod(join(root, "denied"), 0); const scenarioFor = (path: string) => - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [path], @@ -480,7 +480,7 @@ it.skipIf(process.platform === "win32")( await writeFile(join(listed, "child.txt"), "child"); // Read without search permission: names enumerate, lookups are denied. await chmod(listed, 0o444); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -509,7 +509,7 @@ it.skipIf(process.platform === "win32")( "keeps an admitted root behind a symlink loop unobserved", async () => { const root = await createTestTempDirectory("rea-fs-root-loop-"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [join(root, "loop", "child")], @@ -532,7 +532,7 @@ it.skipIf(process.platform === "win32")( const link = join(root, "link"); await mkdir(target); await symlink(target, link); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, filesystem_observation_paths: [link], }); @@ -561,7 +561,7 @@ it.skipIf(process.platform === "win32")( it("allocates the observer directory before baseline and excludes it before entry accounting", async () => { const root = await createTestTempDirectory("rea-observer-filesystem-"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, filesystem_observation_paths: [root], limits: { files: 1 }, @@ -611,7 +611,7 @@ it.skipIf(process.platform === "win32")( "target", ); await symlink(physicalParent, alias); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, filesystem_observation_paths: [join(alias, "root")], }); diff --git a/src/process/capture/FilesystemRootAdmission.test.ts b/src/process/capture/FilesystemRootAdmission.test.ts index 4b1e0ba41a..ad7f280d8a 100644 --- a/src/process/capture/FilesystemRootAdmission.test.ts +++ b/src/process/capture/FilesystemRootAdmission.test.ts @@ -8,7 +8,7 @@ import { } from "../../domain/analysisErrorBase.js"; import { projectAnalysisError } from "../../domain/analysisErrorProjection.js"; import { emptyProcessCapture } from "../../domain/process/processCapture.fixture.js"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import { ProcessCaptureSnapshotFailure } from "./FilesystemSnapshot.js"; import { prepareProcessCapture } from "./ProcessCaptureLifecycle.js"; @@ -54,7 +54,7 @@ it.each(["EACCES", "EPERM"] as const)( snapshot, cleanupLeases: [lease], }); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, filesystem_observation_paths: ["/fixture/absent", selected], }); diff --git a/src/process/capture/ProcessCaptureLifecycle.test.ts b/src/process/capture/ProcessCaptureLifecycle.test.ts index cd6dc19a4c..d70e14c348 100644 --- a/src/process/capture/ProcessCaptureLifecycle.test.ts +++ b/src/process/capture/ProcessCaptureLifecycle.test.ts @@ -1,7 +1,7 @@ import { expect, it, vi } from "vitest"; import type { IPty } from "@lydell/node-pty"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import type { ProcessCaptureFinalization } from "../../domain/process/processCapture.js"; import { awaitTerminalExit } from "./ProcessCaptureLifecycle.js"; import type { ProcessTimer } from "./ProcessTimer.js"; @@ -75,7 +75,7 @@ const start = ( ) => awaitTerminalExit({ terminal: fake.terminal, - scenario: parseProcessScenario({ + scenario: processScenarioSchema.parse({ executable: "unused", idle_timeout_ms: 10_000, ...scenario, diff --git a/src/process/capture/ProcessCaptureObservation.test.ts b/src/process/capture/ProcessCaptureObservation.test.ts index b14135b652..e4acc0f188 100644 --- a/src/process/capture/ProcessCaptureObservation.test.ts +++ b/src/process/capture/ProcessCaptureObservation.test.ts @@ -8,7 +8,7 @@ import { buildCaptureResult } from "./ProcessCaptureLifecycle.js"; import { isInitializedPtyRoot } from "./ProcessSampling.js"; import { readLinuxChildren } from "./LinuxProcessSampling.js"; import { TerminalRenderer } from "./TerminalRenderer.js"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import type { ProcessCapture } from "../../domain/process/processCaptureParsing.js"; import type { FilesystemCoverage, @@ -143,7 +143,7 @@ it("preserves rendered observation order instead of timestamp sorting", () => { coverage: emptyFilesystemCoverage(), }, truncationDetails: truncationDetails([], renderedFrames, []), - scenario: parseProcessScenario(base), + scenario: processScenarioSchema.parse(base), rootPid: 1, samplingPartial: false, renderedFrames, @@ -179,7 +179,7 @@ it("marks redacted scripted input as an interaction unknown", () => { coverage: emptyFilesystemCoverage(), }, truncationDetails: truncationDetails([], [], []), - scenario: parseProcessScenario({ + scenario: processScenarioSchema.parse({ ...base, events: [{ type: "input", at_ms: 0, data: "secret", sensitive: true }], }), @@ -278,7 +278,7 @@ it("cancels filesystem snapshots before traversing declared roots", async () => const controller = new AbortController(); controller.abort(); const failure: unknown = await snapshotRoots( - parseProcessScenario({ + processScenarioSchema.parse({ ...base, filesystem_observation_paths: ["/tmp"], }), @@ -330,7 +330,7 @@ it.each(["symlink_not_followed", "observer_owned"] as const)( filesystem_before: coverage, filesystem_after: coverage, }, - scenario: parseProcessScenario({ + scenario: processScenarioSchema.parse({ ...base, filesystem_observation_paths: ["/selected"], }), diff --git a/src/process/capture/ProcessCaptureTerminalRetention.test.ts b/src/process/capture/ProcessCaptureTerminalRetention.test.ts index 22287233cd..5c55e057e0 100644 --- a/src/process/capture/ProcessCaptureTerminalRetention.test.ts +++ b/src/process/capture/ProcessCaptureTerminalRetention.test.ts @@ -1,7 +1,7 @@ import { expect, it } from "vitest"; import type { IPty } from "@lydell/node-pty"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js"; import { createProcessIdentifierLookup } from "./ProcessNormalization.js"; import type { @@ -19,7 +19,7 @@ it("omits an expanding chunk whole and retains a later smaller normalized chunk" return { dispose: () => undefined }; }, } as unknown as IPty; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", limits: { output_bytes: 1_000 }, normalization: { @@ -78,7 +78,7 @@ it.each([false, true])( return { dispose: () => undefined }; }, } as unknown as IPty; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", limits: { output_bytes: overBudget ? 4 : 1000 }, normalization: { @@ -147,7 +147,7 @@ it("retains PTY chunk boundaries when two output messages arrive fragmented", () return { dispose: () => undefined }; }, } as unknown as IPty; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", normalization: { paths: false, pids: false, ports: false }, }); diff --git a/src/process/capture/ProcessNormalization.test.ts b/src/process/capture/ProcessNormalization.test.ts index a8bc0daed5..cda8dc4f6c 100644 --- a/src/process/capture/ProcessNormalization.test.ts +++ b/src/process/capture/ProcessNormalization.test.ts @@ -7,7 +7,7 @@ import { normalizeProcessSamples, normalizeProcessText, } from "./ProcessNormalization.js"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; const rootPid = 41_010; const samples = Object.freeze( @@ -67,7 +67,7 @@ const scenario = (normalization: { readonly replacement: string; }[]; }) => - parseProcessScenario({ + processScenarioSchema.parse({ executable: "/usr/bin/node", working_directory: "/workspace", normalization: { @@ -294,7 +294,7 @@ it("reuses matchers while observing the terminal PID after launch", () => { }); it("keeps equal-path priority and replacement aliases local to each capture", () => { - const declared = parseProcessScenario({ + const declared = processScenarioSchema.parse({ executable: "/selected/tool", working_directory: "/selected", filesystem_observation_paths: ["/selected", ""], @@ -485,7 +485,7 @@ it("normalizes representative process identities and preserves null, zero, and u }); it("normalizes nested paths once using the most specific selected identity", () => { - const declared = parseProcessScenario({ + const declared = processScenarioSchema.parse({ executable: "/workspace/project/bin/program", working_directory: "/workspace/project", filesystem_observation_paths: [ @@ -507,7 +507,7 @@ it("normalizes nested paths once using the most specific selected identity", () }); it("treats path metacharacters literally while preferring nested observed roots", () => { - const declared = parseProcessScenario({ + const declared = processScenarioSchema.parse({ executable: "/selected/[tool]+", working_directory: "/selected", filesystem_observation_paths: [ @@ -529,7 +529,7 @@ it("treats path metacharacters literally while preferring nested observed roots" }); it("does not give a selected executable identity to a sibling filename", () => { - const declared = parseProcessScenario({ + const declared = processScenarioSchema.parse({ executable: "/tmp/process-paths/original/tool", working_directory: "/tmp/process-paths", normalization: { paths: true, pids: false, ports: false, patterns: [] }, diff --git a/src/process/capture/ProcessScenarioRuntimeValidation.test.ts b/src/process/capture/ProcessScenarioRuntimeValidation.test.ts index 77a43a7f2f..02418f4eb4 100644 --- a/src/process/capture/ProcessScenarioRuntimeValidation.test.ts +++ b/src/process/capture/ProcessScenarioRuntimeValidation.test.ts @@ -19,7 +19,7 @@ import { resolveExecutable, resolveProcessScenarioRuntimePaths, } from "./ProcessScenarioRuntimeValidation.js"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import { createTestTempDirectory } from "../../../tests/fixtures/temporaryDirectory.js"; it.skipIf(process.platform === "win32")( @@ -33,7 +33,7 @@ it.skipIf(process.platform === "win32")( await symlink(process.execPath, selected); await expect(resolveExecutable(command, root, bin)).resolves.toBe(selected); const resolved = await resolveProcessScenarioRuntimePaths( - parseProcessScenario({ + processScenarioSchema.parse({ executable: command, working_directory: root, environment: { PATH: bin }, @@ -64,7 +64,7 @@ it("resolves a Windows executable through the canonical PATH spelling", async () await mkdir(ambient); await writeFile(join(selected, "tool.exe"), ""); await chmod(join(selected, "tool.exe"), 0o644); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "tool.exe", working_directory: root, environment: { Path: selected }, @@ -200,12 +200,10 @@ const deniedFixture = async () => { return { root, denied, tool }; }; -const runtimePathOutcome = async ( - scenario: Parameters[0], -): Promise => { +const runtimePathOutcome = async (scenario: unknown): Promise => { try { return await resolveProcessScenarioRuntimePaths( - parseProcessScenario(scenario), + processScenarioSchema.parse(scenario), ); } catch (cause: unknown) { return cause; @@ -291,11 +289,13 @@ it.skipIf(SKIP_PERMISSIONS)( ); const runtimePathFailure = async ( - scenario: Parameters[0], + scenario: unknown, ): Promise => { let failure: unknown; try { - await resolveProcessScenarioRuntimePaths(parseProcessScenario(scenario)); + await resolveProcessScenarioRuntimePaths( + processScenarioSchema.parse(scenario), + ); } catch (cause: unknown) { failure = cause; } diff --git a/src/process/capture/ProcessTerminalObservation.test.ts b/src/process/capture/ProcessTerminalObservation.test.ts index b15f6e7529..3b6f1ec275 100644 --- a/src/process/capture/ProcessTerminalObservation.test.ts +++ b/src/process/capture/ProcessTerminalObservation.test.ts @@ -17,7 +17,7 @@ import { } from "./ProcessCaptureError.js"; import { AnalysisResourceConstraintError } from "../../domain/analysisErrorCore.js"; import { projectAnalysisError } from "../../domain/analysisErrorProjection.js"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import { createProcessCaptureObservationBuffer, resolveProcessResult, @@ -27,7 +27,7 @@ import { import { createProcessTerminalFinalizer } from "./ProcessTerminalObservation.js"; const createTerminalCleanupFixture = () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", terminal: { columns: 80, rows: 4 }, normalization: { paths: false, ports: false }, @@ -157,7 +157,7 @@ it("retains completed terminal facts and the typed capacity failure through fina state: "available", value: rendered, }); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", limits: { output_bytes: 4 }, }); diff --git a/src/process/capture/TerminalRenderer.test.ts b/src/process/capture/TerminalRenderer.test.ts index 32e37b4818..7bd1ff7fec 100644 --- a/src/process/capture/TerminalRenderer.test.ts +++ b/src/process/capture/TerminalRenderer.test.ts @@ -7,7 +7,7 @@ import { expect, it, vi } from "vitest"; import { TerminalRenderer } from "./TerminalRenderer.js"; import { ProcessCaptureResourceScope } from "./ProcessCaptureLifecycle.js"; import { createBoundedProcessTextNormalizer } from "./ProcessNormalization.js"; -import { parseProcessScenario } from "../../domain/process/processScenario.js"; +import { processScenarioSchema } from "../../domain/process/processScenario.js"; import type { BoundedProcessTextNormalization } from "./ProcessNormalization.js"; const require = createRequire(import.meta.url); @@ -128,7 +128,7 @@ it("omits rendered frames with unknown expanded size and keeps later bounded sta scrollback: 0, maxBytes: 1_000, normalize: createBoundedProcessTextNormalizer( - parseProcessScenario({ + processScenarioSchema.parse({ executable: "unused", normalization: { paths: false, @@ -259,7 +259,7 @@ it.each([1024, 2048])( scrollback: 0, maxBytes, normalize: createBoundedProcessTextNormalizer( - parseProcessScenario({ + processScenarioSchema.parse({ executable: "unused", normalization: { paths: false, pids: false, ports: false }, }), @@ -285,7 +285,7 @@ it.each([1024, 2048])( it("renders retained chunks once after late PID knowledge, preserving event times and resize order", async () => { let identifiers: readonly number[] = [100]; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", normalization: { paths: false, @@ -333,7 +333,7 @@ it("renders retained chunks once after late PID knowledge, preserving event time }); it("renders a bounded sequence of retained chunks and resizes", async () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "unused", normalization: { paths: false, ports: false, pids: true, patterns: [] }, }); diff --git a/tests/boundary/process/ProcessEvidence.host.test.ts b/tests/boundary/process/ProcessEvidence.host.test.ts index 8052ad7383..388361ea31 100644 --- a/tests/boundary/process/ProcessEvidence.host.test.ts +++ b/tests/boundary/process/ProcessEvidence.host.test.ts @@ -3,7 +3,7 @@ import { expect, it } from "vitest"; import { emptyUnverifiedProcessCapture } from "../../../src/domain/process/processCapture.fixture.js"; import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { createProcessCaptureEvidence } from "../../../src/application/process/ProcessEvidence.js"; import { observeSettlement } from "../../../src/process/capture/ProcessCaptureLifecycle.js"; @@ -14,7 +14,7 @@ it.each([ ] as const)( "interprets the executable name using the captured %s host", (platform, expectedName) => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "/fixtures/directory\\program.exe", working_directory: process.cwd(), events: [], @@ -32,7 +32,7 @@ it.each([ ); it("stamps process Evidence from the capture manifest host", () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: process.cwd(), events: [], diff --git a/tests/boundary/process/ProcessEvidence.test.ts b/tests/boundary/process/ProcessEvidence.test.ts index c7bd0ccaf6..3528dbe871 100644 --- a/tests/boundary/process/ProcessEvidence.test.ts +++ b/tests/boundary/process/ProcessEvidence.test.ts @@ -14,13 +14,13 @@ import { compareProcessCaptures } from "../../../src/domain/process/processCompa import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js"; import { digestProcessCommitment, - parseProcessScenario, + processScenarioSchema, processComparisonContract, processScenarioCommitment, } from "../../../src/domain/process/processScenario.js"; const captureEvidenceForSensitiveInput = (data: string) => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "/bin/echo", working_directory: "/tmp", events: [{ type: "input", at_ms: 0, data, sensitive: true }], @@ -60,7 +60,7 @@ const captureEvidenceForSensitiveInput = (data: string) => { }; const captureEvidenceForEnvironmentSecret = async (value: string) => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: "/bin/echo", working_directory: "/tmp", environment: { API_TOKEN: value }, diff --git a/tests/boundary/process/processCaptureCallerReason.test.ts b/tests/boundary/process/processCaptureCallerReason.test.ts index d201e7fbd1..615b5f1bbf 100644 --- a/tests/boundary/process/processCaptureCallerReason.test.ts +++ b/tests/boundary/process/processCaptureCallerReason.test.ts @@ -1,6 +1,6 @@ import { expect } from "vitest"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { captureProcessScenario } from "../../../src/process/capture/ProcessHarness.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { itWithCaptureCapability } from "./processCaptureCapability.js"; @@ -13,7 +13,7 @@ itWithCaptureCapability( const reason = { request: "cancel after cleanup completed" }; let cleanupReported = false; const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: ["--eval", "console.log('completed capture')"], working_directory: root, diff --git a/tests/boundary/process/processCaptureLifecycle.test.ts b/tests/boundary/process/processCaptureLifecycle.test.ts index 10c92357c1..ad1cf560a2 100644 --- a/tests/boundary/process/processCaptureLifecycle.test.ts +++ b/tests/boundary/process/processCaptureLifecycle.test.ts @@ -29,7 +29,7 @@ import { observeLaunchedExecutable, observeSelectedExecutable, } from "../../../src/process/capture/ProcessCaptureLifecycle.js"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { emptyProcessCapture } from "../../../src/domain/process/processCapture.fixture.js"; import { processSourceTruncated } from "../../../src/domain/process/processCaptureCoverage.js"; import type { ProcessCapture } from "../../../src/domain/process/processCaptureParsing.js"; @@ -140,7 +140,7 @@ itWithCaptureCapability( await mkdir(join(root, "reports")); await writeFile(join(root, "reports", "final.json"), payload); const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [ "-e", @@ -187,7 +187,7 @@ itWithCaptureCapability( }, 10_000); try { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "hang"], working_directory: dirname(processFixture), @@ -226,7 +226,7 @@ itWithCaptureCapability( vi.setSystemTime(new Date("2026-01-02T00:00:00.000Z")); try { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "partial"], working_directory: dirname(processFixture), @@ -282,7 +282,7 @@ itWithCaptureCapability( let unownedPid: number | undefined; try { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "detached-cleanup", pidMarker], working_directory: root, @@ -374,7 +374,7 @@ itWithCaptureCapability( rm(path, { recursive: true, force: true }), }; const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "partial"], working_directory: dirname(processFixture), @@ -492,7 +492,7 @@ itWithCaptureCapability( .digest("hex"); try { const capturePromise = captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable, arguments: [processFixture, "ready-hang", readyMarker], working_directory: root, @@ -541,7 +541,7 @@ itWithCaptureCapability( await symlink("/etc/passwd", join(root, "escape")); try { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: "/usr/bin/true", working_directory: root, filesystem_observation_paths: [root], @@ -578,7 +578,7 @@ itWithCaptureCapability( "distinguishes timeout from cancellation and cleans both runs", async () => { const timedOut = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "hang"], working_directory: dirname(processFixture), @@ -606,7 +606,7 @@ itWithCaptureCapability( const controller = new AbortController(); let reachedRunning = false; const cancelled = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "hang"], working_directory: dirname(processFixture), @@ -665,7 +665,7 @@ const captureFinalizationFixture = async ( ): Promise<{ readonly result: CaptureRun; readonly root: string }> => { const root = await createTestTempDirectory("rea-finalization-"); const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [finalizationFixture, mode, root], working_directory: root, @@ -958,7 +958,7 @@ itWithCaptureCapability( }; const root = await createTestTempDirectory("rea-finalization-host-"); const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [finalizationFixture, "ignoring", root], working_directory: root, @@ -1032,7 +1032,7 @@ itWithCaptureCapability( }); const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [path], @@ -1066,7 +1066,7 @@ itWithCaptureCapability( return snapshot; }; const resultPromise = captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [snapshotCancellationFixture, root], working_directory: dirname(snapshotCancellationFixture), @@ -1116,7 +1116,7 @@ itWithCaptureCapability( }; const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [join(obstruction, "child")], @@ -1139,7 +1139,7 @@ itWithCaptureCapability( "captures input, Unicode, and resize across PTY startup", async () => { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "interactive"], working_directory: dirname(processFixture), @@ -1177,7 +1177,7 @@ itWithCaptureCapability( "dispatches an external signal without depending on child startup output", async () => { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "hang"], working_directory: dirname(processFixture), @@ -1202,7 +1202,7 @@ itWithCaptureCapability( "buffers newline input until a silent PTY fixture is ready to read it", async () => { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "silent-interactive"], working_directory: dirname(processFixture), @@ -1238,7 +1238,7 @@ itWithCaptureCapability( "samples and cleans a source-owned child and grandchild process tree", async () => { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, "tree"], working_directory: dirname(processFixture), diff --git a/tests/boundary/process/processCaptureNormalization.test.ts b/tests/boundary/process/processCaptureNormalization.test.ts index ade22f8816..91ec59bf56 100644 --- a/tests/boundary/process/processCaptureNormalization.test.ts +++ b/tests/boundary/process/processCaptureNormalization.test.ts @@ -8,7 +8,7 @@ import { captureProcessScenario } from "../../../src/process/capture/ProcessHarn import { createProcessCaptureEvidence } from "../../../src/application/process/ProcessEvidence.js"; import { digestProcessCommitment, - parseProcessScenario, + processScenarioSchema, } from "../../../src/domain/process/processScenario.js"; import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js"; import { compareProcessCaptures } from "../../../src/domain/process/processComparison.js"; @@ -37,7 +37,7 @@ itWithCaptureCapability( const command = "selected\\node"; const selected = join(bin, command); await symlink(process.execPath, selected); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: command, working_directory: root, environment: { PATH: bin }, @@ -69,7 +69,7 @@ itWithCaptureCapability( score: 20, }); const original = `${report}\nlisten:8080\n`; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, arguments: ["-e", `process.stdout.write(${JSON.stringify(original)})`], @@ -119,7 +119,7 @@ itWithCaptureCapability.each([ "preserves literal replacement $replacement and rejects legacy comparison semantics", async ({ pattern, replacement, expected }) => { const root = await createTestTempDirectory("rea-process-literal-"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, arguments: ["-e", 'process.stdout.write("AB")'], working_directory: root, @@ -173,7 +173,7 @@ itWithLinuxCaptureCapability.each([false, true])( async (pids) => { const root = await createTestTempDirectory("rea-process-identifiers-"); const identityPath = join(root, "identity.json"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, arguments: [processFixture, identityPath], working_directory: root, @@ -241,7 +241,7 @@ itWithCaptureCapability( await symlink(process.execPath, executable); await mkdir(observed); const original = `${executable}\n${observed}/result\n${root}/log`; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable, working_directory: root, filesystem_observation_paths: [observed], @@ -317,7 +317,7 @@ itWithCaptureCapability( await mkdir(join(root, "original"), { recursive: true }); await symlink(process.execPath, executable); const sibling = `${executable}-helper`; - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable, working_directory: root, arguments: ["-e", `process.stdout.write(${JSON.stringify(sibling)})`], @@ -339,7 +339,7 @@ itWithCaptureCapability.each([false, true])( "normalizes a sampled child in raw and rendered terminal projections, pids=%s", async (pids) => { const root = await createTestTempDirectory("rea-sampled-terminal-pids-"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, arguments: [ diff --git a/tests/boundary/process/processCaptureTerminal.test.ts b/tests/boundary/process/processCaptureTerminal.test.ts index 880c8d868a..79d17023b0 100644 --- a/tests/boundary/process/processCaptureTerminal.test.ts +++ b/tests/boundary/process/processCaptureTerminal.test.ts @@ -5,13 +5,13 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { itWithCaptureCapability } from "./processCaptureCapability.js"; import { captureProcessScenario } from "../../../src/process/capture/ProcessHarness.js"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; itWithCaptureCapability( "normalizes wide terminal cells without inventing blank cells", async () => { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: ["-e", 'process.stdout.write("界")'], terminal: { columns: 4, rows: 1, scrollback: 0 }, @@ -54,7 +54,7 @@ itWithCaptureCapability( ); try { const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: [script], working_directory: root, diff --git a/tests/boundary/process/processFilesystemCoverageAdapters.test.ts b/tests/boundary/process/processFilesystemCoverageAdapters.test.ts index 9ded590b07..086b38ca8e 100644 --- a/tests/boundary/process/processFilesystemCoverageAdapters.test.ts +++ b/tests/boundary/process/processFilesystemCoverageAdapters.test.ts @@ -16,7 +16,7 @@ import { analysisCliErrorEnvelopeSchema } from "../../../src/contracts/errorSche import { parseEvidence } from "../../../src/domain/evidence.js"; import { compareProcessCaptures } from "../../../src/domain/process/processComparison.js"; import { parseProcessCapture } from "../../../src/domain/process/processCaptureParsing.js"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { FINALIZED_PROCESS_CAPTURE_EXAMPLE } from "../../../src/domain/process/processCaptureExample.js"; import { createServer } from "../../../src/server/createServer.js"; import { createTestBinarySession } from "../../fixtures/binarySession.js"; @@ -207,7 +207,7 @@ it("documents a finalization scenario and exit record that match the contract", throw new Error("Missing finalization examples"); expect( - parseProcessScenario(JSON.parse(scenario)).finalization_ms, + processScenarioSchema.parse(JSON.parse(scenario)).finalization_ms, "the documented scenario is accepted and carries the interval", ).toBe(1_500); expect( @@ -225,7 +225,7 @@ itWithCaptureCapability.each(["cli", "mcp"] as const)( ?.match(/```json\n([\s\S]*?)\n```/u)?.[1]; if (example === undefined) throw new Error("Missing report capture example"); - const scenario = parseProcessScenario(JSON.parse(example)); + const scenario = processScenarioSchema.parse(JSON.parse(example)); const root = await createTestTempDirectory("rea-full-report-adapter-"); const evidence = await (adapter === "cli" ? captureViaCli : captureViaMcp)({ ...scenario, diff --git a/tests/boundary/process/processHostIdentity.test.ts b/tests/boundary/process/processHostIdentity.test.ts index 24fa5886f0..db84d1c392 100644 --- a/tests/boundary/process/processHostIdentity.test.ts +++ b/tests/boundary/process/processHostIdentity.test.ts @@ -1,7 +1,7 @@ import { ProcessOwnershipEvidenceOwner } from "../../../src/process/ProcessOwnershipEvidence.js"; import { expect, it } from "vitest"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { createRunManifest, observeLaunchedExecutable, @@ -10,7 +10,7 @@ import { } from "../../../src/process/capture/ProcessCaptureLifecycle.js"; it("uses one selected host identity for manifest and settlement", async () => { - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: process.cwd(), events: [], diff --git a/tests/boundary/process/processPreparation.test.ts b/tests/boundary/process/processPreparation.test.ts index 153c2cba07..293f91d2b6 100644 --- a/tests/boundary/process/processPreparation.test.ts +++ b/tests/boundary/process/processPreparation.test.ts @@ -9,7 +9,7 @@ import { snapshotRoots, } from "../../../src/process/capture/FilesystemSnapshot.js"; import { prepareProcessCapture } from "../../../src/process/capture/ProcessCaptureLifecycle.js"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { emptyProcessCapture } from "../../../src/domain/process/processCapture.fixture.js"; const emptyFilesystemCoverage = @@ -28,7 +28,7 @@ it("prepares ownership inspection before snapshotting or allocating a target run await expect( prepareProcessCapture( - parseProcessScenario({ + processScenarioSchema.parse({ executable: "/bin/true", working_directory: "/tmp", }), @@ -59,7 +59,7 @@ it("cleans the temporary root when cancellation arrives during identity capture" await expect( prepareProcessCapture( - parseProcessScenario({ + processScenarioSchema.parse({ executable: "/bin/true", working_directory: "/tmp", }), @@ -98,7 +98,7 @@ it.each([false, true])( if (failing) throw new Error("controlled temporary-root removal denial"); }); const observed = await prepareProcessCapture( - parseProcessScenario({ + processScenarioSchema.parse({ executable: "/bin/true", filesystem_observation_paths: [path], }), diff --git a/tests/boundary/process/processSnapshotHandleOwnership.test.ts b/tests/boundary/process/processSnapshotHandleOwnership.test.ts index 37e33060fb..3df77631ff 100644 --- a/tests/boundary/process/processSnapshotHandleOwnership.test.ts +++ b/tests/boundary/process/processSnapshotHandleOwnership.test.ts @@ -74,7 +74,7 @@ vi.mock("node:fs/promises", async (importOriginal) => { }); import { AnalysisCleanupLease } from "../../../src/artifacts/AnalysisCleanupLease.js"; -import { parseProcessScenario } from "../../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../../src/domain/process/processScenario.js"; import { hashFile, snapshotRoots, @@ -97,7 +97,7 @@ type DirectoryReadCallback = ( type DirectoryCloseCallback = (error?: NodeJS.ErrnoException | null) => void; const scenarioFor = (root: string) => - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], diff --git a/tests/process-global/filesystemSnapshotFallbackCancellation.test.ts b/tests/process-global/filesystemSnapshotFallbackCancellation.test.ts index 3370fa4d42..cfe1d7ab65 100644 --- a/tests/process-global/filesystemSnapshotFallbackCancellation.test.ts +++ b/tests/process-global/filesystemSnapshotFallbackCancellation.test.ts @@ -54,7 +54,7 @@ vi.mock("node:fs/promises", async (importOriginal) => { }; }); -import { parseProcessScenario } from "../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../src/domain/process/processScenario.js"; import { hashFile, snapshotRoots, @@ -94,7 +94,7 @@ it.each(["hash", "snapshot"] as const)( operation === "hash" ? hashFile(path, expected, 1_000, controller.signal) : snapshotRoots( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, working_directory: directory, filesystem_observation_paths: [path], diff --git a/tests/process-global/filesystemSnapshotRaces.test.ts b/tests/process-global/filesystemSnapshotRaces.test.ts index bc216dd2e8..7a82870747 100644 --- a/tests/process-global/filesystemSnapshotRaces.test.ts +++ b/tests/process-global/filesystemSnapshotRaces.test.ts @@ -104,7 +104,7 @@ vi.mock("node:fs/promises", async (importOriginal) => { }); import { - parseProcessScenario, + processScenarioSchema, type ProcessScenario, } from "../../src/domain/process/processScenario.js"; import { classifyFilesystemEffects } from "../../src/process/capture/ProcessFilesystemEffects.js"; @@ -178,7 +178,7 @@ const entryUnavailable = async ( const link = join(root, "z-link"); await writeFile(sibling, "retain this sibling"); await symlink("missing-target", link); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -240,7 +240,7 @@ it.skipIf(process.platform === "win32")( const link = join(root, "z-link"); await writeFile(sibling, "retain this sibling"); await symlink("original-target", link); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -275,7 +275,7 @@ it("retains siblings and marks child absence unknown when directory revalidation await writeFile(sibling, "retain this sibling"); await mkdir(directory); await writeFile(join(directory, "child"), "child observed before race"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -309,7 +309,7 @@ it.skipIf(process.platform === "win32")( withTemporaryRoot("rea-snapshot-cancel-race-", async (root) => { const link = join(root, "link"); await symlink("missing-target", link); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -330,7 +330,7 @@ it.skipIf(process.platform === "win32")( withTemporaryRoot("rea-snapshot-cancel-missing-", async (root) => { const link = join(root, "link"); await symlink("missing-target", link); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], @@ -350,7 +350,7 @@ it("observes cancellation after the selected directory handle closes", async () const directory = join(root, "selected"); await mkdir(directory); await writeFile(join(directory, "child"), "observed child"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [directory], @@ -374,7 +374,7 @@ it("releases buffered names after a failed directory revalidation before visitin await writeFile(join(firstRoot, "a-child"), "first"); await writeFile(join(firstRoot, "b-child"), "second"); await writeFile(join(secondRoot, "child"), "retain this root"); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: parent, filesystem_observation_paths: [firstRoot, secondRoot], @@ -398,7 +398,7 @@ it.skipIf(process.platform === "win32")( withTemporaryRoot("rea-snapshot-eio-control-", async (root) => { const link = join(root, "link"); await symlink("missing-target", link); - const scenario = parseProcessScenario({ + const scenario = processScenarioSchema.parse({ executable: process.execPath, working_directory: root, filesystem_observation_paths: [root], diff --git a/tests/process-global/processPrelaunchCancellation.test.ts b/tests/process-global/processPrelaunchCancellation.test.ts index a8e4bab411..fa4a968d48 100644 --- a/tests/process-global/processPrelaunchCancellation.test.ts +++ b/tests/process-global/processPrelaunchCancellation.test.ts @@ -2,7 +2,7 @@ import { rm, stat, type FileHandle } from "node:fs/promises"; import { afterEach, expect, it, vi } from "vitest"; import { captureProcessScenario } from "../../src/process/capture/ProcessHarness.js"; -import { parseProcessScenario } from "../../src/domain/process/processScenario.js"; +import { processScenarioSchema } from "../../src/domain/process/processScenario.js"; import { emptyProcessCapture } from "../../src/domain/process/processCapture.fixture.js"; const control = vi.hoisted(() => ({ @@ -100,7 +100,7 @@ it.each(["none", "before", "open", "final-stat", "close"] as const)( if (stage === "before") controller.abort(reason); const removed: string[] = []; const result = await captureProcessScenario( - parseProcessScenario({ + processScenarioSchema.parse({ executable: process.execPath, arguments: ["--eval", "process.exit(0)"], working_directory: process.cwd(),