openova/products
e3mrah e9a72aa00d
feat(self-sovereign-cutover): auto-trigger on install + always-defined State (#933 E1) (#936)
Closes the otech113 dashboard regression where SovereigntyCard rendered
`invalid CutoverState: <undefined>` instead of a Tethered badge, and
makes the Day-2 cutover fire automatically once the chart lands rather
than waiting for an operator click on "Achieve True Sovereignty".

Founder rule per #933: handover is not "done" until cutover has run;
the operator must NOT have to click a CTA on
console.<sov-fqdn>/console/dashboard.

Three coupled changes:

1. catalyst-api: cutoverStatusResponse now ALWAYS emits a `state` field
   ("tethered" or "sovereign"), derived from cutoverComplete. The UI's
   branded parseCutoverState rejects empty/undefined, which is what
   was rendering the user-visible error text. Tests cover the empty
   ConfigMap, missing cutoverComplete, and explicit-true cases.

2. UI parseCutoverStatus: defensive fallback when wire frame omits
   `state` — derive from cutoverComplete (default "tethered"). Hostile/
   typo'd state values (e.g. 'pending', '') still throw via the branded
   parser. Defends against partial-rollout where a stale catalyst-api
   Pod is still serving the old shape.

3. bp-self-sovereign-cutover 0.1.16 (chart): new Helm post-install/
   post-upgrade hook (templates/10-auto-trigger-job.yaml) POSTs
   /api/v1/sovereign/cutover/start on catalyst-api after the step
   ConfigMaps + RBAC land. Idempotent via catalyst-api's durable
   status ConfigMap (200 if already complete, 409 if running, 200
   to start). Fails open: a transient catalyst-api unreachability
   exits 0 so the chart install doesn't block; operator can always
   re-fire via the manual CTA. Gated on .Values.trigger.auto (default
   true; per-Sovereign overlays can disable for soak Sovereigns).

Hard rules honoured:
- No contabo Pods touched.
- Existing tethered Sovereigns that have not cutover stay tethered —
  the auto-trigger Job is in the chart (per-Sovereign), not in the
  mothership; only fresh Sovereign installs of bp-self-sovereign-cutover
  0.1.16+ get it.
- IaC-first: the auto-trigger uses catalyst-api's existing /start
  endpoint (no bespoke cluster mutation outside the chart).
- Event-driven: post-install hook fires on chart install (no cron).

Verification:
- Go: cutover_test.go +TestBuildCutoverStatusResponse_StateAlwaysDefined
  +TestHandleCutoverStatus_StateFieldEmittedOnFreshSovereign — both
  green.
- TS: cutover.test.ts +5 cases for parseCutoverStatus state-fallback;
  35/35 green. Sovereignty widget tests 20/20 green.
- Chart: tests/cutover-contract.sh +Case 8/9 (auto-trigger present by
  default, absent under trigger.auto=false); helm template renders
  cleanly.

Co-authored-by: Hatice Yildiz <hatiyildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 14:40:52 +04:00
..
axon feat(axon): make qwen3-coder thinking mode toggleable via request parameter 2026-04-26 09:20:33 +02:00
catalyst feat(self-sovereign-cutover): auto-trigger on install + always-defined State (#933 E1) (#936) 2026-05-05 14:40:52 +04:00
cortex docs(pass-52): bundled date-sweep + cross-component namespace clean; knative clean 2026-04-28 00:37:21 +02:00
fabric docs(seaweedfs+guacamole): replace MinIO with SeaweedFS as unified S3 encapsulation; add Guacamole to bp-relay 2026-04-28 10:23:46 +02:00
fingate docs(pass-52): bundled date-sweep + cross-component namespace clean; knative clean 2026-04-28 00:37:21 +02:00
relay docs(seaweedfs+guacamole): replace MinIO with SeaweedFS as unified S3 encapsulation; add Guacamole to bp-relay 2026-04-28 10:23:46 +02:00