nix: gate the avatar-sync path unit on the same condition as its service
`systemd.paths.forge-avatar-sync` was gated on `agent.icon != null` alone, while the `systemd.services.forge-avatar-sync` it triggers is gated on `agent.icon != null && agent.forge.url != null`. An agent with an icon and no forge URL therefore rendered a `.path` unit, pulled into multi-user.target, watching for a forge-token whose arrival would activate a unit that does not exist. The module already documents the fixed behaviour: `forge.url`'s own option description says the tea-login and avatar-sync units are "not generated at all" when it is null --- an absent integration, never a misdirected one. That sentence was true of the oneshot and false of its watcher. Latent, not live: hive-c0re renders `forge.url` into every agent's config from the host's `HIVE_FORGE_URL`, so on a real hive it is always set and the asymmetric arm is unreachable. It is reachable wherever the agent modules are evaluated outside a hive. A module-eval case pins both halves absent for an agent with an icon and no forge; it fails on the parent commit, where the path unit renders.
This commit is contained in:
parent
fb9a2c0830
commit
ed1fce3329
2 changed files with 39 additions and 7 deletions
|
|
@ -723,6 +723,15 @@ let
|
|||
# get it installed twice.
|
||||
agentPluginsDuplicate = agent { claudePlugins = [ "base@hyperhive" ]; };
|
||||
agentPlugins = machine: machine.services.hyperhive.agent.claudePlugins;
|
||||
|
||||
# An agent with an icon and no forge. Both halves of the avatar sync — the
|
||||
# `.path` watcher and the oneshot it triggers — hang off the icon, but only
|
||||
# the service can do anything with a forge URL, so the icon alone is the one
|
||||
# input that can render half the feature. `pkgs.emptyFile` rather than a real
|
||||
# SVG: the icon is only ever a gate here, and nothing this case reads
|
||||
# rasterizes it.
|
||||
agentIconNoForge = agentWith { services.hyperhive.agent.icon = pkgs.emptyFile; };
|
||||
|
||||
agentHarness = machine: machine.systemd.services.hive-agent;
|
||||
agentSubagentDaemon = machine: machine.systemd.services.hive-subagent-daemon;
|
||||
agentBaoIdentity = machine: machine.systemd.services.hive-agent-bao-identity;
|
||||
|
|
@ -2050,6 +2059,20 @@ let
|
|||
name = "one subagent losing the OOM draw does not stop the daemon";
|
||||
ok = (agentSubagentDaemon agentUncapped).serviceConfig.OOMPolicy == "continue";
|
||||
}
|
||||
{
|
||||
# The absence class, and a gate asymmetry nothing else can see. A `.path`
|
||||
# unit is `wantedBy = multi-user.target` and names a `Unit=` by
|
||||
# convention rather than by reference, so one gated more loosely than the
|
||||
# service it triggers evaluates clean, deploys clean, and then fails to
|
||||
# activate the first time the watched file is written. `forge.url`'s own
|
||||
# option doc already promises the avatar-sync units are "not generated at
|
||||
# all" without a forge — this is the case that makes that sentence true
|
||||
# of the watcher and not only of the oneshot.
|
||||
name = "an agent with an icon and no forge renders neither avatar-sync unit";
|
||||
ok =
|
||||
!(agentIconNoForge.systemd.paths ? forge-avatar-sync)
|
||||
&& !(agentIconNoForge.systemd.services ? forge-avatar-sync);
|
||||
}
|
||||
{
|
||||
# A homeserver URL is the whole input: from it the module derives the
|
||||
# hive-internal `main` account, and from a non-empty account set the three
|
||||
|
|
|
|||
Loading…
Reference in a new issue