infra_manifest: mandate DigitalOcean + reverse-DNS droplet naming

Add two must-rules and a schema pattern:
- cloud_provider: standing cloud hosts run on DO (nyc3 default), uvlava TF.
- droplet_naming: com.uvlava.<producer>.<role>; name is ForceNew → rename
  live via doctl + ignore_changes=[name], never a destructive apply.
- droplets[].name pattern ^com\.uvlava\.(ct|mc|quinn)\.[a-z0-9-]+$

Reflects the live fleet: com.uvlava.{ct.services,ct.redroid,quinn.artifacts,quinn.infra}.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Natalie 2026-06-29 20:42:20 -04:00
parent 11fc015686
commit 5024ee517d

View file

@ -1,5 +1,5 @@
apiVersion: conventions/v1
version: 0.4.0
version: 0.5.0
updated: "2026-06-29"
name: infra_manifest
title: Infra manifest (.infra.yaml — per-project + producer-level shared infra)
@ -18,6 +18,14 @@ rules:
- id: gpu_ondemand
level: should
text: GPU workloads are on-demand — provision, keep warm while the queue is deep, release on idle. Never a standing GPU.
- id: cloud_provider
level: must
text: "Standing cloud hosts run on DigitalOcean (region nyc3 by default — operator-local; fra1/ams3 only if EU PII residency wins the GDPR call), managed by the uvlava terraform at @ct/infra/uvlava/terraform/do/. `provider: digitalocean` in the manifest. Today all droplets share ONE DO account (PATs ~/.vault/do_pat_*); per-producer DO accounts are the target, not yet real."
rationale: One declared cloud provider keeps IaC, billing, and the mesh reconciler coherent; nyc3 co-locates droplets + managed PG + Spaces.
- id: droplet_naming
level: must
text: "DO droplets are named reverse-DNS `com.uvlava.<producer>.<role>` — `<producer>` ∈ {ct, mc, quinn}; `<role>` is the function (services, artifacts, redroid, infra, gpu). Shared operator infra is `quinn.*` (e.g. com.uvlava.quinn.artifacts = forges+registries, com.uvlava.quinn.infra = DNS+WG hub); producer app/data hosts are `<producer>.*` (e.g. com.uvlava.ct.services, com.uvlava.ct.redroid). The DO `name` is ForceNew in the provider: set it once at create, rename LIVE via `doctl compute droplet-action rename`, and keep `lifecycle.ignore_changes = [name]` so a label change never destroys the box."
rationale: Stable, sortable, ownership-legible names that survive rebuilds and never trigger a destructive terraform replace.
- id: host_in_mesh
level: must
text: "`service.host` is a host name from net-tools mesh-hosts.json (lime, fennel, redroid, …) — the infra-net reconciler validates this and regenerates the mesh-hosts services map from all .infra.yaml."
@ -75,7 +83,7 @@ providesFile:
additionalProperties: false
required: [name, services]
properties:
name: { type: string }
name: { type: string, pattern: "^com\\.uvlava\\.(ct|mc|quinn)\\.[a-z0-9-]+$", description: "Reverse-DNS droplet name com.uvlava.<producer>.<role> (see rule droplet_naming). Rename live via doctl; name is ForceNew in terraform." }
role: { type: string }
provider: { type: string, enum: [digitalocean, mac, bare-metal, local] }
hosts: { type: array, items: { type: string }, description: "mesh-hosts.json names this droplet registers on provision." }