refactor(workspace-server): SSOT consolidation for BYO-compute meta-runtimes #2895

Open
agent-dev-b wants to merge 1 commits from fix/byo-compute-meta-runtime-ssot into main
Member

Summary

Per PM-triage approval (bounded-fill, low-priority): SSOT consolidation for the BYO-compute meta-runtime set (external, kimi, kimi-cli). The same 3 names were previously hardcoded in 4 separate sites with 3 different shapes — adding a new BYO-compute meta-runtime required updating all 4 in lockstep. Now a single var externalLikeRuntimes = []string{"external", "kimi", "kimi-cli"} drives all 4.

The drift surface (4 sites, 3 shapes)

# Location Shape (pre-PR)
1 runtime_registry.go:76-88 (fallbackRuntimes map) map[string]struct{}{"external": {}, "kimi": {}, "kimi-cli": {}, ...}
2 runtime_registry.go:109-122 (loadRuntimesFromManifest injection) map[string]struct{}{"external": {}, "kimi": {}, "kimi-cli": {}, "mock": {}}
3 runtime_registry.go:144 (isExternalLikeRuntime switch) case "external", "kimi", "kimi-cli": return true
4 workspace.go:400 (error message) "external workspaces must use runtime \"external\", \"kimi\", or \"kimi-cli\""

