Plan: ./uis platform list / use + per-command platform banner
Status: Completed — shipped 2026-05-12
Shipped: PRs #161 (initial implementation) + #162 (F15 kubeconf-all seeding) + #163 (F16 legacy lockstep sync) + #164 (F18 pre-merge seed) + #165 (F17 destroyed-context cleanup). All seven Phases of this plan delivered.
Verified end-to-end in testing/uis1/talk/talk.md round-by-round across talks 48–51:
- talk48: initial verification — surfaced F14 (no-TTY exit in apply prompt), F15 (kubeconf-all not seeded), F16 (silent wrong-cluster deploy via legacy kubeconfig divergence), F17 (post-destroy
✗ unreachablecosmetic), F18 (seeder gate too narrow → recycle→up→use cascade). - talk49–50: each F-finding fixed in its own PR, with the lockstep mechanic re-verified each round.
- talk51 (final): full novice path (
./uis tools install azure-aks→init→up→deploy nginx→use rancher-desktopround-trip →down) ran end-to-end without manual intervention. All four locations (in-container kubeconf-all, legacy kubeconf-all,cluster-config.shCLUSTER_TYPE + TARGET_HOST) stayed in lockstep. F14/F15/F16/F18 closed; F17 closed in PR #165.
User-facing documentation lives in website/docs/platforms/index.md (the platform hub) and website/docs/platforms/azure-aks.md (the novice walkthrough). The CLI reference at website/docs/reference/uis-cli-reference.md carries the full subcommand list.
Source investigation (also moved to completed/ in the same docs PR): INVESTIGATE-active-cluster-visibility-ux.md.
IMPLEMENTATION RULES (historical): Before implementing this plan, read and follow:
- WORKFLOW.md - The implementation process
- PLANS.md - Plan structure and best practices
Status: Active (historical — kept for the plan record below)
Goal: Add ./uis platform list (potential platforms + status), ./uis platform use <name> (refuse-unless-initialized-and-reachable + lockstep flip), and a per-command banner at the top of every cluster-touching ./uis command — so a user with 2+ platforms can see what they have, switch safely between them, and tell what platform any command is targeting before it runs. Layer 4 + Layer 1 of INVESTIGATE-active-cluster-visibility-ux.md, bundled per Q2 / C-9.
Last Updated: 2026-05-12 — work started on branch feat/platform-list-use-and-banner.
Source: INVESTIGATE-active-cluster-visibility-ux.md — design questions Q1–Q5 + implementation contracts C-1 through C-9, locked through three gap-and-contradiction sweeps. This PLAN drafts the implementation against those contracts; design decisions don't get revisited here.
Related (context):
- INVESTIGATE-platform-aks-novice-onboarding.md — sibling investigation that shipped
./uis platform init / up / status / downvia PRs #154–#159. This PLAN extends the./uis platformfamily withlist+useand threads the banner through every cluster-touching command in the same image.
Problem Summary
talk47 closed the AKS novice-onboarding sequence with one operational gap: once the user has azure-aks + rancher-desktop both potentially in play (and eventually google-gke / aws-eks / azure-microk8s), there's no command that answers either "what platforms do I have here and what state is each in?" or "let me switch to a different one" without cat-ing config files by hand. And even when the user knows which platform they're on, no ./uis command surfaces it before running — so the talk41 stale-port-forward / talk44 phantom-replay class of bug remains live.
This PLAN closes both:
./uis platform list— directory-listing-driven inventory of every platform UIS knows how to onboard (plus the always-present rancher-desktop row). Each row shows a state from the C-1 enum (not-initialized/configured-not-running/running/unreachable) plus an inline recovery pointer when the platform isn't ready to use../uis platform use <name>— lockstep flip ofkubectl current-context+cluster-config.shfor arunning-and-reachable platform. Refuses with a pointer otherwise.--offlineescape for the "I know it's broken, switch anyway" case.- Per-command platform banner — every cluster-touching
./uiscommand (deploy,expose,configure,undeploy,status,list,stack install,test-all, plus the./uis platformfamily itself) emits a one-line banner before its first action, naming the active platform and confirming reachability. Aborts with a recovery banner if the cluster is unreachable.
The lockstep flip (Q4) is the most invasive piece — it extracts the existing sed -i writes from 02-post-apply.sh (auto-flip on up) and 03-destroy.sh (auto-reset on down) into a single shared writer in provision-host/uis/lib/platform-switching.sh, then routes all three call sites (up / down / new use) through it. The investigation's "lockstep, never read independently" guarantee for cluster-config.sh only holds if all three writers converge.
Out of Scope
- Layer 2 — coloured PS1 inside
./uis shell. Deferred to a separate PLAN (PLAN-ps1-cluster-tag.md) — touches the container's bashrc and the Dockerfile, lower priority because Layer 1's banner covers in-shell users too. - Layer 3 —
./uis statuscluster header. Deferred toPLAN-uis-status-cluster-header.md— trivial once banner machinery exists, but distinct enough to ship after Layer 4+1 verifies. - Host-side kubectl integration (
k9s,lens, rawkubectlfrom macOS Terminal). The lockstep flip targets onlykubeconf-allinside the container — host's~/.kube/configis the user's environment. See the investigation's "Out of scope" section. - Removing
cluster-config.shentirely. Q4's lockstep design makes it a cached projection; a future PLAN could drop it outright once nothing reads it independently. Out of scope here. - Cross-cluster broadcasts (deploying once to multiple platforms). UIS stays single-cluster-per-invocation.
- Production-vs-sandbox enforcement / typed-name confirms for
use. Future PLAN once Layer 2's colour scheme tags platforms by sensitivity. - Provisioning new platforms from
list.listshows what exists; provisioning is./uis platform up <name>. No "click to provision" affordance.
Phase 1: Shared helper provision-host/uis/lib/platform-switching.sh
The single source of truth for: (1) the reachability probe primitive, (2) the lockstep writer, (3) inventory enumeration, (4) parsing per-platform status.sh --summary output. Consumers: list, use, the per-command banner, 02-post-apply.sh's auto-flip-on-up, 03-destroy.sh's auto-reset-on-down.
Before writing this file, read PLANS.md § Library Reuse Rules — verify nothing already in provision-host/uis/lib/ covers what's needed and that nothing here duplicates paths.sh / utilities.sh / logging.sh functions. New functionality only.
Tasks
-
1.1 Create
provision-host/uis/lib/platform-switching.shwith the following functions. Names are illustrative; the function signatures + behaviors must match the contracts. All functions defensive:set -euo pipefailat start of each, no|| truemasking, no regex on JSON.pf_active_platform()— print the active kubectl context to stdout. Empty string if unset. Readskubectl config current-contextfromkubeconf-all.pf_probe_reachable <context>— return 0 if reachable, non-zero otherwise. Implementation:kubectl --context "$1" --request-timeout=3s get --raw /version >/dev/null 2>&1. Used by C-9 banner + by C-1 state machine.pf_lockstep_flip <platform>— atomic write of both halves:kubectl config use-context "$platform"ANDsed -ioncluster-config.shupdatingCLUSTER_TYPE+TARGET_HOSTto$platform. Single call site for the three converging writers (Phase 6).pf_list_platforms()— emit the inventory to stdout, one platform name per line. Source:platforms/*/scripts/init.shdirectory listing, skipping any directory whose name starts with_or.(per Edge case #8). Hard-codesrancher-desktopas the first row (always present).pf_platform_summary <platform> [--offline]— invoke<platform>/scripts/status.sh --summary [--offline], capture the tab-separated<state>\t<hint>output, validate field 1 is in the C-1 enum, and emit it on stdout. Non-zero exit if thestatus.sherrors or returns malformed output (caller renders? errorfor that row).pf_banner [--silent-if-set] [--check-reachable]— print the Layer 1 banner to stderr per C-9. HonorsUIS_BANNER_PRINTED=1env var (set by parent dispatcher to suppress in child invocations, per C-4) when--silent-if-setis passed. With--check-reachable, runspf_probe_reachableon the active context and emits the four C-9 cases (reachable / unreachable+abort / not-in-platforms / unset). The active platform name comes frompf_active_platform. For the unreachable case, callspf_platform_summaryon the active platform to pull the platform-specific recovery hint from field 2.
-
1.2
chmod +xnot applicable (sourced library, not invoked).
Validation (Phase 1)
- 1.3
bash -n provision-host/uis/lib/platform-switching.shparses cleanly. - 1.4 Source standalone in a bash subshell, verify each function resolves:
( source provision-host/uis/lib/platform-switching.sh && for f in pf_active_platform pf_probe_reachable pf_lockstep_flip pf_list_platforms pf_platform_summary pf_banner; do type -t "$f" >/dev/null || { echo "missing: $f"; exit 1; }; done && echo "all functions sourceable" ). - 1.5 Manual smoke against the running container:
pf_active_platformreturns the current context (probablyrancher-desktoppost-talk47 destroy);pf_probe_reachable rancher-desktopreturns 0;pf_list_platformsemitsrancher-desktop+azure-akson separate lines.
Phase 2: Per-platform status.sh --summary contracts (C-1)
Two scripts: extend the existing azure-aks/scripts/status.sh with --summary and --offline flags, and add a new trivial rancher-desktop/scripts/status.sh that owns its 3-of-4 state machine per C-1's rancher-desktop subsection.
Tasks
-
2.1 Extend
platforms/azure-aks/scripts/status.shwith a--summaryflag:- Without flag: keeps existing human-readable multi-line banner (no behavior change).
- With
--summary: emits exactly one tab-separated line<state>\t<hint>to stdout per the C-1 enum + state-machine discriminator. Reads env file presence at.uis.secrets/cloud-accounts/azure-default.env, kubectl context presence inkubeconf-all, and runspf_probe_reachable azure-aksonly when both above are present. Hard-codes--context azure-aksper C-1's cross-context invocation rule (mirrors PR #158's F12 fix). - With
--summary --offline: same as--summarybut skips the probe entirely; state outcome follows C-7's reduced table. - With
--summary --deep: same as--summarybut additionally runs the cloud-API check (az aks show) for richer status (cluster age, node-pool details). Sourced bylist --deep. Time bound: not constrained.
Hint text for each state (field 2):
not-initialized run './uis platform init azure-aks' to set up
configured-not-running run './uis platform up azure-aks' to start it
running <node-count>× <vm-size> in <region>, k8s <version>
unreachable API server timeout after 3s; run './uis platform status azure-aks' for details -
2.2 Create
platforms/rancher-desktop/scripts/status.sh— minimal status script for the always-present local platform. Mirrors azure-aks's--summarybehavior but uses the rancher-desktop 3-state machine (no env file;not-initializedreinterpreted as "Rancher Desktop not installed or not started"):not-initialized install Rancher Desktop and start it, then './uis start'
running local k8s, k3s <version>
unreachable start Rancher DesktopWithout
--summarythe script emits a short human-readable banner (matches azure-aks's no-flag shape but rancher-desktop has nothing cluster-cost-related to report). -
2.3
chmod +x platforms/rancher-desktop/scripts/status.sh.
Validation (Phase 2)
- 2.4
bash -n platforms/azure-aks/scripts/status.shandbash -n platforms/rancher-desktop/scripts/status.shparse cleanly. - 2.5 Manual smoke (current state, in the running container):
bash platforms/rancher-desktop/scripts/status.sh --summary→running\tlocal k8s, k3s ...(since the host's Rancher Desktop is running and probe succeeds).bash platforms/azure-aks/scripts/status.sh --summary→configured-not-running\trun './uis platform up azure-aks' to start it(env file from talk47 is preserved; no cluster).bash platforms/rancher-desktop/scripts/status.sh(no flag) → existing banner output, unchanged shape.bash platforms/azure-aks/scripts/status.sh(no flag) → existing banner output, unchanged.
- 2.6
--offlinesmoke:bash platforms/azure-aks/scripts/status.sh --summary --offlinereturns the same state as 2.5's azure-aks line, but without running the kubectl probe (measurable as <100ms viatime).
Phase 3: ./uis platform list command
New dispatcher case in uis-cli.sh, delegating to a new cmd_platform_list function.
Tasks
-
3.1 In
provision-host/uis/manage/uis-cli.sh, add alist)case tocmd_platform's subcommand switch, parallel toinit / up / status / down. Route tocmd_platform_list. -
3.2 Add
cmd_platform_listaftercmd_platform_status. Sourcesplatform-switching.sh. Accepts--offlineand--deepflags (mutually exclusive). Iteratespf_list_platforms()output, invokespf_platform_summary <platform> [--offline|--deep]per row in parallel (one background bash per platform,waitfor all, collect into an indexed array preserving order). Renders the table:Active: <pf_active_platform output or appropriate C-2 case>
PLATFORM STATUS
rancher-desktop ✓ running (active)
azure-aks · configured, not running (run './uis platform up azure-aks' to start it)Column widths: platform name padded to longest-name + 2 spaces; status icon + state words padded to "configured, not running" length + 3 spaces; hint flush.
Row visual treatment by C-1 state:
running→✓ running(green if TTY + notNO_COLOR=1)not-initialized→· not initialized(dim)configured-not-running→· configured, not running(dim)unreachable→✗ unreachable(red)- Malformed
status.sh --summaryoutput →? error(yellow)
Active row gets a trailing
(active)annotation; per C-2, if active context isn't a UIS platform OR isn't set, NO row gets(active)and the headerActive:line surfaces the external/unset state. -
3.3 Update
cmd_help'sPlatform:section to includeplatform list <provider?> List potential platforms and their statusbetweeninitandup. Use the host-runnable./uis ...form per the talk47 follow-up cosmetic memory.
Validation (Phase 3)
- 3.4
bash -n provision-host/uis/manage/uis-cli.shparses cleanly. - 3.5 Inside the container after Phase 2's status scripts ship + the binary is rebuilt:
uis platform list→ shows rancher-desktop running + azure-aks configured-not-running, completes under 500ms (time uis platform list).uis platform list --offline→ same rows but no probe runs; under 100ms.uis platform list --deep→ same rows but with extended hint text (1× Standard_B2s_v2 in westeurope, k8s 1.34for running azure-aks); 2-5s typical when AKS is up.uis help→platform listrow shown alongside the others, no "not yet implemented" tag.
Phase 4: ./uis platform use <name> command
New dispatcher case + the lockstep-flip command itself, routing through pf_lockstep_flip.
Tasks
-
4.1 In
cmd_platform's subcommand switch, add ause)case routing tocmd_platform_use. -
4.2 Add
cmd_platform_useaftercmd_platform_list. Sourcesplatform-switching.sh. Accepts--offlineflag and an optional<name>positional.- No
<name>→ interactive picker per C-8: print the same tablelistshows, but onlyrunningrows get[N]selectors; non-selectable rows appear without selectors with their inline pointer. Footer prompt:Pick a platform [1-N]:. Plainread -p, nofzf. - With
<name>→ callpf_platform_summary "$name", parse field 1, dispatch per Q5's enum table:not-initialized→ emit✗ <name> is not initialized.\n Run './uis platform init <name>' first.to stderr, exit non-zero.--offlinedoes NOT override.configured-not-running→ emit✗ <name> is configured but not running.\n Run './uis platform up <name>' to start it.to stderr, exit non-zero.--offlinedoes NOT override.running→ callpf_lockstep_flip "$name", emit✓ Switched: <from> → <name>to stdout (usingpf_active_platformfor the<from>value, captured before the flip), exit 0. If<name>equals the current active platform, treat as a no-op + reachability re-probe: emitℹ Already active: <name>. Re-probing... ✓ still reachable.and exit 0. If the re-probe fails, emit✗ <name> is no longer reachable (API server timeout after 3s).+ recovery hint, exit non-zero (active platform doesn't change).unreachable→ emit✗ <name> is unreachable (API server timeout after 3s).\n Check the cluster state with './uis platform status <name>'.\n To switch anyway (e.g. to clean up stale kubectl state), use --offline.to stderr, exit non-zero.--offlineoverrides this case only: callpf_lockstep_flipdespite reachability failure, emit the✓ Switched: ... (forced; cluster not reachable)form.
- No
-
4.3 Update
cmd_helpto add aplatform use <provider>row.
Validation (Phase 4)
- 4.4
bash -nclean. - 4.5 Inside the container (rancher-desktop running, azure-aks env file present but no cluster):
uis platform use rancher-desktop(already active) →ℹ Already active... ✓ still reachable., exit 0.uis platform use azure-aks→ refuses withconfigured-not-runningpointer at./uis platform up azure-aks, exit 1.uis platform use google-gke→ refuses withnot-initializedpointer at./uis platform init google-gke, exit 1.uis platform use azure-aks --offline→ also refuses (configured-not-running can't be overridden), exit 1.uis platform use(no arg) → interactive picker with only rancher-desktop selectable, azure-aks shown without[N]+ its pointer.
Phase 5: Layer 1 banner — inject into every cluster-touching ./uis command
Per Q2 + C-9: every cluster-touching command emits the banner to stderr before its first action. Implementation: each cmd_<verb> function in uis-cli.sh calls pf_banner --silent-if-set --check-reachable near its top, before delegating. --silent-if-set honors UIS_BANNER_PRINTED=1 for the stack install-child case (C-4).
Tasks
-
5.1 In
provision-host/uis/manage/uis-cli.sh, insertpf_banner --silent-if-set --check-reachableat the top of each cluster-touching command function, immediately after argument parsing:cmd_deploycmd_undeploycmd_configurecmd_exposecmd_statuscmd_list(the service-list, notcmd_platform_list)cmd_stack_install(parent — setsUIS_BANNER_PRINTED=1before invoking children)cmd_test_allcmd_platform_upcmd_platform_downcmd_platform_statuscmd_platform_usecmd_platform_list
Skip (no banner) — these don't touch any cluster:
cmd_help,cmd_version,cmd_container,cmd_pull,cmd_build,cmd_start,cmd_stop,cmd_restart,cmd_shell,cmd_tools_*,cmd_init(the UIS-level setup wizard, not platform init),cmd_platform_init(creates an env file, no cluster touched yet).Wait —
cmd_platform_initdeserves a special note: it logs into Azure (cloud API) but doesn't touch a kubernetes cluster. Per Q2 the banner is for cluster-touching commands. Markinitas not-cluster-touching → no banner. Matches the principle that init writes the env file; nothing kubernetes happens untilup. -
5.2 In
cmd_stack_installspecifically, setexport UIS_BANNER_PRINTED=1after the parent banner prints, before fanning out to child./uis deploy <service>calls. Per C-4 this is the only place the env var is needed.
Validation (Phase 5)
- 5.3 Inside the container:
uis deploy nginx→ bannerℹ Platform: rancher-desktop (reachable)to stderr before the deploy starts. Pipe test:uis deploy nginx 2>/dev/nullsuppresses the banner;uis deploy nginx >/dev/nullkeeps it visible.uis help→ no banner (informational command).uis tools install azure-aks(already installed) → no banner (tools commands don't touch clusters).uis platform up azure-aks(no env file → refuses early) → banner not relevant because the command refuses before doing cluster work; need to think about ordering — see Implementation Notes.
- 5.4 Manual
unreachabletest: with kubectl context set to something unreachable, runuis deploy nginx— expects the unreachable banner block + abort, exit 1. Concrete repro:kubectl config use-context azure-aks(without an active cluster), thenuis deploy nginx.
Phase 6: Converge 02-post-apply.sh and 03-destroy.sh onto pf_lockstep_flip
The lockstep-flip writer in platform-switching.sh now owns the cluster-config.sh + kubectl-context write. Replace the existing sed -i blocks in 02-post-apply.sh (auto-flip on up) and 03-destroy.sh (auto-reset on destroy) with calls to the shared writer.
Tasks
-
6.1 In
platforms/azure-aks/scripts/02-post-apply.sh, replace the existingsed -i ... cluster-config.shblock (currently lines 102–115) with:source /mnt/urbalurbadisk/provision-host/uis/lib/platform-switching.sh
pf_lockstep_flip "$AZURE_AKS_CLUSTER_NAME" # flips kubectl + cluster-config.sh together -
6.2 In
platforms/azure-aks/scripts/03-destroy.sh, replace the existing reset block (currently lines 184–199) with:source /mnt/urbalurbadisk/provision-host/uis/lib/platform-switching.sh
pf_lockstep_flip "rancher-desktop" # symmetric reset on tear-down -
6.3 Move the kubeconfig-context-delete block in
03-destroy.sh(currently lines 171–177) intopf_lockstep_flipitself? No —pf_lockstep_flipis for switching to an existing context. Context deletion is its own operation. Leave thekubectl config delete-contextblock in03-destroy.shas-is, just before the reset to rancher-desktop.
Validation (Phase 6)
- 6.4
bash -non both edited scripts. - 6.5 Live: end-to-end cycle —
uis platform up azure-aksshould auto-flip via the shared writer;uis platform down azure-aksshould auto-reset via the shared writer. Comparecluster-config.shstate before/after each to confirm the writes happen. - 6.6 Defensive: after
up, manually editcluster-config.shto point atrancher-desktop(simulating external tampering). Then runuis deploy nginx— banner should detect the divergence... wait, no: the investigation explicitly drops the divergence banner case per N-C5. So instead: confirm that despite the manual edit, kubectl context still saysazure-aks(because the user only touched the cached projection, not the truth), anduis deploy nginxcorrectly targets azure-aks. The lockstep guarantee holds for reads via kubectl context.
Phase 7: Tester verification round
Single talk round covering everything Layer 4 + Layer 1 ships. Goal is end-to-end against CI-built :latest post-merge, mirroring the talk47 protocol.
Tasks
-
7.1 File the verification round at
testing/uis1/talk/talk.md, archiving the previous current round per the talk-naming protocol (mv talk.md talk<N>.md, freshtalk.md). -
7.2 Round outline (final talk.md):
- R0 — pull
:latest, confirmplatform-switching.sh+platform/rancher-desktop/scripts/status.sh+ updatedazure-aks/scripts/status.share present in the container;uis helpshowsplatform list+platform usein the Platform section. - R1 (Tier 1, ~5 min, €0) —
listanduseagainst the post-talk47 baseline (rancher-desktop running, azure-aks env file present, no cluster):uis platform list→ shows both rows correctly with the right statesuis platform list --offline→ same rows but no probe (verify withtime)uis platform use rancher-desktop(already active) → no-op + re-probeuis platform use azure-aks(configured-not-running) → refuses with pointer atupuis platform use google-gke(not-initialized) → refuses with pointer atinituis platform use(no arg) → interactive picker, only rancher-desktop selectableuis deploy nginx→ banner showsPlatform: rancher-desktop (reachable)to stderr, deploy proceeds to rancher-desktop
- R2 (Tier 2, ~25 min, ~€0.05–0.10) — full novice cycle with
useflipping between platforms:uis platform up azure-aks(still usespf_lockstep_flipinternally via Phase 6) — cluster upuis platform list→ both rows nowrunning, azure-aks marked(active)uis platform list --deep→ enhanced status with k8s version + node pooluis deploy nginx→ banner showsPlatform: azure-aks (reachable), nginx deploys to AKSuis platform use rancher-desktop→ success:✓ Switched: azure-aks → rancher-desktopuis deploy nginxagain → banner now showsPlatform: rancher-desktop, idempotent skipuis platform use azure-aks→ success: switched backuis platform down azure-aks→ tear-down + symmetric auto-reset to rancher-desktop via shared writeruis platform listafter down → azure-aks back toconfigured-not-running, rancher-desktop active
- R3 (banner safety, ~2 min, no spend) — simulate the talk41 stale-context scenario by manually breaking kubectl:
KUBECONFIG=/mnt/urbalurbadisk/kubeconfig/kubeconf-all kubectl config use-context <some-nonexistent>, thenuis deploy nginx. Banner should fire the unreachable block + abort, exit 1, no deploy attempted.
- R0 — pull
-
7.3 Tester rounds close green; any findings filed as F-numbered items follow up.
Validation (Phase 7)
- 7.4 Tester confirms R0 + R1 (Tier 1) green at minimum; R2 + R3 close the full bar.
Acceptance Criteria
-
provision-host/uis/lib/platform-switching.shexists with the 6 functions named in Phase 1, all sourceable + invocable standalone. -
platforms/azure-aks/scripts/status.shaccepts--summary/--offline/--deepflags and emits C-1-conformant output. Backward-compatible: no-flag invocation unchanged. -
platforms/rancher-desktop/scripts/status.shexists, runs in <100ms, implements the 3-state rancher-desktop machine. -
./uis platform listruns in <500ms with 2 platforms;--offline<100ms;--deepworks against a live AKS cluster. -
./uis platform use <name>correctly refuses fornot-initialized/configured-not-running/unreachable; succeeds with lockstep flip forrunning;--offlineoverrides only the unreachable case. - Every cluster-touching
./uiscommand emits the Layer 1 banner to stderr before its first action. -
02-post-apply.shand03-destroy.shboth route theircluster-config.shwrites throughpf_lockstep_flip— no remainingsed -i ... cluster-config.shblocks in either. - Tester closes R0 + R1 + R2 + R3 in the talk round.
- CI green on push: Test UIS Scripts, Build UIS Container, Generate UIS Documentation, Deploy Documentation.
- Local Docusaurus build clean for this PLAN file.
Implementation Notes
-
Banner before refusal banners. When
cmd_platform_up azure-aksis invoked with no env file,up.shrefuses early with✗ No config file found.... The Layer 1 banner needs to fire before this refusal (so the user sees what platform was attempted). The Q2-listed touch points (cmd_platform_up, etc.) get the banner at their top, before delegating to the per-platform script. The banner machinery thus needs to compute "active platform" even when the lifecycle script subsequently refuses — that's fine, the banner is about kubectl context, not about whether the platform is set up. -
Order of dispatch when active context isn't a UIS platform. If the user's kubectl context is a personal
prod-clusterand they run./uis deploy nginx, the banner emits the C-9 case-3 warning (not a UIS platform — proceeding with kubectl context anyway) and the deploy goes ahead againstprod-cluster. This matches Q5's spirit: UIS doesn't take ownership of contexts it doesn't manage; it just surfaces the situation. -
pf_bannercost on every command. Default reachability probe is ~50–200ms. For commands that don't actually need a cluster (e.g.uis statuswhen no services deployed), this is overhead the user can't opt out of. Acceptable per the investigation's stance — "the cost of one probe per command is the cost of not silently deploying to the wrong cluster". -
No probe cache. The investigation explicitly drops the
/tmpprobe cache idea. Each invocation re-probes; staleness can't accumulate. If session-level performance becomes a real problem, revisit with measurements. -
status.sh --summaryreads kubeconfig directly, doesn't shell out tokubectl config get-contexts. Parsekubeconf-allonce withawkor a singlekubectl config view --output jsonpathto get the context list — avoids multiple kubectl invocations perlistrow. -
Backward compat for
02-post-apply.sh/03-destroy.sh. The existingsed -iwrites have been in production through PR #149 and the talk44/45/46/47 cycles. Replacement viapf_lockstep_flipmust preserve the same outcome (same file contents post-write). Test by diffingcluster-config.shbefore/after a write in each call site under both old and new code. -
cluster-config.shCLUSTER_TYPE and TARGET_HOST. Per the investigation's Edge case #10, both fields always hold the same string.pf_lockstep_flipwrites both with the same value (matching the existing twosed -i -e ...invocations). -
No need for
cluster-config.shlocking. Per Edge case #9, concurrentusefrom two terminals is documented as "last write wins"; the lockstep writer issues both writes (kubectl + sed) back-to-back, sub-millisecond window. Engineering a lock would be overkill for the use case.
Files to Modify
New:
provision-host/uis/lib/platform-switching.shplatforms/rancher-desktop/scripts/status.sh
Modified:
platforms/azure-aks/scripts/status.sh— add--summary/--offline/--deepflags (backward-compat preserved)platforms/azure-aks/scripts/02-post-apply.sh— replacesed -iblock withpf_lockstep_flipcallplatforms/azure-aks/scripts/03-destroy.sh— replace reset block withpf_lockstep_flip "rancher-desktop"callprovision-host/uis/manage/uis-cli.sh— addcmd_platform_list+cmd_platform_use+list)/use)dispatcher cases + banner injection at ~13 command functions + help-banner row additions
No new platform directories beyond platforms/rancher-desktop/ (which is the always-present row from Q3).