Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7db13c1
refactor(onboard): extract flow handoff context
cv Jul 28, 2026
ea6d595
test(onboard): cover sandbox name precedence
cv Jul 28, 2026
5477a39
merge(onboard): refresh FSM stack base
cv Jul 28, 2026
7d63d3c
test(onboard): cover final handoff guards
cv Jul 28, 2026
94d1ca3
merge(onboard): refresh FSM stack base
cv Jul 28, 2026
7d51871
merge(onboard): refresh FSM stack base
cv Jul 28, 2026
853e7bf
refactor(onboard): route handoffs through core flow
cv Jul 28, 2026
01aa8c3
merge(onboard): refresh FSM stack base
cv Jul 28, 2026
413b244
Merge remote-tracking branch 'origin/codex/onboard-fsm-runtime-author…
cv Aug 3, 2026
5de3844
fix(onboard): align handoff tests with reasoning state
cv Aug 3, 2026
30bcbbf
fix(onboard): remove unused handoff locals
cv Aug 3, 2026
f244b1d
test(onboard): align failed-session transition assertion
cv Aug 3, 2026
54d121e
merge(stack): refresh #7717 from #7716
cv Aug 3, 2026
a644818
merge(onboard): refresh #7717 stack base
cv Aug 3, 2026
036f0d4
test(onboard): assert failed session transition
cv Aug 3, 2026
8e22f68
test(onboard): cover interrupted flow handoffs
cv Aug 3, 2026
4c2bd95
test(onboard): use valid handoff endpoint fixtures
cv Aug 3, 2026
4721b38
test(onboard): format handoff regression tests
cv Aug 3, 2026
6c3c9cd
merge(onboard): refresh #7717 on current stack base
cv Aug 3, 2026
6fba00e
merge: refresh PR #7717 from its base branch
cv Aug 3, 2026
2562393
merge: refresh PR #7717 from its base branch
cv Aug 3, 2026
bf3b4c6
merge: refresh #7717 onto its base
cv Aug 3, 2026
74d0248
merge: refresh #7717 onto #7716
cv Aug 3, 2026
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
76 changes: 17 additions & 59 deletions src/lib/onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ const {
restoreDefaultAfterRecreate,
}: typeof import("./onboard/cancel-rollback") = require("./onboard/cancel-rollback");
// biome-ignore format: keep src/lib/onboard.ts net-neutral for growth guardrail.
const { createProviderInferenceOnboardFlowPhase, createSandboxOnboardFlowPhase, runCoreOnboardFlowSlice }: typeof import("./onboard/machine/core-flow-phases") = require("./onboard/machine/core-flow-phases");
const { createProviderInferenceOnboardFlowPhase, createSandboxOnboardFlowPhase, prepareCoreOnboardFlowContext, prepareFinalOnboardFlowContext, runCoreOnboardFlowSlice }: typeof import("./onboard/machine/core-flow-phases") = require("./onboard/machine/core-flow-phases");
const {
createFinalOnboardFlowPhases,
runFinalOnboardFlowSlice,
Expand Down Expand Up @@ -4251,35 +4251,23 @@ async function runOnboard(opts: OnboardOptions = {}): Promise<void> {
recordRepairEvent,
});

const initialContext = initialFlowResult.context;
if (!initialContext.sandboxGpuConfig) {
throw new Error("Preflight did not produce a sandbox GPU configuration.");
}
session = initialFlowResult.session;
const sandboxGpuConfig = initialContext.sandboxGpuConfig;
const { gpuPassthrough } = initialContext;
const gpu = initialContext.gpu ?? null;

