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
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@

import { describe, expect, it } from "vitest";

import {
createSession,
filterSafeUpdates,
MACHINE_SNAPSHOT_VERSION,
normalizeSession,
type Session,
type SessionUpdates,
} from "../../../state/onboard-session";
import type { OnboardFlowContext } from "../flow-context";
import { advanceTo, completeOnboardMachine } from "../result";
import { OnboardRuntime, type OnboardRuntimeDeps } from "../runtime";
Expand All @@ -22,6 +14,18 @@ import {
createPoliciesPhase,
createPostVerifyPhase,
} from "./agent-policy-finalization";
import {
MACHINE_SNAPSHOT_VERSION,
type Session,
type SessionUpdates,
cloneSession,
createSession,
createTestRuntime,
} from "../../../../../test/helpers/onboard-machine-runtime-fixture";

function createRuntime(initialSession: Session = createSession()) {
return createTestRuntime(initialSession, { now: () => "2026-05-29T00:00:00.000Z" });
}

function context(): OnboardFlowContext<null, null, null> {
return {
Expand Down Expand Up @@ -52,51 +56,6 @@ function context(): OnboardFlowContext<null, null, null> {
};
}

function cloneSession(session: Session): Session {
return normalizeSession(JSON.parse(JSON.stringify(session))) ?? session;
}

function createRuntime(initialSession: Session = createSession()) {
let session = cloneSession(initialSession);
const updateSession = (mutator: (value: Session) => Session | void): Session => {
session = cloneSession(mutator(cloneSession(session)) ?? session);
return cloneSession(session);
};
const deps: OnboardRuntimeDeps = {
loadSession: () => cloneSession(session),
createSession,
saveSession: (next) => {
session = cloneSession(next);
return cloneSession(session);
},
updateSession,
markStepStarted: () => cloneSession(session),
markStepComplete: (_stepName, updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
return current;
}),
markStepSkipped: () => cloneSession(session),
markStepFailed: (stepName, message) =>
updateSession((current) => {
current.steps[stepName].status = "failed";
current.steps[stepName].error = message ?? null;
return current;
}),
completeSession: (updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
current.status = "complete";
current.resumable = false;
return current;
}),
filterSafeUpdates,
emitEvent: () => undefined,
now: () => "2026-05-29T00:00:00.000Z",
};
return new OnboardRuntime(deps);
}

