Skip to content

Commit 323753b

Browse files
committed
fix(onboard): revert incorrect N1x rebuild changes
Signed-off-by: San Dang <sdang@nvidia.com>
1 parent 71992f6 commit 323753b

15 files changed

Lines changed: 12 additions & 453 deletions

docs/inference/set-up-vllm.mdx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -371,22 +371,6 @@ Accepting the preview prompt sets explicit managed-vLLM intent for the narrow pe
371371
Declining the prompt or setting only `NEMOCLAW_NO_EXPRESS=1` stops the installer before onboarding; neither path opens interactive provider selection.
372372
Set `NEMOCLAW_PROVIDER=install-vllm` when you need to bypass the prompt with the same explicit preview intent.
373373

374-
On a host that still meets the N1x identity checks, `rebuild` reuses the recorded route as explicit preview intent only when all of these conditions hold:
375-
376-
- The sandbox registry records provider `vllm-local`.
377-
- The registry records model `nvidia/Qwen3.6-35B-A3B-NVFP4`.
378-
- The registry records upstream endpoint `http://host.openshell.internal:8000/v1`.
379-
- The registry records `endpointSource` as `onboard` and `openshellDriver` as `docker`.
380-
- The replacement keeps the recorded provider and model, then re-derives the canonical local endpoint.
381-
- `hostLocalInferenceReceipt` is absent or `null`, or contains a canonical vLLM receipt for `host.openshell.internal:8000` and the same model.
382-
383-
NemoClaw v0.0.109 can omit `hostLocalInferenceReceipt` or record it as `null`.
384-
Matching sandboxes from that release remain eligible only when every condition above passes.
385-
You do not need to set `NEMOCLAW_PROVIDER` again for a matching rebuild.
386-
Any unmet condition stops readiness preflight before NemoClaw deletes the existing sandbox.
387-
A malformed, non-vLLM, or conflicting receipt also stops readiness preflight before deletion.
388-
This reuse waives only the pending physical-validation finding and does not change the Deferred status.
389-
390374
<Warning title="N1x Express Qualification Pending">
391375
Physical CUDA and CDI checks passed on one N1x host.
392376
The full NemoClaw Express E2E test is still pending, so the N1x platform status remains Deferred.

