matrix: drop the per-agent matrix.enable; accounts are the enable signal
`services.hyperhive.agent.matrix.enable` was a second source of truth for a fact the account set already carried: after ①-③ the hive-internal `main` account is an ordinary `matrixAccounts` entry, so "does this agent have matrix" and "does this agent have an account" were the same question asked twice, with the boolean able to disagree. The option is gone and a non-empty `matrixAccounts` now gates the daemon unit, its token path-watcher and the injected `extraMcpServers.matrix` entry. That is only a real condition because `matrixAccounts.main` is itself gated: it is declared when `matrix.url != null`, never unconditionally. A `main` with no homeserver is an account the daemon can never log in as, so declaring one always would have made the signal trivially true and turned matrix on for every agent in every hive. With the URL gate, the empty set is reachable exactly for an agent the hive gave no homeserver and whose operator declared no account of its own — the state the old `enable = false` expressed. Assertions: "extras require enable" is deleted, having become the definition of the thing it checked (an external-only account with its own homeserver is now rendered rather than rejected). `main.tokenFile` stays pinned, re-guarded on `? main` instead of on the flag, since `main` is absent whenever the URL is null and an unguarded index would throw there. Both spellings of the option get `mkRemovedOptionModule`, following ../host-modules/deploy.nix's registrationTokenFile pair rather than a silent delete: the definition whose meaning changes is `false`, and left undeclared it would be ignored and hand the agent the tools its operator turned off. Failing the eval with the replacement spelling is the only outcome that cannot. module-eval gains the three arms — URL, nothing, external-only — with the middle one carrying why it exists: it is the only thing in the suite that would notice `main` becoming unconditional again. Refs #4475
This commit is contained in:
parent
e95e988965
commit
99b141f5f2
7 changed files with 254 additions and 92 deletions
|
|
@ -611,6 +611,29 @@ let
|
|||
# RAM percentage and so hands the module no byte count to size against.
|
||||
agentCapped = agent { claudeMemoryMaxBytes = 8589934592; };
|
||||
agentUncapped = agent { };
|
||||
|
||||
# Matrix's enable signal, which is the account set itself — there is no
|
||||
# `matrix.enable` option left to read. Three arms, because the property has
|
||||
# three distinct shapes and only one of them is the common case:
|
||||
#
|
||||
# - a homeserver URL, which is what the module turns into a `main` account;
|
||||
# - neither URL nor operator account, the state that replaced
|
||||
# `matrix.enable = false`. ⚠️ **This is the arm that matters.** `main` is
|
||||
# declared by the module itself, so "any account declared" would be
|
||||
# trivially true — and matrix would render for every agent in every hive —
|
||||
# the moment that declaration stops being gated on the URL. Nothing else in
|
||||
# this suite would notice;
|
||||
# - an operator account carrying its own homeserver and no hive one, which is
|
||||
# matrix on with no `main` at all.
|
||||
agentMatrix = agent { matrix.url = "https://chat.t.local"; };
|
||||
agentNoMatrix = agent { };
|
||||
agentMatrixExternalOnly = agent {
|
||||
matrixAccounts.ccc = {
|
||||
tokenFile = "/agents/a1/state/matrix-token-ccc";
|
||||
sessionDir = "/agents/a1/state/matrix-sdk-state-ccc";
|
||||
homeserver = "https://matrix.example.invalid";
|
||||
};
|
||||
};
|
||||
agentHarness = machine: machine.systemd.services.hive-agent;
|
||||
agentSubagentDaemon = machine: machine.systemd.services.hive-subagent-daemon;
|
||||
agentSettings = machine: machine.services.opentelemetry-collector.settings;
|
||||
|
|
@ -1793,6 +1816,62 @@ let
|
|||
name = "one subagent losing the OOM draw does not stop the daemon";
|
||||
ok = (agentSubagentDaemon agentUncapped).serviceConfig.OOMPolicy == "continue";
|
||||
}
|
||||
{
|
||||
# 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
|
||||
# things that used to hang off `matrix.enable`.
|
||||
name = "an agent with a homeserver gets a main account and the matrix units";
|
||||
ok =
|
||||
let
|
||||
a = agentMatrix.services.hyperhive.agent.matrixAccounts;
|
||||
in
|
||||
lib.attrNames a == [ "main" ]
|
||||
&& a.main.tokenFile == "/agents/a1/state/matrix-token"
|
||||
&& a.main.homeserver == "https://chat.t.local"
|
||||
&& agentMatrix.systemd.services ? hive-matrix-daemon
|
||||
&& agentMatrix.systemd.paths ? hive-matrix-daemon
|
||||
&& agentMatrix.services.hyperhive.agent.extraMcpServers ? matrix;
|
||||
}
|
||||
{
|
||||
# The absence arm, and the reason the enable signal is not vacuous. An
|
||||
# agent the hive gave no homeserver, whose operator declared nothing, must
|
||||
# come out with an EMPTY account set — not a `main` that can never log in
|
||||
# — and therefore with none of the three. Assert the emptiness itself and
|
||||
# not just the units: it is the account set that is load-bearing now, and
|
||||
# a `main` sneaking back in is the regression this case exists to name.
|
||||
name = "an agent with no homeserver and no declared account gets no matrix at all";
|
||||
ok =
|
||||
agentNoMatrix.services.hyperhive.agent.matrixAccounts == { }
|
||||
&& !(agentNoMatrix.systemd.services ? hive-matrix-daemon)
|
||||
&& !(agentNoMatrix.systemd.paths ? hive-matrix-daemon)
|
||||
&& !(agentNoMatrix.services.hyperhive.agent.extraMcpServers ? matrix);
|
||||
}
|
||||
{
|
||||
# Matrix without a hive homeserver: one operator account, its own
|
||||
# homeserver, no `main`. Under the deleted `matrix.enable` this config was
|
||||
# an assertion failure ("extras require enable") even though every account
|
||||
# in it was complete; the account set being the signal is what makes it
|
||||
# expressible, and the serialized env var is where that has to show up.
|
||||
name = "an external-only account enables matrix with no main entry";
|
||||
ok =
|
||||
let
|
||||
accts = agentMatrixExternalOnly.services.hyperhive.agent.matrixAccounts;
|
||||
env = agentMatrixExternalOnly.systemd.services.hive-matrix-daemon.environment;
|
||||
in
|
||||
lib.attrNames accts == [ "ccc" ]
|
||||
&& !(accts ? main)
|
||||
&&
|
||||
builtins.fromJSON env.HIVE_MATRIX_ACCOUNTS == [
|
||||
{
|
||||
name = "ccc";
|
||||
token_file = "/agents/a1/state/matrix-token-ccc";
|
||||
state_dir = "/agents/a1/state/matrix-sdk-state-ccc";
|
||||
homeserver = "https://matrix.example.invalid";
|
||||
}
|
||||
]
|
||||
# No hive homeserver, so nothing may claim one.
|
||||
&& !(env ? HIVE_MATRIX_URL);
|
||||
}
|
||||
{
|
||||
# The doctrine three glue files state, as a property a rewrite has to
|
||||
# keep: a client is defined by holding a certificate the store accepts,
|
||||
|
|
|
|||
Loading…
Reference in a new issue