Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
52 changes: 52 additions & 0 deletions src/lib/onboard/provider-recovery.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,58 @@ describe("provider recovery persisted routing state", () => {
expect(helpers().readLiveInference("alpha")).toBeNull();
});

it("does not recover a stale live route for a brand-new sandbox name (#6630)", () => {
vi.spyOn(registry, "getSandbox").mockReturnValue(null);
vi.spyOn(registry, "listSandboxes").mockReturnValue({
defaultSandbox: null,
sandboxes: [],
});
vi.spyOn(onboardSession, "loadSession").mockReturnValue(
onboardSession.createSession({
sandboxName: null,
provider: "nvidia-prod",
model: "nvidia/nemotron-3-super-120b-a12b",
}),
);
const parseGatewayInference = vi.fn(() => ({
provider: "nvidia-prod",
model: "nvidia/nemotron-3-super-120b-a12b",
}));
const runCaptureOpenshell = vi.fn(() => "Gateway inference:");
const recovery = createProviderRecoveryHelpers({
parseGatewayInference,
runCaptureOpenshell,
});

expect(recovery.readRecordedProvider("dc-after")).toBeNull();
expect(recovery.readRecordedModel("dc-after")).toBeNull();
expect(runCaptureOpenshell).not.toHaveBeenCalled();
expect(parseGatewayInference).not.toHaveBeenCalled();
});

it("recovers a live route when a matching session proves the sandbox identity", () => {
vi.spyOn(registry, "getSandbox").mockReturnValue(null);
vi.spyOn(registry, "listSandboxes").mockReturnValue({
defaultSandbox: null,
sandboxes: [],
});
vi.spyOn(onboardSession, "loadSession").mockReturnValue(
onboardSession.createSession({ sandboxName: "rebuild-box" }),
);
const runCaptureOpenshell = vi.fn(() => "Gateway inference:");
const recovery = createProviderRecoveryHelpers({
parseGatewayInference: () => ({
provider: "nvidia-prod",
model: "nvidia/nemotron-3-super-120b-a12b",
}),
runCaptureOpenshell,
});

expect(recovery.readRecordedProvider("rebuild-box")).toBe("nvidia-prod");
expect(recovery.readRecordedModel("rebuild-box")).toBe("nvidia/nemotron-3-super-120b-a12b");
expect(runCaptureOpenshell).toHaveBeenCalledTimes(2);
});

it("prefers the selected sandbox registry endpoint over session state", () => {
vi.spyOn(registry, "getSandbox").mockReturnValue({
name: "alpha",
Expand Down
34 changes: 20 additions & 14 deletions src/lib/onboard/provider-recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,10 @@ export function createProviderRecoveryHelpers(deps: ProviderRecoveryDeps): Provi

function readRecordedProvider(sandboxName: string | null | undefined): string | null {
if (!sandboxName) return null;
let hasRecordedSandboxIdentity = false;
try {
const entry = registry.getSandbox(sandboxName);
hasRecordedSandboxIdentity = Boolean(entry);
if (entry && typeof entry.provider === "string" && entry.provider) {
return entry.provider;
}
Expand All @@ -143,17 +145,20 @@ export function createProviderRecoveryHelpers(deps: ProviderRecoveryDeps): Provi
}
try {
const session = onboardSession.loadSession();
if (
session &&
session.sandboxName === sandboxName &&
typeof session.provider === "string" &&
session.provider
) {
return session.provider;
if (session && session.sandboxName === sandboxName) {
hasRecordedSandboxIdentity = true;
if (typeof session.provider === "string" && session.provider) {
return session.provider;
}
}
} catch {
// fall through to live gateway
}
// An empty registry does not prove that the gateway's residual route
// belongs to this requested sandbox name. Require a matching registry or
// session identity before using that route as rebuild recovery state;
// otherwise a brand-new sandbox inherits the previous sandbox's model.
if (!hasRecordedSandboxIdentity) return null;
const live = readLiveInference(sandboxName);
if (live && typeof live.provider === "string" && live.provider) {
return live.provider;
Expand Down Expand Up @@ -189,8 +194,10 @@ export function createProviderRecoveryHelpers(deps: ProviderRecoveryDeps): Provi

function readRecordedModel(sandboxName: string | null | undefined): string | null {
if (!sandboxName) return null;
let hasRecordedSandboxIdentity = false;
try {
const entry = registry.getSandbox(sandboxName);
hasRecordedSandboxIdentity = Boolean(entry);
if (entry && typeof entry.model === "string" && entry.model) {
return entry.model;
}
Expand All @@ -199,17 +206,16 @@ export function createProviderRecoveryHelpers(deps: ProviderRecoveryDeps): Provi
}
try {
const session = onboardSession.loadSession();
if (
session &&
session.sandboxName === sandboxName &&
typeof session.model === "string" &&
session.model
) {
return session.model;
if (session && session.sandboxName === sandboxName) {
hasRecordedSandboxIdentity = true;
if (typeof session.model === "string" && session.model) {
return session.model;
}
}
} catch {
// fall through to live gateway
}
if (!hasRecordedSandboxIdentity) return null;
const live = readLiveInference(sandboxName);
if (live && typeof live.model === "string" && live.model) {
return live.model;
Expand Down
Loading