From 747f405c6f9f4d1c61c8b6513325917216d20de2 Mon Sep 17 00:00:00 2001 From: atlas Date: Wed, 5 Aug 2026 14:47:26 +0200 Subject: [PATCH] fix(nix): keep the domain-derived defaults total The required-domain assertion in hive-network.nix could not be reached: `forge.` and `matrix.` are evaluated while the assertion list is, so an unset domain threw `cannot coerce null to a string` naming one of those options instead of printing the message that says which option to set. Both defaults now fall back to a name under the reserved `.invalid` TLD, which the assertion refuses to let out the door. --- docs/swarm.md | 8 ++++---- nix/host-modules/hive-forge/default.nix | 4 +++- nix/host-modules/hive-matrix.nix | 4 +++- nix/host-modules/hive-network.nix | 11 +++++++++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/swarm.md b/docs/swarm.md index be4897ba..b2f4c388 100644 --- a/docs/swarm.md +++ b/docs/swarm.md @@ -38,10 +38,10 @@ rename — a hive that pins `domain` explicitly keeps exactly the value it has today, which is the point: re-rooting where a value *comes from* must not reinterpret the values already deployed. -`hiveName` and -`swarm.name` are purely display — they surface in the dashboard chrome -header and per-agent system prompts. Federated hives at different -domains can share a `swarm.name`; that it sits under `swarm` and +`hiveName` and `swarm.name` are purely display — they surface in the +dashboard chrome header and per-agent system prompts. Federated hives +at different domains can share a `swarm.name`; that it sits under +`swarm` and `hiveName` does not is the whole distinction — one names this hive, the other names the group it belongs to. diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index 518e22cf..c50532ef 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -120,7 +120,9 @@ in domain = lib.mkOption { type = lib.types.str; - default = "forge.${hyperhiveDomain}"; + # Total on a null hive domain so the required-domain assertion in + # hive-network.nix is the thing that fires; see the comment there. + default = if hyperhiveDomain == null then "forge.invalid" else "forge.${hyperhiveDomain}"; defaultText = lib.literalExpression ''"forge.''${services.hyperhive.domain}"''; example = "git.example.com"; description = '' diff --git a/nix/host-modules/hive-matrix.nix b/nix/host-modules/hive-matrix.nix index 419d5376..35c2bbdb 100644 --- a/nix/host-modules/hive-matrix.nix +++ b/nix/host-modules/hive-matrix.nix @@ -190,7 +190,9 @@ in gatewayHost = lib.mkOption { type = lib.types.nullOr lib.types.str; - default = "matrix.${hyperhiveDomain}"; + # Total on a null hive domain so the required-domain assertion in + # hive-network.nix is the thing that fires; see the comment there. + default = if hyperhiveDomain == null then "matrix.invalid" else "matrix.${hyperhiveDomain}"; defaultText = lib.literalExpression ''"matrix.''${services.hyperhive.domain}"''; example = "matrix.example.com"; description = '' diff --git a/nix/host-modules/hive-network.nix b/nix/host-modules/hive-network.nix index 218a88f8..4f460d01 100644 --- a/nix/host-modules/hive-network.nix +++ b/nix/host-modules/hive-network.nix @@ -153,6 +153,17 @@ in # hyperhive is enabled: the shared-netns mode was removed, so there # is one mode (private netns behind the bridge). (lib.mkIf config.services.hyperhive.enable { + # This message is only useful if an operator can actually reach + # it, and an assertion competes with every eager default that + # reads the value it guards: option defaults that interpolate the + # domain (`forge.`, `matrix.`) throw while the + # assertion list is being evaluated, so the operator sees + # `cannot coerce null to a string` naming an unrelated option + # instead of the sentence below. Those defaults therefore stay + # total, falling back to a name under the reserved `.invalid` TLD + # (RFC 2606) — a value this assertion then refuses to let out the + # door, and one that fails loudly at resolution rather than + # quietly working if it somehow did. assertions = [ { assertion = config.services.hyperhive.domain != null;