isExternalLikeRuntime (#3) is called in 4 different files (plugins.go:245, discovery.go:142, discovery.go:187, registry.go:186). So the SSOT in #3 already drives 4 caller sites; consolidating all 4 means the entire BYO-compute meta-runtime set is provably the same everywhere.

The existing runtime_registry.go docstring (lines 7-15) already documents a prior drift incident in this file: "knownRuntimes was a hardcoded Go map in workspace_provision.go, kept in sync MANUALLY...". This PR eliminates the next drift surface (the BYO-compute meta-runtime set) in the same file.

Changes

File Lines Purpose
workspace-server/internal/handlers/runtime_registry.go +92/-23 New externalLikeRuntimes SSOT; new joinExternalLikeRuntimesForMessage() helper; derive all 3 sites from SSOT; isExternalLikeRuntime switch → loop
workspace-server/internal/handlers/workspace.go +5/-1 Error message now uses joinExternalLikeRuntimesForMessage()
workspace-server/internal/handlers/runtime_registry_test.go +92/-0 New TestExternalLikeRuntimesConsistent pin test

Total: +188/-25 across 3 files.

Behavior-preserving

The pin test (TestExternalLikeRuntimesConsistent) asserts identical resolved shapes before and after the consolidation:

  • externalLikeRuntimes length and order match {"external", "kimi", "kimi-cli"} exactly
  • fallbackRuntimes contains the SSOT + claude-code / hermes / openclaw / codex / mock (8 entries total — same as pre-PR)
  • loadRuntimesFromManifest injects the SSOT + mock (4 entries — same as pre-PR)
  • isExternalLikeRuntime returns true for each SSOT entry and false for claude-code / hermes / openclaw / codex / mock / unknown-runtime-xyz (same as pre-PR)
  • joinExternalLikeRuntimesForMessage() produces the exact wire shape "external", "kimi", or "kimi-cli"
  • The full workspace.go:400 error body is external workspaces must use runtime "external", "kimi", or "kimi-cli" (verbatim preserved)

No API contract change, no migration, no test deletion, no caller update.

Verification

  • go build ./... — clean
  • go vet ./internal/handlers/ — clean
  • gofmt -l — clean
  • go test ./internal/handlers/ — 25.3s, all green
  • TestExternalLikeRuntimesConsistent — PASS
  • All 5 existing TestLoadRuntimesFromManifest_* / TestInitTemplateRepoByName_* tests pass unchanged

Out of scope (per PM scope agreement)

  • Canvas TS RUNTIME_OPTIONS list (canvas/src/components/tabs/ContainerConfigTab.tsx:48) — out of lane for a Go-side bounded fill, and the user-facing canvas dropdown has different semantics (it's a list of all user-selectable runtimes, not just the BYO-compute subset).
  • Renaming mock into the externalLikeRuntimes set — intentionally separate. mock is virtual-only (no container, no EC2), never user-selected (only the funding-demo org uses it), and has different A2A-reply semantics. Folding it into the SSOT would conflate "BYO-compute meta-runtime" (user-facing) with "virtual test runtime" (test-only). The pin test asserts mock is in fallbackRuntimes and in the loadRuntimesFromManifest injection but NOT in externalLikeRuntimes — locks the boundary.

Routing

Routes to 1-genuine (low-priority, per PM scope agreement). Will not block the security / main-red queue. No self-merge. Will pivot off this work instantly if any of (a) #2853 re-review RC, (b) Kimi #2851 Go-consumption request, (c) driver's #2818 scope call lands.

🤖 Generated with Claude Code

## Summary Per PM-triage approval (bounded-fill, low-priority): SSOT consolidation for the BYO-compute meta-runtime set (`external`, `kimi`, `kimi-cli`). The same 3 names were previously hardcoded in **4 separate sites with 3 different shapes** — adding a new BYO-compute meta-runtime required updating all 4 in lockstep. Now a single `var externalLikeRuntimes = []string{"external", "kimi", "kimi-cli"}` drives all 4. ## The drift surface (4 sites, 3 shapes) | # | Location | Shape (pre-PR) | |---|---|---| | 1 | `runtime_registry.go:76-88` (`fallbackRuntimes` map) | `map[string]struct{}{"external": {}, "kimi": {}, "kimi-cli": {}, ...}` | | 2 | `runtime_registry.go:109-122` (`loadRuntimesFromManifest` injection) | `map[string]struct{}{"external": {}, "kimi": {}, "kimi-cli": {}, "mock": {}}` | | 3 | `runtime_registry.go:144` (`isExternalLikeRuntime` switch) | `case "external", "kimi", "kimi-cli": return true` | | 4 | `workspace.go:400` (error message) | `"external workspaces must use runtime \"external\", \"kimi\", or \"kimi-cli\""` | `isExternalLikeRuntime` (#3) is called in 4 different files (`plugins.go:245`, `discovery.go:142`, `discovery.go:187`, `registry.go:186`). So the SSOT in #3 already drives 4 caller sites; consolidating all 4 means the entire BYO-compute meta-runtime set is provably the same everywhere. The existing `runtime_registry.go` docstring (lines 7-15) already documents a prior drift incident in this file: "knownRuntimes was a hardcoded Go map in workspace_provision.go, kept in sync MANUALLY...". This PR eliminates the next drift surface (the BYO-compute meta-runtime set) in the same file. ## Changes | File | Lines | Purpose | |---|---|---| | `workspace-server/internal/handlers/runtime_registry.go` | +92/-23 | New `externalLikeRuntimes` SSOT; new `joinExternalLikeRuntimesForMessage()` helper; derive all 3 sites from SSOT; `isExternalLikeRuntime` switch → loop | | `workspace-server/internal/handlers/workspace.go` | +5/-1 | Error message now uses `joinExternalLikeRuntimesForMessage()` | | `workspace-server/internal/handlers/runtime_registry_test.go` | +92/-0 | New `TestExternalLikeRuntimesConsistent` pin test | Total: **+188/-25** across 3 files. ## Behavior-preserving The pin test (`TestExternalLikeRuntimesConsistent`) asserts **identical resolved shapes** before and after the consolidation: - `externalLikeRuntimes` length and order match `{"external", "kimi", "kimi-cli"}` exactly - `fallbackRuntimes` contains the SSOT + `claude-code` / `hermes` / `openclaw` / `codex` / `mock` (8 entries total — same as pre-PR) - `loadRuntimesFromManifest` injects the SSOT + `mock` (4 entries — same as pre-PR) - `isExternalLikeRuntime` returns `true` for each SSOT entry and `false` for `claude-code` / `hermes` / `openclaw` / `codex` / `mock` / `unknown-runtime-xyz` (same as pre-PR) - `joinExternalLikeRuntimesForMessage()` produces the exact wire shape `"external", "kimi", or "kimi-cli"` - The full `workspace.go:400` error body is `external workspaces must use runtime "external", "kimi", or "kimi-cli"` (verbatim preserved) No API contract change, no migration, no test deletion, no caller update. ## Verification - `go build ./...` — clean - `go vet ./internal/handlers/` — clean - `gofmt -l` — clean - `go test ./internal/handlers/` — 25.3s, all green - `TestExternalLikeRuntimesConsistent` — PASS - All 5 existing `TestLoadRuntimesFromManifest_*` / `TestInitTemplateRepoByName_*` tests pass unchanged ## Out of scope (per PM scope agreement) - **Canvas TS `RUNTIME_OPTIONS` list** (`canvas/src/components/tabs/ContainerConfigTab.tsx:48`) — out of lane for a Go-side bounded fill, and the user-facing canvas dropdown has different semantics (it's a list of *all* user-selectable runtimes, not just the BYO-compute subset). - **Renaming `mock` into the `externalLikeRuntimes` set** — intentionally separate. `mock` is virtual-only (no container, no EC2), never user-selected (only the funding-demo org uses it), and has different A2A-reply semantics. Folding it into the SSOT would conflate "BYO-compute meta-runtime" (user-facing) with "virtual test runtime" (test-only). The pin test asserts `mock` is in `fallbackRuntimes` and in the `loadRuntimesFromManifest` injection but NOT in `externalLikeRuntimes` — locks the boundary. ## Routing Routes to **1-genuine** (low-priority, per PM scope agreement). Will not block the security / main-red queue. No self-merge. Will pivot off this work instantly if any of (a) #2853 re-review RC, (b) Kimi #2851 Go-consumption request, (c) driver's #2818 scope call lands. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
agent-dev-b added 1 commit 2026-06-15 00:26:37 +00:00
refactor(workspace-server): SSOT consolidation for BYO-compute meta-runtimes
CI / Python Lint & Test (pull_request) Successful in 5s
E2E Peer Visibility (literal MCP list_peers) / detect-changes (pull_request) Successful in 5s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (local) (pull_request) Has been skipped
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 6s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
Harness Replays / detect-changes (pull_request) Successful in 9s
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (pull_request) Successful in 6s
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
security-review / approved (pull_request_target) Failing after 8s
sop-checklist / na-declarations (pull_request) N/A: (none)
qa-review / approved (pull_request_target) Failing after 11s
CI / Detect changes (pull_request) Successful in 15s
sop-checklist / all-items-acked (pull_request_target) Successful in 8s
reserved-path-review / reserved-path-review (pull_request_target) Successful in 10s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 15s
gate-check-v3 / gate-check (pull_request_target) Failing after 14s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 1s
E2E Chat / detect-changes (pull_request) Successful in 17s
CI / Canvas (Next.js) (pull_request) Successful in 3s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 20s
CI / Canvas Deploy Status (pull_request) Successful in 1s
E2E Chat / E2E Chat (pull_request) Successful in 3s
E2E API Smoke Test / detect-changes (pull_request) Successful in 23s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 2s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 30s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 35s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 32s
Harness Replays / Harness Replays (pull_request) Successful in 1m12s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m29s
CI / Platform (Go) (pull_request) Successful in 2m40s
CI / all-required (pull_request) Successful in 4s
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m38s
c7d75fed19
Per PM-triage approval (bounded-fill, low-priority): consolidate
the BYO-compute meta-runtime set (external, kimi, kimi-cli) into
a single SSOT. Before this PR the same 3 names were hardcoded
in 4 separate sites with 3 different shapes:

1. runtime_registry.go:76-88  fallbackRuntimes map (3 entries)
2. runtime_registry.go:109-122 loadRuntimesFromManifest injection
3. runtime_registry.go:144     isExternalLikeRuntime switch
4. workspace.go:400             error message string literal

Adding a new BYO-compute meta-runtime required updating all 4
sites in lockstep; missing one was a silent drift surface. Now
a single var externalLikeRuntimes = []string{"external", "kimi",
"kimi-cli"} drives all 4.

CHANGES
=======

1. runtime_registry.go: new const-style var externalLikeRuntimes
   is the SINGLE source of truth. fallbackRuntimes builds itself
   from externalLikeRuntimes + the (intentionally-separate) mock
   entry. loadRuntimesFromManifest injects the SSOT into its
   result map the same way. isExternalLikeRuntime converts from
   a hardcoded switch to a loop over the SSOT. New helper
   joinExternalLikeRuntimesForMessage() builds the Oxford-comma
   "external", "kimi", or "kimi-cli" string from the SSOT.

2. workspace.go:400: the 422 error body now uses
   fmt.Sprintf("external workspaces must use runtime %s",
   joinExternalLikeRuntimesForMessage()) so the user-facing
   string derives from the SSOT. A future SSOT change auto-
   propagates to the error message.

3. runtime_registry_test.go: new TestExternalLikeRuntimesConsistent
   pin test locks the resolved shape across all 4 sites. Asserts
   (a) externalLikeRuntimes length and order match {"external",
   "kimi", "kimi-cli"}; (b) fallbackRuntimes contains the SSOT
   + claude-code/hermes/openclaw/codex/mock; (c) isExternalLikeRuntime
   returns true for each SSOT entry and false for template-backed
   runtimes + unknown; (d) joinExternalLikeRuntimesForMessage()
   produces the exact wire shape "external", "kimi", or
   "kimi-cli"; (e) the full error string is preserved verbatim.

BEHAVIOR-PRESERVING
====================

The pin test asserts identical resolved shapes before and after
the consolidation:
  - fallbackRuntimes has the same 8 entries (4 template-backed +
    3 external-like + mock)
  - loadRuntimesFromManifest injects the same 4 entries (3
    external-like + mock) + the manifest-backed entries
  - isExternalLikeRuntime returns the same boolean for every
    runtime input (loop vs switch is mechanical)
  - The user-facing error message produces the same string for
    the same runtime set

No API contract change, no migration, no test deletion, no caller
update. Drift guard (the new pin test) PREVENTS future drift,
doesn't fix existing bugs.

VERIFICATION
============

  - go build ./...  clean
  - go vet ./internal/handlers/  clean
  - gofmt -l  clean
  - go test ./internal/handlers/  25.3s, all green
  - TestExternalLikeRuntimesConsistent  PASS
  - All 5 existing TestLoadRuntimesFromManifest_* / TestInitTemplateRepoByName_*
    tests pass unchanged

OUT OF SCOPE
============

- Canvas TS RUNTIME_OPTIONS list (out of lane for a Go-side
  bounded fill)
- Renaming "mock" into the external-like set (intentionally
  separate — mock is virtual-only, never user-selected, has
  different semantics around A2A replies)

Routes to 1-genuine (low-priority; will not block the security /
main-red queue). Per PM: "the review jam is capacity, not
PR-count, so one more low-pri queued PR doesn't hurt". No
self-merge.
Some optional checks failed
CI / Python Lint & Test (pull_request) Successful in 5s
E2E Peer Visibility (literal MCP list_peers) / detect-changes (pull_request) Successful in 5s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (local) (pull_request) Has been skipped
Handlers Postgres Integration / detect-changes (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 6s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 6s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
Required
Details
Harness Replays / detect-changes (pull_request) Successful in 9s
E2E Peer Visibility (literal MCP list_peers) / E2E Peer Visibility (pull_request) Successful in 6s
Required
Details
sop-checklist / all-items-acked (pull_request) acked: 0/7 — missing: comprehensive-testing, local-postgres-e2e, staging-smoke, +4 — body-unfilled: comprehensive-testing, local-postgres-e2
security-review / approved (pull_request_target) Failing after 8s
sop-checklist / na-declarations (pull_request) N/A: (none)
qa-review / approved (pull_request_target) Failing after 11s
CI / Detect changes (pull_request) Successful in 15s
sop-checklist / all-items-acked (pull_request_target) Successful in 8s
reserved-path-review / reserved-path-review (pull_request_target) Successful in 10s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 15s
gate-check-v3 / gate-check (pull_request_target) Failing after 14s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 1s
E2E Chat / detect-changes (pull_request) Successful in 17s
CI / Canvas (Next.js) (pull_request) Successful in 3s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 20s
CI / Canvas Deploy Status (pull_request) Successful in 1s
E2E Chat / E2E Chat (pull_request) Successful in 3s
E2E API Smoke Test / detect-changes (pull_request) Successful in 23s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 2s
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (stub) (pull_request) Successful in 30s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 35s
Required
Details
Local Provision Lifecycle E2E / Local Provision Lifecycle E2E (real image + MiniMax LLM, advisory) (pull_request) Successful in 32s
Harness Replays / Harness Replays (pull_request) Successful in 1m12s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m29s
Required
Details
CI / Platform (Go) (pull_request) Successful in 2m40s
CI / all-required (pull_request) Successful in 4s
Required
Details
E2E Staging External Runtime / E2E Staging External Runtime (pull_request) Successful in 5m38s
This pull request doesn't have enough required approvals yet. 0 of 1 official approvals granted.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin fix/byo-compute-meta-runtime-ssot:fix/byo-compute-meta-runtime-ssot
git checkout fix/byo-compute-meta-runtime-ssot
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2895