summary:"Every deployable project declares its infrastructure in a root .infra.yaml (single `service`); `service.host` must be a host in net-tools mesh-hosts.json. A PRODUCER root may also carry a .infra.yaml describing shared-infra TOPOLOGY via `droplets` — physical hosts each running many co-located services (e.g. @quinn/.infra.yaml — one services droplet for all forges + registries + DNS + edge, plus an MCP droplet). The infra-net reconciler reads every .infra*.yaml; a future infra-apply renders the DO parts."
text:A project needing a database declares its own logical DB + dedicated user on the shared managed cluster (data-sourced), never reusing another service's creds.
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.
text:"DO droplets are named reverse-DNS. TWO tiers: (1) GLOBAL shared services with NO producer segment — `com.uvlava.<role>` (e.g. com.uvlava.dns = DNS authority/resolver, com.uvlava.wg = WG mesh hub); (2) PRODUCER hosts — `com.uvlava.<producer>.<role>`, `<producer>` ∈ {ct, mc, quinn}, `<role>` is the function (services, artifacts, redroid, gpu). Operator-shared producer infra is `quinn.*` (com.uvlava.quinn.artifacts = forges+registries); per-producer app/data hosts are `<producer>.*` (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."
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."
text:"Shared metal owned by the operator is declared once at the producer root (@quinn/.infra.yaml) via `droplets` — each droplet lists the co-located services it runs (forges, npm/pypi/swift registries, DNS, reverse-proxy, MCP). Logical per-producer forges (ct/mc/quinn) co-locate on one services droplet rather than one droplet each; tag each service with its `producer`. On provision, register each droplet's `hosts` in mesh-hosts.json."
rationale:One services droplet (forges + registries + DNS + edge) + one MCP droplet is cheaper and simpler than a droplet per producer, while keeping forges logically per-producer.
text:"Default manifest is `.infra.yaml` (prod, environment defaults to prod). A distinct non-prod deployment lives in a sibling `.infra.<env>.yaml` (currently only `.infra.dev.yaml`) with the same schema + `environment` set. One project may thus appear as multiple services (e.g. prod on a DO droplet + a local mac instance). Keep run-only/access config (passcodes, bind addresses) out of the manifest — it is not mesh infra."
provider:{type: string, enum: [digitalocean, mac, bare-metal, local], description:"Where it physically runs: digitalocean droplet, a mac (e.g. fennel), bare-metal, or local."}
systemd_unit:{type: string, description:"systemd unit name. manage-apps drives it via `ssh <host> systemctl …` (start/stop/status); the host resolves as an ssh alias from host-apply's ~/.ssh/config."}
deploy:{type: string, description:"Repo-relative deploy script (ships + builds + installs/enables the unit). manage-apps `deploy` runs it locally; the script handles ssh/rsync."}
description:"Producer-level shared-infra topology: physical droplets each hosting MANY co-located services. Used by a producer-root manifest (e.g. @quinn/.infra.yaml) that owns shared metal — distinct from a single project's `service`. Logical per-producer endpoints (ct-forge/mc-forge/quinn-forge) may co-locate on one droplet."
name:{type: string, pattern:"^com\\.uvlava\\.((ct|mc|quinn)\\.)?[a-z0-9-]+$", description:"Reverse-DNS droplet name: global com.uvlava.<role> (e.g. com.uvlava.dns) OR producer com.uvlava.<producer>.<role> (see rule droplet_naming). Rename live via doctl; name is ForceNew in terraform."}