refactor(canvas): remove RUNTIME_PROFILES.hermes — value flows server-side now (#2054 phase 3)
Closes the canvas-side loop on #2054. Phases 1+2 plumbed provision_timeout_ms from template manifest → workspace API → canvas socket → node-data → ProvisioningTimeout resolver. The template-hermes manifest declares provision_timeout_seconds: 720 (filed as a separate template-repo PR). With that flow live, the canvas-side hardcoded RUNTIME_PROFILES.hermes entry is redundant. Removed: - RUNTIME_PROFILES.hermes (was 720000ms hardcoded in canvas/src/lib/runtimeProfiles.ts) Doc updates: - RUNTIME_PROFILES jsdoc explains the map is now empty by design — new runtimes that need a non-default cold-boot threshold should declare runtime_config.provision_timeout_seconds in their template manifest, NOT add an entry here. Tests updated (3): - "returns hermes override when runtime = hermes" → "hermes returns default — value moved server-side post-#2054 phase 3". Asserts RUNTIME_PROFILES.hermes is undefined. - The two server-override tests now compare against DEFAULT_RUNTIME_PROFILE since hermes no longer has a profile entry. 19/19 pass locally. The end-state for hermes: workspace-server reads template manifest at request time → workspace API includes provision_timeout_ms: 720000 → canvas hydrate populates node.data.provisionTimeoutMs → ProvisioningTimeout resolver picks it up via overrides. Same effective threshold (720s), now declarative and one-edit-point per runtime. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a8c9644618
commit
756aa00e1f
@ -226,13 +226,18 @@ describe("ProvisioningTimeout", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("returns hermes override when runtime = hermes", () => {
|
||||
it("hermes returns default — value moved server-side post-#2054 phase 3", () => {
|
||||
// RUNTIME_PROFILES.hermes was removed when template-hermes
|
||||
// started declaring provision_timeout_seconds in its
|
||||
// config.yaml. The value now flows server-side via the
|
||||
// workspace API → WorkspaceData.provision_timeout_ms →
|
||||
// resolver overrides path. With no override supplied, the
|
||||
// resolver falls through to the default — same as any other
|
||||
// runtime without a canvas-side override.
|
||||
expect(provisionTimeoutForRuntime("hermes")).toBe(
|
||||
RUNTIME_PROFILES.hermes?.provisionTimeoutMs,
|
||||
);
|
||||
expect(provisionTimeoutForRuntime("hermes")).toBeGreaterThanOrEqual(
|
||||
DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs * 5,
|
||||
DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs,
|
||||
);
|
||||
expect(RUNTIME_PROFILES.hermes).toBeUndefined();
|
||||
});
|
||||
|
||||
it("server-side workspace override wins over runtime profile", () => {
|
||||
@ -309,7 +314,7 @@ describe("ProvisioningTimeout", () => {
|
||||
expect(node?.data.provisionTimeoutMs).toBe(600_000);
|
||||
});
|
||||
|
||||
it("absent provision_timeout_ms hydrates to null (falls through to runtime profile)", () => {
|
||||
it("absent provision_timeout_ms hydrates to null (falls through to default post-cleanup)", () => {
|
||||
useCanvasStore.getState().hydrate([
|
||||
makeWS({ id: "ws-default", name: "Default", status: "provisioning", runtime: "hermes" }),
|
||||
]);
|
||||
@ -317,27 +322,32 @@ describe("ProvisioningTimeout", () => {
|
||||
.getState()
|
||||
.nodes.find((n) => n.id === "ws-default");
|
||||
expect(node?.data.provisionTimeoutMs).toBeNull();
|
||||
// And the resolver still returns hermes' profile value when
|
||||
// no override is supplied — proves the fall-through stays intact.
|
||||
// Post-#2054 phase 3: hermes no longer has a canvas-side
|
||||
// RUNTIME_PROFILES entry. With no node override the resolver
|
||||
// falls all the way through to DEFAULT_RUNTIME_PROFILE. In
|
||||
// production the workspace-server-side template lookup
|
||||
// populates node.provisionTimeoutMs to 720000 before this
|
||||
// resolver runs (#2094); this test isolates the fall-through
|
||||
// behavior when that population hasn't happened yet.
|
||||
expect(
|
||||
provisionTimeoutForRuntime("hermes", {
|
||||
provisionTimeoutMs: node?.data.provisionTimeoutMs ?? undefined,
|
||||
}),
|
||||
).toBe(RUNTIME_PROFILES.hermes.provisionTimeoutMs);
|
||||
).toBe(DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs);
|
||||
});
|
||||
|
||||
it("server override wins over runtime profile via the resolver path the component uses", () => {
|
||||
// Mirrors ProvisioningTimeout.tsx:144 where node.provisionTimeoutMs
|
||||
// is passed as overrides — verifies the resolver respects it
|
||||
// even when the runtime has its own profile entry.
|
||||
const override = 30_000;
|
||||
it("server override wins over default via the resolver path the component uses", () => {
|
||||
// Mirrors ProvisioningTimeout.tsx where node.provisionTimeoutMs
|
||||
// is passed as overrides — verifies the resolver respects the
|
||||
// override regardless of the runtime's profile state.
|
||||
const override = 600_000;
|
||||
expect(
|
||||
provisionTimeoutForRuntime("hermes", {
|
||||
provisionTimeoutMs: override,
|
||||
}),
|
||||
).toBe(override);
|
||||
// Sanity — the runtime profile would have been much larger.
|
||||
expect(RUNTIME_PROFILES.hermes.provisionTimeoutMs).toBeGreaterThan(
|
||||
// Sanity — the override is the path that wins (default is much smaller).
|
||||
expect(DEFAULT_RUNTIME_PROFILE.provisionTimeoutMs).toBeLessThan(
|
||||
override,
|
||||
);
|
||||
});
|
||||
|
||||
@ -60,21 +60,23 @@ export const DEFAULT_RUNTIME_PROFILE: Required<
|
||||
/**
|
||||
* Named per-runtime overrides. Keep this map small and explicit —
|
||||
* each entry is a deliberate statement that this runtime's cold-boot
|
||||
* behavior differs materially from the default.
|
||||
* behavior differs materially from the default AND that the runtime's
|
||||
* template manifest hasn't yet declared a server-side
|
||||
* `provision_timeout_seconds` (the preferred path post-#2054).
|
||||
*
|
||||
* Each override must also ship with a comment explaining WHY the default
|
||||
* is wrong for this runtime. Unexplained numbers rot.
|
||||
*
|
||||
* Empty today — `hermes` previously lived here at 720_000ms, but
|
||||
* Molecule-AI/molecule-ai-workspace-template-hermes now declares the
|
||||
* value in its config.yaml manifest, so the value flows through the
|
||||
* server (workspace API → WorkspaceData.provision_timeout_ms → resolver
|
||||
* overrides) instead of being canvas-hardcoded. New runtimes that need
|
||||
* a non-default cold-boot threshold should follow the same pattern:
|
||||
* declare `runtime_config.provision_timeout_seconds` in their template
|
||||
* manifest, NOT add an entry here.
|
||||
*/
|
||||
export const RUNTIME_PROFILES: Record<string, RuntimeProfile> = {
|
||||
hermes: {
|
||||
// 12 min. Installs ripgrep + ffmpeg + node22 + builds hermes-agent
|
||||
// from source + Playwright + Chromium (~300MB download). Measured
|
||||
// cold boots on staging EC2 routinely land at 8-13 min. Aligns
|
||||
// with SaaS E2E's PROVISION_TIMEOUT_SECS=900 (15 min) so the UI
|
||||
// warning lands shortly before the backend itself gives up.
|
||||
provisionTimeoutMs: 720_000,
|
||||
},
|
||||
};
|
||||
export const RUNTIME_PROFILES: Record<string, RuntimeProfile> = {};
|
||||
|
||||
/**
|
||||
* Data fields the canvas can consult for per-workspace overrides. These
|
||||
|
||||
Loading…
Reference in New Issue
Block a user