// #2753: for an unfinished sandbox, an explicit requested name precedes
// the checkpointed name from the interrupted session.
let sandboxName =
recordedSandboxName || requestedSandboxName || checkpointedSandboxName || null;
if (sandboxName && RESERVED_SANDBOX_NAMES.has(sandboxName)) {
console.error(
` Reserved name in resumed session: '${sandboxName}' is a ${cliDisplayName()} CLI command.`,
);
console.error(" Start a fresh onboard with --name <sandbox> to choose a different name.");
process.exit(1);
}
const coreFlowContext: InitialOnboardFlowContext = {
...initialContext,
session,
sandboxName,
const coreFlowContext = prepareCoreOnboardFlowContext({
initial: initialFlowResult,
recordedSandboxName,
requestedSandboxName,
checkpointedSandboxName,
selectedMessagingChannels,
gpu,
sandboxGpuConfig,
gpuPassthrough,
};
assertSandboxNameAllowed: (sandboxName) => {
if (!RESERVED_SANDBOX_NAMES.has(sandboxName)) return;
console.error(
` Reserved name in resumed session: '${sandboxName}' is a ${cliDisplayName()} CLI command.`,
);
console.error(" Start a fresh onboard with --name <sandbox> to choose a different name.");
process.exit(1);
},
});
// biome-ignore format: keep src/lib/onboard.ts net-neutral for growth guardrail.
const runCoreGatewayOpenshell = setupInferenceFactory.createGatewayScopedOpenshellRunner(runOpenshell, GATEWAY_NAME);
// biome-ignore format: keep src/lib/onboard.ts net-neutral for growth guardrail.
Expand Down Expand Up @@ -4445,38 +4433,8 @@ async function runOnboard(opts: OnboardOptions = {}): Promise<void> {
recordRepairEvent,
});
setupInferenceFactory.selectGatewayForFollowupOrExit(GATEWAY_NAME, runOpenshell);
const coreContext = coreFlowResult.context;
session = coreContext.session;
sandboxName = coreContext.sandboxName;
if (!sandboxName || !coreContext.model || !coreContext.provider) {
throw new Error("Onboarding state is incomplete after sandbox setup.");
}
const model = coreContext.model;
const provider = coreContext.provider;
const endpointUrl = coreContext.endpointUrl;
const credentialEnv = coreContext.credentialEnv;
const hermesAuthMethod = coreContext.hermesAuthMethod;
const hermesToolGateways = coreContext.hermesToolGateways;
const nimContainer = coreContext.nimContainer;
let webSearchConfig = coreContext.webSearchConfig as WebSearchConfig | null;
const webSearchSupported = coreContext.webSearchSupported;

const finalFlowContext: InitialOnboardFlowContext = {
...coreContext,
session,
sandboxName,
model,
provider,
endpointUrl,
credentialEnv,
hermesAuthMethod,
hermesToolGateways,
nimContainer,
webSearchConfig,
selectedMessagingChannels: coreContext.selectedMessagingChannels,
webSearchSupported,
};
let liveFinalFlowContext = finalFlowContext;
const finalFlowContext = prepareFinalOnboardFlowContext(coreFlowResult);
let liveFinalFlowContext: InitialOnboardFlowContext = finalFlowContext;

const finalFlowPhases = createFinalOnboardFlowPhases<
InitialOnboardFlowContext,
Expand Down
2 changes: 2 additions & 0 deletions src/lib/onboard/machine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ The target shape is a machine-driven onboarding runner:

In that final shape, `src/lib/onboard.ts` should be a thin entrypoint. State handlers should own state-specific prompts, resume validation, repair decisions, and side effects.

`flow-handoff.ts` validates required data and constructs context at the initial-to-core and core-to-final boundaries. The entrypoint supplies process-bound dependencies and reserved-name output.

The strict runner owns exact `init`, `preflight`, `provider_selection`, `inference`, and `sandbox` entry. If the durable state is later than a slice entry, earlier phases run as evented prerequisite repairs. A repair must return a legal, update-free transition chain and must not change the durable entry state.

## State ownership
Expand Down
2 changes: 2 additions & 0 deletions src/lib/onboard/machine/core-flow-phases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import type { OnboardMachineRunnerResult, OnboardMachineRunnerRuntime } from "./
import { runOnboardSequenceWithRunner, type OnboardSequencePhase } from "./sequence-runner";
import type { OnboardMachineState } from "./types";

export { prepareCoreOnboardFlowContext, prepareFinalOnboardFlowContext } from "./flow-handoff";

export interface EndpointProvenanceOptions {
endpointSource?: InferenceEndpointSource | null;
endpointSourceProvider?: string | null;
Expand Down
Loading
Loading