refactor(#2693): null, not "", for the unpinned claude-code

mara on PR #2769: "make the default null instead of special casing """.

`claude_code_path` was a `String` whose empty value meant "no host-level
pin". That is a sentinel doing an `Option`'s job — the same shape argus
and mara already rejected on #2755's weights, and the same
empty-field cruft mara called out on #2756.

So it is `Option<String>` end to end:

- host module: `claudeCodePath` evaluates to `null` when
  `claudeCodePackage` is unset, so `serve.json` carries JSON `null`
  rather than `""`.
- `Coordinator` + `HiveEnv`: `Option<String>`, defaulting to `None`.
- `render_flake`/`render_flake_with_lookup`: `Option<&str>`, and the
  emission is an `if let Some(path)` instead of an `is_empty()` guard.
- agent module: `hyperhive.claudeCodePath` is `nullOr str`, default
  `null`.

Behaviour is unchanged in both directions; only the way "unset" is
spelled moves. The `builtins.hasContext` assertion still guards the
pinned case (short-circuited by the null check, so an unpinned hive
never evaluates it).

16/16 `meta::` tests, clippy clean, `nix fmt` no-op, `nix build .#docs`
green.
This commit is contained in:
atlas 2026-07-27 13:21:11 +02:00 committed by mara
commit 2ad4b43118
4 changed files with 32 additions and 35 deletions

View file

@ -62,11 +62,11 @@
};
options.hyperhive.claudeCodePath = lib.mkOption {
type = lib.types.str;
default = "";
type = lib.types.nullOr lib.types.str;
default = null;
example = "/nix/store/-claude-code-2.1.220";
description = ''
Store path of the `claude-code` this agent runs, or `""` (the
Store path of the `claude-code` this agent runs, or `null` (the
default) to use the `claude-code` from the container's own
nixpkgs.
@ -212,7 +212,7 @@
]
++ [
(
if config.hyperhive.claudeCodePath == "" then
if config.hyperhive.claudeCodePath == null then
pkgs.claude-code
else
# Host-pinned claude: a symlink farm around a path the