namespace/release/pod were duplicated as independent literals across
OpenbaoScore (hardcoded) and OpenbaoSetupScore (defaults) — pod was a
derived fact (`{release}-0`) stored as a literal that rots if release
changes, and namespace agreement was by coincidence. Introduce
OpenbaoInstance { namespace, release } with a derived pod(); both scores
take it. Only the shared identity moves; per-score knobs (host, tls,
kv_mount, policies, …) stay on their owner.
Full in-cluster CD is blocked on headless OpenBao auth (Zitadel machine
identity), so the clickable deploy-staging workflow + its runner would be
dead config. Drop it; document the manual operator deploy (same secure
OpenBao-config path) until the auth flow lands.
The binary carried a dev nats+operator+agent stack with user/pass flags
that no automated caller used (the e2e harness composes those Scores
from the lib directly). Cut it: main.rs is now load FleetDeploySecrets →
run one FleetOperatorScore. 265→118 lines. Matches ADR-023 (one Score
per component, compose upward).
The deploy workflow took a hand-typed chart version (a second source of
truth, typo-prone). Take a --from-tag instead and parse the version in
Rust via the existing version_from_tag — the tag is the single source of
truth and YAML never parses it. --operator-chart-version stays for the
laptop path.
Adds the deploy half of fleet-operator CD: a manual workflow_dispatch
that installs a published operator chart version via harmony apply,
run from an in-cluster, permissionless runner.
- FleetDeploySecrets (#[config(secret)]) loaded via ConfigClient: the
published-chart path is Zitadel-SSO-only by construction — operator
credentials + deployer kubeconfig come from OpenBao, no user/pass
field reachable. user/pass stays a dev-only rendered-chart flag.
- FleetOperatorScore::credentials() so the published-chart path applies
the operator Secret (was a no-op).
- Deprecate SecretManager in favour of harmony_config::ConfigClient.