Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions src/lib/actions/sandbox/rebuild-gpu-opt-out.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ export type RebuildRecreateOnboardOpts = {
providerRecoveryReceipt?: ProviderRecoveryReceipt;
/** Recorded managed-vLLM intent admitted only by the N1x readiness exception. */
allowDeferredN1xManagedVllm?: true;
/** Internal legacy Hermes rebuild authority for the pre-v0.0.97 Station admission rule. */
allowLegacyDgxStationQualification?: true;
/** Target-scoped authority admitted by the authoritative rebuild preflight. */
rebuildGatewayAuthority?: CheckpointGatewayAuthority;
preparedImageRebuild?: PreparedImageRebuildHandoff;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,59 @@ describe("prepareRebuildTargetPreflights", () => {
expect(mocks.resolveContextWindowForModel).toHaveBeenCalledWith("ollama-local", "qwen3.5:9b");
});

it("passes legacy Station authority from the source registry row into rebuild readiness (#10370)", async () => {
const resumeConfig = {
provider: "ollama-local",
model: "llama3.2:1b",
preferredInferenceApi: "openai-completions",
endpointUrl: null,
compatibleEndpointReasoning: null,
compatibleEndpointReasoningEffort: null,
registryInferenceRoute: null,
};
mocks.prepareRebuildTargetConfig.mockReturnValue({
agentDefinition: {},
resumeConfig,
durableConfig: {
toolDisclosure: "progressive",
dcodeAutoApprovalMode: "disabled",
webSearchConfig: null,
},
credentialEnv: null,
fromDockerfile: false,
hermesToolGateways: [],
});
mocks.prepareRebuildRecreateOptions.mockReturnValue({
controlUiPort: 18_789,
targetGatewayName: "nemoclaw",
toolDisclosure: "progressive",
dcodeAutoApprovalMode: "disabled",
observabilityEnabled: false,
});

await prepareRebuildTargetPreflights({
sandboxName: "legacy-hermes",
sandboxEntry: {
name: "legacy-hermes",
agent: "hermes",
nemoclawVersion: "v0.0.83",
fromDockerfile: null,
gatewayName: "nemoclaw",
openshellDriver: "docker",
provider: resumeConfig.provider,
model: resumeConfig.model,
} as never,
rebuildAgent: "hermes",
autoYes: true,
log: vi.fn(),
bail: mocks.bail as never,
});

expect(mocks.preflightAuthoritativeOnboardRuntime.mock.calls[0]?.[2]).toEqual(
expect.objectContaining({ allowLegacyDgxStationQualification: true }),
);
});

it("passes exact legacy N1x intent into authoritative readiness (#9292)", async () => {
const readinessOptions = await prepareN1xTarget("onboard");

Expand Down
4 changes: 4 additions & 0 deletions src/lib/actions/sandbox/rebuild-preflight-target-phase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
} from "./rebuild-preflight-guards";
import { disposePreparedBuildContext } from "./rebuild-prepared-image-context";
import {
hasLegacyDgxStationQualificationAuthority,
hydrateMessagingConfigForRebuild,
preflightAuthoritativeOnboardRuntime,
preflightRebuildTargetRuntime,
Expand Down Expand Up @@ -198,6 +199,9 @@ export async function prepareRebuildTargetPreflights(args: {
bail,
);
if (!recreateOptions) return null;
if (hasLegacyDgxStationQualificationAuthority(sandboxEntry)) {
recreateOptions.allowLegacyDgxStationQualification = true;
}
let managedWorkloadRebuildCatalog: Awaited<
ReturnType<typeof prepareManagedWorkloadRebuildHandoff>
> = null;
Expand Down
6 changes: 2 additions & 4 deletions src/lib/actions/sandbox/rebuild-target-preflight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
* staging remain independently reviewable.
*/
export { printRebuildPreflightFailure } from "./rebuild-preflight-error";
export { prepareRebuildTargetConfig, type RebuildTargetConfig } from "./rebuild-target-config";
export {
prepareRebuildTargetConfig,
type RebuildTargetConfig,
} from "./rebuild-target-config";
export {
hasLegacyDgxStationQualificationAuthority,
preflightAuthoritativeOnboardRuntime,
preflightRebuildTargetRuntime,
} from "./rebuild-target-runtime";
Expand Down
41 changes: 41 additions & 0 deletions src/lib/actions/sandbox/rebuild-target-runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import type { RebuildRecreateOnboardOpts } from "./rebuild-gpu-opt-out";
import type { RebuildResumeConfig } from "./rebuild-resume-config";
import type { RebuildTargetConfig } from "./rebuild-target-config";
import {
hasLegacyDgxStationQualificationAuthority,
preflightAuthoritativeOnboardRuntime,
preflightRebuildTargetRuntime,
} from "./rebuild-target-runtime";
Expand Down Expand Up @@ -195,13 +196,52 @@ describe("preflightRebuildTargetRuntime GPU route", () => {
});
});

describe("legacy DGX Station rebuild authority", () => {
it.each([
["v0.0.83", true],
["0.0.96-12-gabcdef0", true],
["v0.0.97", false],
["0.0.97-1-gabcdef0", false],
["0.0.83-preview", false],
["v0.0.096", false],
["0.0.x", false],
["", false],
])("accepts only a valid release older than v0.0.97: %s", (nemoclawVersion, expected) => {
expect(
hasLegacyDgxStationQualificationAuthority({
agent: "hermes",
fromDockerfile: null,
nemoclawVersion,
}),
).toBe(expected);
});

it("rejects unrelated sandbox state", () => {
expect(
hasLegacyDgxStationQualificationAuthority({
agent: "openclaw",
fromDockerfile: null,
nemoclawVersion: "v0.0.83",
}),
).toBe(false);
expect(
hasLegacyDgxStationQualificationAuthority({
agent: "hermes",
fromDockerfile: "/tmp/Dockerfile",
nemoclawVersion: "v0.0.83",
}),
).toBe(false);
});
});

describe("authoritative rebuild readiness", () => {
it("passes recorded managed-vLLM intent to the pre-delete readiness gate (#9292)", async () => {
const authority = { checkpoint: "gateway-authority" };
mocks.preflightAuthoritativeRebuildTarget.mockResolvedValue(authority);
const recreateOptions = {
...RECREATE_OPTIONS,
allowDeferredN1xManagedVllm: true,
allowLegacyDgxStationQualification: true,
} as RebuildRecreateOnboardOpts;
const bail = vi.fn((message: string): never => {
throw new Error(message);
Expand All @@ -219,6 +259,7 @@ describe("authoritative rebuild readiness", () => {
expect(mocks.preflightAuthoritativeRebuildTarget).toHaveBeenCalledWith(
expect.objectContaining({
allowDeferredN1xManagedVllm: true,
allowLegacyDgxStationQualification: true,
provider: "vllm-local",
model: "test-model",
sandboxName: "alpha",
Expand Down
18 changes: 18 additions & 0 deletions src/lib/actions/sandbox/rebuild-target-runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ async function preflightRebuildWebSearchCredential(
}
}

/**
* The DGX Station qualification projection was introduced in v0.0.97. A Hermes
* sandbox stamped by an earlier managed release may be rebuilt once without
* re-litigating that later admission rule. This is deliberately a strict
* release parser: untrusted version-shaped text is not recovery authority.
*/
export function hasLegacyDgxStationQualificationAuthority(
sandbox: Pick<RebuildSandboxEntry, "agent" | "fromDockerfile" | "nemoclawVersion">,
): boolean {
if (sandbox.agent !== "hermes" || sandbox.fromDockerfile != null) return false;
const match = /^(?:v)?0\.0\.(0|[1-9]\d*)(?:-[1-9]\d*-g[0-9a-f]{7,40})?$/i.exec(
sandbox.nemoclawVersion ?? "",
);
if (!match) return false;
const patch = Number(match[1]);
return Number.isSafeInteger(patch) && patch < 97;
}

export type RebuildTargetRuntimePreflightResult =
| {
ok: true;
Expand Down
11 changes: 8 additions & 3 deletions src/lib/actions/sandbox/snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -513,9 +513,14 @@ describe("runSandboxSnapshot", () => {
([args]) => args[0] === "sandbox" && args[1] === "exec",
),
).toBe(false);
expect(f.backupSandboxStateMock).toHaveBeenCalledWith("alpha", {
name: null,
});
expect(f.backupSandboxStateMock).toHaveBeenCalledWith(
"alpha",
expect.objectContaining({
name: null,
captureStateFile: expect.any(Function),
captureStateDirectories: expect.any(Function),
}),
);
expect(consoleLog.mock.calls.flat().join("\n")).toContain("Snapshot v3 created");
});

Expand Down
Loading
Loading