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;