Skip to content

feat(canvas): per-workspace provision_timeout_ms override (#2054 phase 1) - #2092

Merged
HongmingWang-Rabbit merged 2 commits into
stagingfrom
feat/per-node-provision-timeout-2054
Apr 26, 2026
Merged

HongmingWang-Rabbit merged 2 commits into
stagingfrom
feat/per-node-provision-timeout-2054

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

[Molecule-Platform-Evolvement-Manager]

Phase 1 of #2054 — build the canvas foundation that lets a workspace carry its own `provision_timeout_ms` from a server-side source (e.g. template manifest), so a slow runtime can declare its cold-boot expectation without a canvas release.

Today's gap

`ProvisioningTimeout.tsx:144` resolved the timeout via:
```ts
const base = timeoutMs ?? provisionTimeoutForRuntime(node.runtime);
```
`timeoutMs` was a single Props-level value that applied to all nodes — fine for tests but wrong for production where a batch can mix runtimes (hermes 12-min cold-boot alongside docker 2-min). The runtime profile fallback already handled per-runtime defaults; the missing layer was per-WORKSPACE override above that.

Fix (resolution priority, most specific wins)

  1. `node.provisionTimeoutMs` — server-declared per-workspace override (this PR's new field)
  2. `timeoutMs` prop — single-threshold test override
  3. Runtime profile in `@/lib/runtimeProfiles`
  4. `DEFAULT_RUNTIME_PROFILE`

Changes

File What
`src/store/socket.ts` `WorkspaceData.provision_timeout_ms?: number | null`
`src/store/canvas.ts` `WorkspaceNodeData.provisionTimeoutMs?: number | null`
`src/store/canvas-topology.ts` hydrate threads field onto `node.data`
`src/components/ProvisioningTimeout.tsx` serialized-node string carries 4th positional field; resolver call passes `{provisionTimeoutMs: node.provisionTimeoutMs ?? timeoutMs}`
`src/components/tests/ProvisioningTimeout.test.tsx` 3 new tests

Tests (3 new — 19 total)

  • hydrate carries `provision_timeout_ms` onto node data
  • absent value hydrates to null + fall-through to runtime profile works
  • server override wins over runtime profile via the resolver path the component actually uses

19/19 pass locally.

Phases

  • Phase 1 (this PR): canvas foundation. Field plumbs through socket → node-data → resolver. Field is unused server-side until Phase 2 — pure infra, no behavior change today.
  • Phase 2 (follow-up): `workspace-server` reads `provision_timeout_seconds` from template `config.yaml` at provision time, includes `provision_timeout_ms` in the workspace API/socket response.
  • Phase 3 (template-repo PR): `template-hermes config.yaml` declares `provision_timeout_seconds: 720`; canvas `RUNTIME_PROFILES.hermes` becomes redundant + can be removed.

Test plan

  • CI green
  • No regression on hermes provisioning UX (still 12-min threshold via runtime profile fall-through, since no server data lands until Phase 2)

HongmingWang-Rabbit and others added 2 commits April 26, 2026 06:02
Phase 1 of moving runtime UX knobs server-side. Builds the canvas
foundation: a workspace can carry its own provision_timeout_ms
(sourced server-side from a template manifest in a follow-up PR),
and ProvisioningTimeout's resolver respects it per-node.

Today the resolver had Props-level timeoutMs that applied to ALL
nodes — fine for tests but wrong for production where one batch
could mix runtimes (hermes 12-min cold boot alongside docker 2-min).
The runtime profile fallback already handles per-runtime defaults;
this PR adds the per-WORKSPACE override layer above that.

Resolution priority (most specific wins):
  1. node.provisionTimeoutMs — server-declared per-workspace
     override (this PR's new field)
  2. timeoutMs prop — single-threshold test override
  3. runtime profile in @/lib/runtimeProfiles
  4. DEFAULT_RUNTIME_PROFILE

Changes:
- WorkspaceData (socket): add optional provision_timeout_ms
- WorkspaceNodeData: add optional provisionTimeoutMs
- canvas-topology hydrate: thread the field through to node.data
- ProvisioningTimeout: extend the serialized-string node iteration
  to carry provisionTimeoutMs (4-field positional split); pass as
  the second arg to provisionTimeoutForRuntime
- 3 new tests in ProvisioningTimeout.test.tsx covering hydrate
  threading, null fall-through, and resolver priority

Phase 2 (separate PR, blocked on workspace-server template-config
loader): workspace-server reads provision_timeout_seconds from
template config.yaml at provision time, includes
provision_timeout_ms in the workspace API/socket response. Phase 3
(template-repo PR): template-hermes config.yaml declares
provision_timeout_seconds: 720; canvas RUNTIME_PROFILES.hermes
becomes redundant and can be removed.

19/19 tests pass (3 new + 16 existing).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…zed-node string

simplify-review note: the |/,-delimited node string is brittle if a
future string-typed field is added without sanitization. Document
which fields are user-typed (name — already sanitized) vs primitive
(id is UUID, runtime is a slug, provisionTimeoutMs is numeric) so
the next field-add doesn't accidentally introduce an injection
vector for the splitter.

Skipped (false-positive review finding): the agent flagged the
prop > runtime-profile order as inconsistent with the docstring,
but the docstring explicitly lists the prop at #2 (between node and
runtime-profile) — matches both the implementation AND the original
behavior pre-#2054 (the prop was 'timeoutMs ?? runtime-profile').

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant