diff --git a/nix/host-modules/swarm-nats.nix b/nix/host-modules/swarm-nats.nix index 519b1bbb..bdadea39 100644 --- a/nix/host-modules/swarm-nats.nix +++ b/nix/host-modules/swarm-nats.nix @@ -276,6 +276,18 @@ in services.nats = { enable = true; + # Retention, so a reader can ask "what did this hive last + # say?" without anyone keeping a second copy. The upstream + # option also wires `settings.jetstream.store_dir = dataDir`; + # the container is `ephemeral = false`, so that survives a + # restart with no bind mount. + # + # ⚠️ Losing the store is not a correctness problem here: a + # reader then sees nothing for every hive, which is the true + # answer until each one publishes again. It degrades to + # honesty rather than to a stale "healthy". + jetstream = true; + serverName = "swarm-nats"; port = cfg.port; settings = { @@ -307,7 +319,25 @@ in # with a hole. So the only way to get a live server here is # a real key whose seed nobody but the responder holds. ${calloutAccount}.users = [ { nkey = cfg.calloutUserPublicKey; } ]; - ${clientAccount} = { }; + # ⚠️ `services.nats.jetstream = true` gives the SERVER + # JetStream; an account gets it only from its own grant. + # Measured against a running 2.14.1 with this exact + # two-account shape, because the failure is invisible to + # any config-rendering check: + # + # global jetstream only → `nats kv add` from this + # account fails `code=503 err_code=10039 jetstream + # not enabled for account`, while the server starts + # cleanly and logs "Starting JetStream" + # + this line → the same command succeeds + # + # The grant is per-account by design, and that is worth + # keeping: the callout account above deliberately does + # NOT get it. The responder mints credentials; it has no + # business holding stream state. + ${clientAccount} = { + jetstream = "enabled"; + }; }; authorization = {