# How Bento releases wam. Lives here rather than in the daemon's config so it is # versioned with the code it describes. # # A service, not an app or a library: wam is run rather than distributed. There # is no bundle for a user to download and no crate to publish. # # wam deploys ITSELF, and that is the deliberate difference from pom. pom hands # its artifact to Sando, which gates it and promotes it tier by tier; wam keeps # the `[[deploy]]` tables and lets Bento install and restart directly. The two # are not disagreeing about what good practice is. They are answering a question # about blast radius, and getting different answers: # # What does a bad deploy cost? For the MNW server it costs paying creators # their platform, so it earns burn-in, tiers, migration dry-runs and a # rollback horizon. For pom it costs the monitoring, which is how anyone finds # out the server broke, so it earns the gates too. For wam it costs an # internal ticket list nobody's money or morning depends on -- and the # recovery is `install-service.sh`'s own `.prev` plus a restart. # # Charging wam the full Sando ceremony would buy a rollback horizon for tickets # we could re-sync from the peer, and would cost an afternoon of topology per # release path. The ladder is a real cost and it should be spent where a bad # deploy is expensive. See wiki `deploy-ceremony-tiers`. kind = "service" # Two arches, two machines, built natively on each: x86_64 on fw13 for the # Hetzner box, aarch64 on astra for astra. Same reason pom needs both -- the # mesh has a node on each -- and the same reason neither can be built by Sando, # whose build::run compiles only on its single configured build host. targets = ["linux/x86_64", "linux/aarch64"] version_path = "Cargo.toml" # MNW is one .git over the server, sando, multithreaded, pom, wam and more, each # versioned separately, so the default `v{version}` names no product in # particular here. tag_format = "wam-v{version}" # Both nodes or neither. The mesh syncs tickets between them and the sync # protocol is the thing most likely to break across a version boundary, so a # release that lands on one node and fails on the other leaves the mesh talking # to itself across a version gap. That is exactly the split-mesh failure pom's # 0.4.1 release hit. require_all_targets = true # The service hosts. A deploy destination is deliberately NOT a `[[host]]` in # the daemon config: a build host is granted build/package, a service host # deploy/restart, and neither is granted the other's. # # install_path is /usr/local/bin/wam on both, which is a move: the running # binary is at /opt/wam/wam on Hetzner today, placed there by hand in April. # install-service.sh refuses any dst outside /usr/local/bin, and that guard is # the only thing bounding a NOPASSWD sudo grant, so the binary moves rather than # the guard widening. Both units' ExecStart move with it. # Hetzner, reached over Tailscale SSH on 22 as root. NOT port 2200: that is what # the retired deploy.sh used, and it refuses this machine's key. # # By tailnet name, not by the 100.120.174.96 that stood here until 2026-08-23. # A written-down address goes stale silently: the deploy would install onto # whatever answers it, or onto nothing, with no error naming the real cause. # The astra row below has always done it this way, in the same file for the # same field. [[deploy]] target = "linux/x86_64" host = "root@alpha-west-1" install_path = "/usr/local/bin/wam" service = "wam.service" health_url = "http://127.0.0.1:7890/tickets" # astra, over the tailnet as max. [[deploy]] target = "linux/aarch64" host = "astra" install_path = "/usr/local/bin/wam" service = "wam.service" health_url = "http://127.0.0.1:7890/tickets"