# pom's tiers and nodes. Design: wiki [[sando-bento-boundary]]. # # No [repo] and no [[backup]]-driven migration gate. pom is intake-only: Bento # builds it natively on astra and on the Hetzner box, and hands Sando finished # bytes with an artifact record. Sando fetches no source for it, so there is no # bare repo on this host to name, and declaring one would be a claim /rebuild # would then act on. backup = [] # ---- host: where an accepted artifact is gated before it goes anywhere ---- # # Not a machine pom runs on. It is the tier every intake lands on, the same way # a Sando-built product's host tier is where its build lands: gates run here, and # a green run is what makes the bundle promotable. sandod's own box (fw13) is not # a pom node and never runs pom. # # The gate list is empty on purpose, and that is the boundary rather than an # omission. Everything Sando would have run here is artifact-scoped — cargo_test, # clippy, fmt, the audits — and artifact-scoped evidence belongs to the builder # under this split. Bento already ran them, and the record carries their verdicts # (`intake::accept` reports whether the builder's gates passed). Asking Sando to # re-run them would need a source checkout it does not have, and the gates say so # rather than passing on having run nothing. # # What is left for Sando is evidence about the artifact *in an environment*, and # every one of those lives on a tier with a node in it, below. [[tier]] name = "host" provisioned = true canary = "sequential" gates = [] # ---- astra: aarch64, and pom's own CI runner ---- # # First real tier because it is the machine that matters least if pom is down for # a moment: it watches, it does not serve anyone. The Hetzner instance keeps # watching while this one restarts. # # The bootstrap caveat is why the two are a ladder and not a fan-out: pom watches # its own deploy, so deploying pom restarts the watcher mid-operation. One # instance at a time, health read from the peer over the mesh, never both at once. [[tier]] name = "astra" provisioned = true canary = "sequential" # Guards astra -> hetzner. node_health proves the restarted instance is actually # serving; burn_in makes production wait on a real interval of the new binary # running somewhere; manual_confirm is the human sign-off before the box that # watches production takes it. gates = [ { kind = "node_health" }, { kind = "burn_in", hours = 24 }, { kind = "manual_confirm" }, ] [[tier.node]] name = "astra" platform = "linux/aarch64" ssh_target = "max@astra" # tailnet name release_root = "/opt/pom" service_name = "pom.service" # Readiness on top of `systemctl is-active`: pom binds its API on the tailnet # address, and the dashboard is on. A crash-looping binary satisfies is-active # between restarts, which is the failure this closes. health_url = "http://127.0.0.1:9100/api/health" # ---- hetzner: x86_64, watching production from production ---- [[tier]] name = "hetzner" provisioned = true canary = "sequential" gates = [ { kind = "node_health" }, { kind = "manual_confirm" }, ] [[tier.node]] name = "hetzner" platform = "linux/x86_64" ssh_target = "root@alpha-west-1" # Tailscale SSH; port 2200 via the ssh config release_root = "/opt/pom" service_name = "pom.service" health_url = "http://127.0.0.1:9100/api/health"