Skip to content

fix(env): the multi-cluster scaffold's initial environment is invisible to env list, add and rm #6905

Description

@devantler

🤖 Generated by the Agentic Engineer

Evidence

Reproduced end to end with a binary built from main, in an empty directory. project init --multi-cluster prod scaffolds an environment named prod, and the env verbs then disagree about whether it exists:

$ ksail project init --multi-cluster prod
✚ created 'k8s/clusters/base/kustomization.yaml'
✚ created 'k8s/clusters/prod/kustomization.yaml'
✔ initialized project

$ ksail project env reconcile --experimental
ENVIRONMENT  OVERLAY        STATE
prod         clusters/prod  Present

$ ksail project env list
ℹ no environments declared; scaffold one with `ksail project env add <name> --from <env>`

$ ksail project env add staging --from prod
✗ failed to load source environment config (ksail.prod.yaml): ... no such file or directory

reconcile reports prod as a first-class declared environment; list reports none; add --from prod cannot find it. Same workspace, same moment.

The plain ksail project init path lands in the same place: it writes only ksail.yaml, so env list prints the identical hint, and there is no environment to pass to --from.

Root cause

The two verbs resolve "what is an environment" through different functions, and only one of them knows about the multi-cluster scaffold's initial environment:

  • environment.DerivePlan (used by env reconcile) calls appendBaseSyncedEntry, which reads the base ksail.yaml's kustomizationFile: clusters/prod and adds prod as a first-class entry. Its own comment names this case exactly: "the initial environment project init --multi-cluster scaffolds without a ksail..yaml".
  • environment.DeriveEnvironments (used by env list, by env add's --from load, by its available-environments hint, and by env rm) enumerates ksail.<name>.yaml files only, so the base-synced environment is invisible to all of them.

So the codebase already recognises this shape in one verb and not its siblings.

Affected audience and impact

Anyone following the multi-cluster path — the flow epic #5441 exists to support. Concretely:

  1. The advertised next step cannot be taken. env add --from is the only way to create a second environment, and the initial environment cannot be named as its source. The multi-cluster scaffold therefore stops at one environment.
  2. The CLI's own remediation hint is unfollowable in exactly the state where it is printed: there is no <env> to pass to --from, in either init mode. A guardrail that names a fix that cannot be applied trains people to distrust the message.
  3. env list contradicts env reconcile on the same workspace, so neither can be trusted as the answer to "what environments do I have?".

There is a workaround, but it is undocumented and requires knowing the file convention: hand-write a ksail.prod.yaml next to ksail.yaml, after which env list and env add --from prod both work.

Expected behaviour

The env verbs agree on what an environment is. The environment that project init --multi-cluster <name> creates is visible to env list, usable as env add --from <name>, and removable by env rm, without hand-writing a config file.

Proposed direction

Give DeriveEnvironments the same base-synced awareness DerivePlan already has — most cheaply by extracting the appendBaseSyncedEntry resolution so both call sites share it, which also guarantees the two verbs cannot drift apart again. Two details worth settling while implementing:

  • What env list should show for DISTRIBUTION/PROVIDER of a base-synced environment (they come from the base ksail.yaml, so they are known).
  • Whether env add --from <base-synced> should also write the missing ksail.<name>.yaml for the source as it clones, so the workspace converges on one representation.

An alternative worth considering instead: have project init --multi-cluster <name> write ksail.<name>.yaml up front, so every environment has the same shape from the start. That is a smaller change but alters the scaffold's output, so it deserves an explicit decision rather than being assumed.

Acceptance criteria

  • After project init --multi-cluster prod, env list reports prod.
  • After project init --multi-cluster prod, env add staging --from prod succeeds and produces a working staging environment.
  • env list and env reconcile report the same environment set for that workspace, pinned by a test that would fail if either resolver changes alone.
  • The "no environments declared" hint is only shown when there is genuinely nothing to clone from, and names an action that works from that state.
  • Regression coverage for both init modes (plain and --multi-cluster).

Rough size

S–M. The resolver change is small and the seam already exists; most of the work is deciding the two questions above and covering both init modes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions