matrix: make the hive-internal main account an ordinary matrixAccounts entry

`matrixAccounts` is meant to be the agent's full account list, but the
hive-internal `main` account was outside it: the nix module emitted only
the extras and `hive-matrix-daemon` prepended a `main` it synthesized
from the per-agent paths, with the option schema forbidding the name
outright.

nix/agent-modules/matrix.nix now declares `main` itself, as an ordinary
entry under `matrix.enable`, from the state-dir paths the module already
used for its token path-watcher (now a shared `stateDir` binding) plus
`matrix.url`. The whole set, `main` included, is serialized to
HIVE_MATRIX_ACCOUNTS.

accounts::configured therefore synthesizes `main` only when the parsed
list carries none, and otherwise takes the declared one verbatim —
hoisting it to index 0, since the daemon reads index 0 as the primary
and nix serializes an attrset, so `main` sorts wherever its key falls.
Declared xor synthesized: an agent whose harness predates this entry
keeps working, a current one gets its own, and there is no arrangement
where `main` is duplicated or missing.

The reserved-name assertion is replaced rather than dropped: the name
must now be legal (the module uses it), but `main`'s tokenFile stays
pinned to `<state>/matrix-token`, since hive-c0re provisions the
hive-internal token there and nowhere else — a retarget would evaluate
fine and then never restore. The other two fields are mkDefault and free
to override.

Refs #4475
This commit is contained in:
atlas 2026-09-18 03:35:00 +02:00 committed by mara
commit c74249f371
4 changed files with 220 additions and 80 deletions

View file

@ -163,8 +163,8 @@ pub async fn put_matrix_account(
let secret_path = matrix::account_path(&agent, &account)
.map_err(|e| error_problem(StatusCode::BAD_REQUEST, &e.to_string()))?;
// `main` is the hive-internal account `nix/agent-modules/matrix.nix`
// synthesizes per agent from `services.hyperhive.agent.matrix.url` — the schema there
// forbids declaring a key by that name for the same reason this route
// declares per agent from `services.hyperhive.agent.matrix.url` — the
// module owns that `matrixAccounts` entry, which is why this route
// refuses to write one: an extra account literally named `main` would
// not overwrite the real one (it lands at a different token-file suffix)
// but would confuse anything that lists accounts by name. Same guard
@ -173,7 +173,7 @@ pub async fn put_matrix_account(
if is_reserved_account(&account) {
return Err(error_problem(
StatusCode::BAD_REQUEST,
"'main' is the hive-internal account, synthesized per agent from \
"'main' is the hive-internal account, declared per agent from \
services.hyperhive.agent.matrix.url it cannot be set through this route.",
));
}
@ -236,7 +236,7 @@ pub async fn put_matrix_account(
Ok(Json(PutMatrixAccountResponse { user_id }))
}
/// Whether `account` is the hive-internal name every hive synthesizes per
/// Whether `account` is the hive-internal name every hive declares per
/// agent (`nix/agent-modules/matrix.nix`) — see the call site's own comment
/// for why this route must never write one.
fn is_reserved_account(account: &str) -> bool {