src/lib/actions/sandbox/rebuild-gpu-opt-out.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ export type RebuildRecreateOnboardOpts = {
127127
rebuildRegistryInferenceRoute?: RebuildRouteHandoff;
128128
rebuildProviderReconfigure?: RebuildProviderReconfigureHandoff;
129129
providerRecoveryReceipt?: ProviderRecoveryReceipt;
130-
/** Recorded managed-vLLM intent admitted only by the N1x readiness exception. */
131-
allowDeferredN1xManagedVllm?: true;
132130
/** Target-scoped authority admitted by the authoritative rebuild preflight. */
133131
rebuildGatewayAuthority?: CheckpointGatewayAuthority;
134132
preparedImageRebuild?: PreparedImageRebuildHandoff;

src/lib/actions/sandbox/rebuild-preflight-target-phase-orchestration.test.ts renamed to src/lib/actions/sandbox/rebuild-managed-workload-context-window.test.ts

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import { beforeEach, describe, expect, it, vi } from "vitest";
4+
import { describe, expect, it, vi } from "vitest";
55

66
const mocks = vi.hoisted(() => ({
77
bail: vi.fn(),
8-
preflightAuthoritativeOnboardRuntime: vi.fn(async (..._args: unknown[]) => false),
98
prepareManagedWorkloadRebuildHandoff: vi.fn(),
109
prepareSandboxWorkloadSourceFromRebuildHandoff: vi.fn(),
1110
prepareRebuildTargetConfig: vi.fn(),
@@ -34,7 +33,7 @@ vi.mock("../../onboard/workload/runtime", () => ({
3433
vi.mock("./rebuild-target-preflight", async (importOriginal) => ({
3534
...(await importOriginal<typeof import("./rebuild-target-preflight")>()),
3635
hydrateMessagingConfigForRebuild: vi.fn(),
37-
preflightAuthoritativeOnboardRuntime: mocks.preflightAuthoritativeOnboardRuntime,
36+
preflightAuthoritativeOnboardRuntime: vi.fn(async () => false),
3837
prepareRebuildRecreateOptions: mocks.prepareRebuildRecreateOptions,
3938
prepareRebuildTargetConfig: mocks.prepareRebuildTargetConfig,
4039
stageRebuildHermesDashboardConfig: vi.fn(() => true),
@@ -51,64 +50,7 @@ vi.mock("./rebuild-messaging-conflict-preflight", () => ({
5150
import { managedRebuildProfileDependencies } from "./agents/managed-workload-rebuild-profile";
5251
import { prepareRebuildTargetPreflights } from "./rebuild-preflight-target-phase";
5352

54-
describe("prepareRebuildTargetPreflights", () => {
55-
beforeEach(() => {
56-
vi.clearAllMocks();
57-
mocks.prepareManagedWorkloadRebuildHandoff.mockResolvedValue(null);
58-
mocks.preflightAuthoritativeOnboardRuntime.mockResolvedValue(false);
59-
});
60-
61-
async function prepareN1xTarget(endpointSource: "onboard" | "inference-set") {
62-
const resumeConfig = {
63-
provider: "vllm-local",
64-
model: "nvidia/Qwen3.6-35B-A3B-NVFP4",
65-
preferredInferenceApi: "openai-completions",
66-
pinEndpoint: true,
67-
endpointUrl: null,
68-
compatibleEndpointReasoning: null,
69-
compatibleEndpointReasoningEffort: null,
70-
registryInferenceRoute: null,
71-
};
72-
mocks.prepareRebuildTargetConfig.mockReturnValue({
73-
agentDefinition: {},
74-
resumeConfig,
75-
durableConfig: {
76-
toolDisclosure: "progressive",
77-
dcodeAutoApprovalMode: "disabled",
78-
webSearchConfig: null,
79-
},
80-
credentialEnv: null,
81-
fromDockerfile: false,
82-
hermesToolGateways: [],
83-
});
84-
mocks.prepareRebuildRecreateOptions.mockReturnValue({
85-
controlUiPort: 18_789,
86-
targetGatewayName: "nemoclaw",
87-
toolDisclosure: "progressive",
88-
dcodeAutoApprovalMode: "disabled",
89-
observabilityEnabled: false,
90-
});
91-
92-
await prepareRebuildTargetPreflights({
93-
sandboxName: "my-assistant",
94-
sandboxEntry: {
95-
name: "my-assistant",
96-
agent: "openclaw",
97-
gatewayName: "nemoclaw",
98-
openshellDriver: "docker",
99-
provider: resumeConfig.provider,
100-
model: resumeConfig.model,
101-
endpointUrl: "http://host.openshell.internal:8000/v1",
102-
endpointSource,
103-
} as never,
104-
rebuildAgent: "openclaw",
105-
autoYes: true,
106-
log: vi.fn(),
107-
bail: mocks.bail as never,
108-
});
109-
return mocks.preflightAuthoritativeOnboardRuntime.mock.calls[0]?.[2];
110-
}
111-
53+
describe("managed workload rebuild context-window preflight", () => {
11254
it("resolves the Ollama context window through target preparation", async () => {
11355
const catalogHandoff = {
11456
agent: "openclaw",
@@ -181,18 +123,4 @@ describe("prepareRebuildTargetPreflights", () => {
181123
).resolves.toBeNull();
182124
expect(mocks.resolveContextWindowForModel).toHaveBeenCalledWith("ollama-local", "qwen3.5:9b");
183125
});
184-
185-
it("passes exact legacy N1x intent into authoritative readiness (#9292)", async () => {
186-
const readinessOptions = await prepareN1xTarget("onboard");
187-
188-
expect(readinessOptions).toEqual(
189-
expect.objectContaining({ allowDeferredN1xManagedVllm: true }),
190-
);
191-
});
192-
193-
it("withholds N1x intent for a mismatched endpoint source (#9292)", async () => {
194-
const readinessOptions = await prepareN1xTarget("inference-set");
195-
196-
expect(readinessOptions).not.toHaveProperty("allowDeferredN1xManagedVllm");
197-
});
198126
});

src/lib/actions/sandbox/rebuild-preflight-target-phase.test.ts

Lines changed: 0 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,15 @@
33

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

6-
import {
7-
hostLocalInferenceReceipt,
8-
serializedHostLocalInferenceReceipt,
9-
serializedLlamaCppHostLocalInferenceReceipt,
10-
} from "../../../../test/helpers/host-local-inference-receipt";
116
import type {
127
ProviderRecoveryReceipt,
138
RegistryInferenceRoute,
149
} from "../../onboard/rebuild-route-handoff";
15-
import { serializeHostLocalInferenceReceipt } from "../../onboard/runtime-provider/host-local-inference";
1610
import type { SandboxBaseImageResolutionMetadata } from "../../sandbox-base-image";
1711
import {
1812
pinRebuildTargetGatewayForReadiness,
1913
runRebuildGatewayRecoveryAfterReadiness,
2014
stageRebuildBaseImageResolutionHandoff,
21-
stageRecordedManagedVllmIntent,
2215
stageRegistryProviderRecoveryReceipt,
2316
} from "./rebuild-preflight-target-phase";
2417

@@ -128,145 +121,6 @@ describe("stageRegistryProviderRecoveryReceipt", () => {
128121
});
129122
});
130123

131-
describe("stageRecordedManagedVllmIntent", () => {
132-
const n1xExpressEntry = {
133-
provider: "vllm-local",
134-
model: "nvidia/Qwen3.6-35B-A3B-NVFP4",
135-
endpointUrl: "http://host.openshell.internal:8000/v1",
136-
endpointSource: "onboard" as const,
137-
openshellDriver: "docker",
138-
};
139-
const n1xExpressSelection = {
140-
provider: n1xExpressEntry.provider,
141-
model: n1xExpressEntry.model,
142-
pinEndpoint: true,
143-
endpointUrl: null,
144-
};
145-
146-
it.each([
147-
{ receiptState: "absent", sandboxEntry: n1xExpressEntry },
148-
{
149-
receiptState: "null",
150-
sandboxEntry: { ...n1xExpressEntry, hostLocalInferenceReceipt: null },
151-
},
152-
])(
153-
"carries the v0.0.109 N1x Express selection with a $receiptState receipt into rebuild readiness (#9292)",
154-
({ sandboxEntry }) => {
155-
const recreateOptions: { allowDeferredN1xManagedVllm?: true } = {};
156-
157-
stageRecordedManagedVllmIntent(recreateOptions, sandboxEntry, n1xExpressSelection);
158-
159-
expect(recreateOptions.allowDeferredN1xManagedVllm).toBe(true);
160-
},
161-
);
162-
163-
it("also accepts a canonical vLLM receipt on the exact N1x Express selection (#9292)", () => {
164-
const recreateOptions: { allowDeferredN1xManagedVllm?: true } = {};
165-
const genericReceipt = hostLocalInferenceReceipt("docker");
166-
const n1xReceipt = serializeHostLocalInferenceReceipt({
167-
...genericReceipt,
168-
endpoint: {
169-
...genericReceipt.endpoint,
170-
host: "host.openshell.internal",
171-
},
172-
inference: {
173-
protocol: "openai-chat-completions",
174-
model: n1xExpressEntry.model,
175-
toolCallingRequired: true,
176-
},
177-
});
178-
179-
stageRecordedManagedVllmIntent(
180-
recreateOptions,
181-
{ ...n1xExpressEntry, hostLocalInferenceReceipt: n1xReceipt },
182-
n1xExpressSelection,
183-
);
184-
185-
expect(recreateOptions.allowDeferredN1xManagedVllm).toBe(true);
186-
});
187-
188-
it.each([
189-
{
190-
caseName: "different recorded provider",
191-
sandboxEntry: { ...n1xExpressEntry, provider: "compatible-endpoint" },
192-
rebuildSelection: n1xExpressSelection,
193-
},
194-
{
195-
caseName: "different recorded model",
196-
sandboxEntry: { ...n1xExpressEntry, model: "meta-llama/Llama-3.1-8B-Instruct" },
197-
rebuildSelection: n1xExpressSelection,
198-
},
199-
{
200-
caseName: "different recorded endpoint",
201-
sandboxEntry: { ...n1xExpressEntry, endpointUrl: "http://host.openshell.internal:8001/v1" },
202-
rebuildSelection: n1xExpressSelection,
203-
},
204-
{
205-
caseName: "different endpoint source",
206-
sandboxEntry: { ...n1xExpressEntry, endpointSource: "inference-set" as const },
207-
rebuildSelection: n1xExpressSelection,
208-
},
209-
{
210-
caseName: "different OpenShell driver",
211-
sandboxEntry: { ...n1xExpressEntry, openshellDriver: "podman" },
212-
rebuildSelection: n1xExpressSelection,
213-
},
214-
{
215-
caseName: "malformed receipt",
216-
sandboxEntry: { ...n1xExpressEntry, hostLocalInferenceReceipt: "not-json" },
217-
rebuildSelection: n1xExpressSelection,
218-
},
219-
{
220-
caseName: "different host-local service",
221-
sandboxEntry: {
222-
...n1xExpressEntry,
223-
hostLocalInferenceReceipt: serializedLlamaCppHostLocalInferenceReceipt(),
224-
},
225-
rebuildSelection: n1xExpressSelection,
226-
},
227-
{
228-
caseName: "conflicting vLLM receipt",
229-
sandboxEntry: {
230-
...n1xExpressEntry,
231-
hostLocalInferenceReceipt: serializedHostLocalInferenceReceipt(),
232-
},
233-
rebuildSelection: n1xExpressSelection,
234-
},
235-
{
236-
caseName: "different rebuild provider",
237-
sandboxEntry: n1xExpressEntry,
238-
rebuildSelection: { ...n1xExpressSelection, provider: "compatible-endpoint" },
239-
},
240-
{
241-
caseName: "different rebuild model",
242-
sandboxEntry: n1xExpressEntry,
243-
rebuildSelection: { ...n1xExpressSelection, model: "meta-llama/Llama-3.1-8B-Instruct" },
244-
},
245-
{
246-
caseName: "unresolved rebuild endpoint",
247-
sandboxEntry: n1xExpressEntry,
248-
rebuildSelection: { ...n1xExpressSelection, pinEndpoint: false },
249-
},
250-
{
251-
caseName: "noncanonical rebuild endpoint",
252-
sandboxEntry: n1xExpressEntry,
253-
rebuildSelection: {
254-
...n1xExpressSelection,
255-
endpointUrl: "http://host.openshell.internal:8001/v1",
256-
},
257-
},
258-
])(
259-
"does not infer N1x Express intent from a $caseName (#9292)",
260-
({ sandboxEntry, rebuildSelection }) => {
261-
const recreateOptions: { allowDeferredN1xManagedVllm?: true } = {};
262-
263-
stageRecordedManagedVllmIntent(recreateOptions, sandboxEntry, rebuildSelection);
264-
265-
expect(recreateOptions).not.toHaveProperty("allowDeferredN1xManagedVllm");
266-
},
267-
);
268-
});
269-
270124
describe("stageRebuildBaseImageResolutionHandoff", () => {
271125
it("binds outer resolver provenance to its immutable local handoff (#7144)", () => {
272126
const imageId = `sha256:${"a".repeat(64)}`;

src/lib/actions/sandbox/rebuild-preflight-target-phase.ts

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { CLI_NAME } from "../../cli/branding";
66
import type { SandboxMessagingPlan } from "../../messaging";
77
import { isSandboxBaseImageRefreshRequested } from "../../onboard/base-image-resolution-flow";
88
import type { DcodeAutoApprovalMode } from "../../onboard/dcode-auto-approval";
9-
import { parseHostLocalInferenceReceipt } from "../../onboard/runtime-provider/host-local-inference";
109
import {
1110
createRebuildProviderReconfigureHandoff,
1211
mintProviderRecoveryReceipt,
@@ -84,62 +83,6 @@ export function stageRegistryProviderRecoveryReceipt(
8483
);
8584
}
8685

87-
const N1X_EXPRESS_PROVIDER = "vllm-local";
88-
const N1X_EXPRESS_MODEL = "nvidia/Qwen3.6-35B-A3B-NVFP4";
89-
const N1X_EXPRESS_ENDPOINT_URL = "http://host.openshell.internal:8000/v1";
90-
91-
/** Reuse only the exact N1x Express selection recorded by onboarding. */
92-
export function stageRecordedManagedVllmIntent(
93-
recreateOptions: Pick<RebuildRecreateOnboardOpts, "allowDeferredN1xManagedVllm">,
94-
sandboxEntry: Pick<
95-
RebuildSandboxEntry,
96-
| "provider"
97-
| "model"
98-
| "endpointUrl"
99-
| "endpointSource"
100-
| "openshellDriver"
101-
| "hostLocalInferenceReceipt"
102-
>,
103-
rebuildSelection: {
104-
provider: string;
105-
model: string;
106-
pinEndpoint: boolean;
107-
endpointUrl: string | null;
108-
},
109-
): void {
110-
if (
111-
sandboxEntry.provider !== N1X_EXPRESS_PROVIDER ||
112-
sandboxEntry.model !== N1X_EXPRESS_MODEL ||
113-
sandboxEntry.endpointUrl !== N1X_EXPRESS_ENDPOINT_URL ||
114-
sandboxEntry.endpointSource !== "onboard" ||
115-
sandboxEntry.openshellDriver !== "docker" ||
116-
rebuildSelection.provider !== sandboxEntry.provider ||
117-
rebuildSelection.model !== sandboxEntry.model ||
118-
rebuildSelection.pinEndpoint !== true ||
119-
rebuildSelection.endpointUrl !== null
120-
) {
121-
return;
122-
}
123-
const serialized = sandboxEntry.hostLocalInferenceReceipt;
124-
if (serialized === undefined || serialized === null) {
125-
recreateOptions.allowDeferredN1xManagedVllm = true;
126-
return;
127-
}
128-
try {
129-
const receipt = parseHostLocalInferenceReceipt(serialized);
130-
if (
131-
receipt.service === "vllm" &&
132-
receipt.endpoint.host === "host.openshell.internal" &&
133-
receipt.endpoint.port === 8000 &&
134-
receipt.inference?.model === N1X_EXPRESS_MODEL
135-
) {
136-
recreateOptions.allowDeferredN1xManagedVllm = true;
137-
}
138-
} catch {
139-
// Malformed durable state must not grant the narrow N1x readiness exception.
140-
}
141-
}
142-
14386
export interface RebuildPreparedTarget {
14487
targetConfig: RebuildTargetConfig;
14588
recreateOptions: RebuildRecreateOnboardOpts;
@@ -290,7 +233,6 @@ export async function prepareRebuildTargetPreflights(args: {
290233
recreateOptions.observabilityEnabled =
291234
requestedObservabilityEnabled ?? recreateOptions.observabilityEnabled;
292235
recreateOptions.observabilityRequestedExplicitly = requestedObservabilityEnabled !== undefined;
293-
stageRecordedManagedVllmIntent(recreateOptions, sandboxEntry, resumeConfig);
294236
if (
295237
!stageRebuildHermesDashboardConfig(
296238
rebuildAgent,

0 commit comments

Comments
 (0)