describe("agent/policy/finalization phases", () => {
it("creates branch-specific setup phases", async () => {
const agentPhase = createAgentSetupPhase(async () => ({ result: advanceTo("policies") }));
Expand Down
65 changes: 12 additions & 53 deletions src/lib/onboard/machine/flow-sequence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,24 @@

import { describe, expect, it } from "vitest";

import {
createSession,
filterSafeUpdates,
MACHINE_SNAPSHOT_VERSION,
normalizeSession,
type Session,
type SessionUpdates,
} from "../../state/onboard-session";
import type { OnboardFlowContext, OnboardFlowPhaseResult } from "./flow-context";
import { onboardFlowPhaseResult } from "./flow-context";
import { buildOnboardFlowPhaseSequence } from "./flow-sequence";
import { advanceTo, branchTo, completeOnboardMachine } from "./result";
import { OnboardRuntime, type OnboardRuntimeDeps } from "./runtime";
import { runOnboardSequenceWithRunner } from "./sequence-runner";
import {
MACHINE_SNAPSHOT_VERSION,
type Session,
type SessionUpdates,
cloneSession,
createSession,
createTestRuntime,
} from "../../../../test/helpers/onboard-machine-runtime-fixture";

function createRuntime(initialSession: Session = createSession()) {
return createTestRuntime(initialSession, { now: () => "2026-05-29T00:00:00.000Z" });
}

type Context = OnboardFlowContext<null, { type: string }, { mode: string }>;

Expand Down Expand Up @@ -57,51 +61,6 @@ function result(
return onboardFlowPhaseResult(ctx, advanceTo(next));
}

function cloneSession(session: Session): Session {
return normalizeSession(JSON.parse(JSON.stringify(session))) ?? session;
}

function createRuntime(initialSession: Session = createSession()) {
let session = cloneSession(initialSession);
const updateSession = (mutator: (value: Session) => Session | void): Session => {
session = cloneSession(mutator(cloneSession(session)) ?? session);
return cloneSession(session);
};
const deps: OnboardRuntimeDeps = {
loadSession: () => cloneSession(session),
createSession,
saveSession: (next) => {
session = cloneSession(next);
return cloneSession(session);
},
updateSession,
markStepStarted: () => cloneSession(session),
markStepComplete: (_stepName, updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
return current;
}),
markStepSkipped: () => cloneSession(session),
markStepFailed: (stepName, message) =>
updateSession((current) => {
current.steps[stepName].status = "failed";
current.steps[stepName].error = message ?? null;
return current;
}),
completeSession: (updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
current.status = "complete";
current.resumable = false;
return current;
}),
filterSafeUpdates,
emitEvent: () => undefined,
now: () => "2026-05-29T00:00:00.000Z",
};
return new OnboardRuntime(deps);
}

describe("onboard flow phase sequence", () => {
it("assembles phases in machine order", () => {
const phases = buildOnboardFlowPhaseSequence<Context>({
Expand Down
20 changes: 8 additions & 12 deletions src/lib/onboard/machine/flow-slices.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@

import { describe, expect, it } from "vitest";

import {
createSession,
filterSafeUpdates,
MACHINE_SNAPSHOT_VERSION,
normalizeSession,
type Session,
type SessionUpdates,
} from "../../state/onboard-session";
import type { OnboardFlowContext } from "./flow-context";
import {
coreOnboardFlowPhases,
Expand All @@ -23,10 +15,14 @@ import {
import { advanceTo, branchTo, completeOnboardMachine } from "./result";
import { OnboardRuntime, type OnboardRuntimeDeps } from "./runtime";
import type { OnboardSequencePhase } from "./sequence-runner";

function cloneSession(session: Session): Session {
return normalizeSession(JSON.parse(JSON.stringify(session))) ?? session;
}
import {
MACHINE_SNAPSHOT_VERSION,
type Session,
type SessionUpdates,
cloneSession,
createSession,
filterSafeUpdates,
} from "../../../../test/helpers/onboard-machine-runtime-fixture";

function runtime(initialSession: Session = createSession()) {
let session = cloneSession(initialSession);
Expand Down
62 changes: 8 additions & 54 deletions src/lib/onboard/machine/runner-sequence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@

import { describe, expect, it, vi } from "vitest";

import {
createSession,
filterSafeUpdates,
MACHINE_SNAPSHOT_VERSION,
normalizeSession,
type Session,
type SessionUpdates,
} from "../../state/onboard-session";
import { advanceTo, branchTo, completeOnboardMachine, failOnboardMachine, retryTo } from "./result";
import {
EmptyOnboardStateHandlerResultError,
Expand All @@ -21,58 +13,20 @@ import {
runOnboardMachine,
} from "./runner";
import { OnboardRuntime, type OnboardRuntimeDeps } from "./runtime";
import {
MACHINE_SNAPSHOT_VERSION,
type Session,
type SessionUpdates,
cloneSession,
createSession,
createTestRuntime as createRuntime,
} from "../../../../test/helpers/onboard-machine-runtime-fixture";

interface RunnerContext {
attempts: number;
visited: string[];
}

function cloneSession(session: Session): Session {
return normalizeSession(JSON.parse(JSON.stringify(session))) ?? session;
}

function createRuntime(initialSession: Session = createSession()) {
let session = cloneSession(initialSession);
const updateSession = (mutator: (value: Session) => Session | void): Session => {
const next = mutator(cloneSession(session)) ?? session;
session = cloneSession(next);
return cloneSession(session);
};
const deps: OnboardRuntimeDeps = {
loadSession: () => cloneSession(session),
createSession,
saveSession: (next) => {
session = cloneSession(next);
return cloneSession(session);
},
updateSession,
markStepStarted: () => cloneSession(session),
markStepComplete: (_stepName, updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
return current;
}),
markStepSkipped: () => cloneSession(session),
markStepFailed: (stepName, message) =>
updateSession((current) => {
current.steps[stepName].status = "failed";
current.steps[stepName].error = message ?? null;
return current;
}),
completeSession: (updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
current.status = "complete";
current.resumable = false;
return current;
}),
filterSafeUpdates,
emitEvent: () => undefined,
now: () => "2026-05-28T00:00:00.000Z",
};
return new OnboardRuntime(deps);
}

describe("runOnboardMachine result sequences", () => {
it("runs handlers until completion while applying multiple results in order", async () => {
const runtime = createRuntime();
Expand Down
62 changes: 8 additions & 54 deletions src/lib/onboard/machine/runner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@

import { describe, expect, it, vi } from "vitest";

import {
createSession,
filterSafeUpdates,
MACHINE_SNAPSHOT_VERSION,
normalizeSession,
type Session,
type SessionUpdates,
} from "../../state/onboard-session";
import {
advanceTo,
branchTo,
Expand All @@ -26,58 +18,20 @@ import {
runOnboardMachine,
} from "./runner";
import { OnboardRuntime, type OnboardRuntimeDeps } from "./runtime";
import {
MACHINE_SNAPSHOT_VERSION,
type Session,
type SessionUpdates,
cloneSession,
createSession,
createTestRuntime as createRuntime,
} from "../../../../test/helpers/onboard-machine-runtime-fixture";

interface RunnerContext {
attempts: number;
visited: string[];
}

function cloneSession(session: Session): Session {
return normalizeSession(JSON.parse(JSON.stringify(session))) ?? session;
}

function createRuntime(initialSession: Session = createSession()) {
let session = cloneSession(initialSession);
const updateSession = (mutator: (value: Session) => Session | void): Session => {
const next = mutator(cloneSession(session)) ?? session;
session = cloneSession(next);
return cloneSession(session);
};
const deps: OnboardRuntimeDeps = {
loadSession: () => cloneSession(session),
createSession,
saveSession: (next) => {
session = cloneSession(next);
return cloneSession(session);
},
updateSession,
markStepStarted: () => cloneSession(session),
markStepComplete: (_stepName, updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
return current;
}),
markStepSkipped: () => cloneSession(session),
markStepFailed: (stepName, message) =>
updateSession((current) => {
current.steps[stepName].status = "failed";
current.steps[stepName].error = message ?? null;
return current;
}),
completeSession: (updates: SessionUpdates = {}) =>
updateSession((current) => {
Object.assign(current, filterSafeUpdates(updates));
current.status = "complete";
current.resumable = false;
return current;
}),
filterSafeUpdates,
emitEvent: () => undefined,
now: () => "2026-05-28T00:00:00.000Z",
};
return new OnboardRuntime(deps);
}

describe("runOnboardMachine", () => {
it("runs handlers until completion while applying retry and branch transitions", async () => {
const runtime = createRuntime();
Expand Down
Loading
Loading