Skip to content

Desired State Model

Core principle: Starbase decides, Shuttle applies.

Everything in a customer cluster flows through desired state — customer workloads, LB scaling, HTTPRoutes, future SecurityPolicies. Shuttle is a dumb applier. It doesn't make decisions; it makes the cluster match what Starbase says.

What desired state includes

Category Examples Who decides Who applies
Customer workloads Deployments, Services, ConfigMaps, Secrets Starbase (from user config + build output) Shuttle
Multi-tenancy isolation Namespaces, RBAC, NetworkPolicy, Quotas Starbase (from customer tier) Shuttle
Traffic routing HTTPRoutes Starbase (from service config) Shuttle
Cluster infrastructure LB size units Starbase (from capacity monitoring) Shuttle (patches annotation)
Auth policies (post-MVP) SecurityPolicies Starbase (from auth-config) Shuttle

Single pattern, no exceptions. If it's a Kubernetes resource in a customer cluster, it goes through desired state. Starbase never directly calls the K8s API in customer clusters — it has no persistent K8s API access. All cluster mutations flow through Shuttle.

Desired state payload is the contract between Starbase and Shuttle. It's a JSON document that Shuttle pulls every 30 seconds (see §25.1). If the payload changes, Shuttle applies the diff on the next tick. If the payload is unchanged, Shuttle does nothing (no-op tick).

Identity in the payload (v1.9)

Each service entry in the desired-state payload (§25.1) carries the canonical tenant key — workspace_id, project_id, environment, and service_id — matching the load-bearing label set (§24.1). workspace_id is the billing-boundary label; project_id + environment + service_id is the identity tuple every metric and log line is attributed to (§35.2). Shuttle stamps these as labels on every resource it creates and encodes project_id + service_id + environment into each HTTPRoute name (§20.2) so Envoy metrics resolve to the same key. There is no customer_id field — it was removed in v1.9; identity flows workspace → project → environment → service throughout.

Where computation lives

Desired state computation — the code that transforms Postgres rows into the JSON payload above — lives in Starbase at internal/service/desiredstate.go (per §9's package layout). Its job is a query-and-serialize: SELECT across projects, environments, services, deployments, var_groups, service_var_groups, and related tables; fold the rows into the payload shape defined in §25.1; return over the HTTP endpoint defined there. The contract (JSON shape, versioning, field semantics) is architecture and lives in this design hub. The computation (SQL, joins, serialization) is implementation-time — it gets designed and reviewed as code against the concrete DB schema, not upfront. Changes to the contract require a design update; changes to the queries do not.


Cross-references

Payload contract & 30s pull → §25.1 · the agent that applies it → Shuttle · level-driven reconciliation → Shuttle › Architecture · tenant key carried in the payload → §24.1 · HTTPRoute name encoding → §20.2 · LB size-unit patching → Networking › Load Balancer. Canonical map: Canonical Sources.