Skip to content

feat: unify fleet config schema across ecs and k8s runtimes - #145

Merged
brettchien merged 6 commits into
mainfrom
feat/unify-fleet-runtime-config
Sep 6, 2026
Merged

feat: unify fleet config schema across ecs and k8s runtimes#145
brettchien merged 6 commits into
mainfrom
feat/unify-fleet-runtime-config

Conversation

@brettchien

Copy link
Copy Markdown
Contributor

Summary

Brett (2026-09-06): the fleet config should host ECS and k8s (and later runtimes) under one schema, not a parallel file/type per runtime. This was flagged before — ADR-2 ("RuntimeDriver is the only layer with vendor terms"), manifest.rs::Runtime's tagged-enum precedent, and the 2026-08-18 openab-pty discussion ("one control plane, multiple kinds") — but the FleetBinding/K8sFleetBinding config-binding layer never got the same treatment when k8s support landed (studio#63 slice 3f).

  • studio-cp: FleetBinding/K8sFleetBinding (two structs, two files — fleets.toml/fleets-k8s.toml) collapse into one FleetBinding with a required runtime: "ecs" | "k8s" field (no default — Brett: explicit, not inferred) plus ECS-only (cluster/region/profile) and k8s-only (context/namespace) fields side by side.
  • Two idempotent startup migrations, wired into OabMcp::from_env in order: (1) normalize_bindings_runtime_field — rewrites any pre-existing fleets.toml entry lacking runtime to add runtime = "ecs" explicitly (targeted line insertion, not a TOML reserialize — comments/layout survive); (2) migrate_legacy_k8s_bindings — folds a legacy fleets-k8s.toml's entries into fleets.toml as runtime = "k8s" blocks, renaming the old file to .migrated (never deleted).
  • oab-mcp: k8s_fleet_config/k8s_fleet_config_write tools removed; fleet_config/fleet_config_write now read/write both runtimes from the one file.
  • src-tauri: matching bridge-command removal. Not locally verifiablestudio-desktop isn't in this workspace and needs macOS/GTK system libs this environment doesn't have; only the bundle-macos CI job builds it. Reviewed by hand against the surrounding bridge functions' pattern.
  • console: FleetConfig/K8sFleetConfig types collapse into one (FleetConfigEntry.runtime discriminant); fleetsK8sToml.ts is gone, appendFleetBlock in fleetToml.ts takes a runtime discriminant and writes the matching keys. deploy.ts's New Fleet wizard always goes through the one fleetConfig()/writeFleetConfig(). render.ts shows cluster (ecs) or context/namespace (k8s) per fleet.

Known gap, not introduced by this PR: k8s fleets still have no roster/observe UI in the console (main.ts's tick/refresh/selectFleet are ECS-cluster-keyed) — selectFleet declines to switch onto a k8s fleet with a clear message rather than silently breaking. This was already a known gap before this PR (k8s fleets simply weren't visible in the config panel at all); this PR makes them visible in the Fleets list without pretending the roster-switch works yet.

Test plan

  • cargo test -p studio-cp --lib — 35/35 passing (incl. migration + normalize round-trip tests)
  • cargo test -p oab-mcp --lib — 3/3 passing
  • cargo check --workspace --exclude studio-desktop — clean
  • npm run typecheck (console) — passes
  • npm test (console, vitest) — 101/101 passing
  • npm run build (console) — passes
  • Manual: open Studio, confirm the Fleets panel shows the migrated k8s fleet(s) from your existing fleets-k8s.toml after first launch on this branch, and that src-tauri's bridge removal doesn't break the New Fleet wizard's k8s path (no local signal for this layer)

🤖 Generated with Claude Code

fleets.toml (AWS) and fleets-k8s.toml (k8s) were two independent
types/files (FleetBinding/K8sFleetBinding) — the same anti-pattern the
2026-08-18 openab-pty thread flagged ("one control plane, multiple
kinds": a new runtime should be a variant of the existing schema, not
a parallel one), and inconsistent with manifest.rs::Runtime's existing
tagged-enum precedent.

FleetBinding now carries a `runtime: FleetRuntime` (ecs default, or
k8s) with ECS-only (cluster/region/profile) and k8s-only
(context/namespace) fields alongside shared ones. migrate_legacy_k8s_bindings
folds an existing fleets-k8s.toml into fleets.toml once at startup and
renames the legacy file to .migrated (never deletes it).

Ref: Brett 2026-09-06 ("fleet config should host ecs and k8s and all
later possible options").
Brett 2026-09-06: runtime should always be explicit in fleets.toml, not
silently inferred. Adds normalize_bindings_runtime_field (wired into
OabMcp::from_env ahead of migrate_legacy_k8s_bindings) to rewrite
pre-existing entries with an explicit `runtime = "ecs"` line once, since
every binding written before this field existed was ECS.
fleet_config/fleet_config_write now read/write both ecs and k8s
runtime fleets from the one fleets.toml; k8s_fleet_config/
k8s_fleet_config_write are gone (nothing else in this crate referenced
the old parallel fleets-k8s.toml path). from_env runs the two
studio-cp migrations (normalize then merge-legacy-k8s) before loading
bindings. target() rejects naming a k8s-runtime fleet from an
ecs-only tool with a clear error instead of a type error.
Mirrors the oab-mcp tool removal — fleet_config/fleet_config_write now
cover both runtimes. NOTE: this crate (studio-desktop) can't be built
or tested in this environment (not in the workspace, needs macOS/
GTK system libs — only the bundle-macos CI job builds it). Reviewed by
hand against the surrounding bridge functions' pattern; no local signal.
Collapses the console-side split that mirrored the old Rust one:
FleetConfigEntry now carries `runtime: "ecs" | "k8s"` with the two
runtimes' fields alongside each other; fleetsK8sToml.ts is gone
(appendFleetBlock in fleetToml.ts takes a runtime discriminant and
writes the matching TOML keys, `runtime = "..."` always first since
it's required now). deploy.ts's wizard always reads/writes through
the one fleetConfig()/writeFleetConfig(), no more isK8s source-method
branching. render.ts shows cluster (ecs) or context/namespace (k8s)
depending on the fleet's runtime.

main.ts's selectFleet declines to switch the roster view onto a k8s
fleet (no cluster to point reads at) instead of silently breaking —
k8s fleets still have no roster/observe UI, a separate, larger gap
from this schema unification (flagged to Brett already).

typecheck + vitest (101/101) + production build all pass.
… fleet

Brett 2026-09-06: an empty members array should be written explicitly,
not omitted — omitting it reads as "forgot to migrate this field", not
"deliberately whole-namespace." (The console's appendFleetBlock already
always wrote members for newly-created fleets; this only affects the
legacy fleets-k8s.toml migration path.)
@brettchien
brettchien merged commit 8694206 into main Sep 6, 2026
2 checks passed
@brettchien
brettchien deleted the feat/unify-fleet-runtime-config branch September 6, 2026 12:55
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