refactor(nix): swarm.peers becomes swarm.hives, a directory of every hive

One attrset describing every hive in the swarm including this one,
identical on every host, with hiveName selecting which entry is us.
"My peers" is derived (swarm.peerHives) rather than declared.

Every field in the old per-host peer list was intrinsic to the hive it
described, never to the pair -- so the list was a directory each host
kept its own copy of. Beyond the deduplication it removes a bug class:
two hosts could hold different endpoints for the same third hive with
nothing to detect the disagreement.

Drops the per-hive caCert. Trust inside a swarm derives from the swarm
root, which every hive chains to. What that genuinely removes is
trusting a hive whose root this swarm does not own -- a cross-swarm
problem that wants a mechanism of its own, not a field that happened to
work.

The matrix container's certificateFiles block goes with it and could
NOT be migrated: that list is read at build time and the swarm root is
a runtime file (its key must never enter the store), so there is no
build-time name to put there. caCert being a nix path was precisely
what made it the build-time distribution channel. Agents are unaffected
-- hive-tls folds the root into the hive trust bundle and the meta
renderer embeds that one file. Tracked separately.

Migration is an assertion plus warnings, not a rename: hives is peers
union {self}, and the set gains a member no existing config has written
down. A rename migrates a name and a default can re-root a meaning;
neither can conjure a new member. The warning explains, the self-entry
assertion stops the build.
This commit is contained in:
atlas 2026-08-05 20:18:22 +02:00
commit 433b294099
19 changed files with 484 additions and 293 deletions

View file

@ -607,10 +607,10 @@ prices. Models not covered fall back to hive-c0re's built-in estimate.
## P33RS tab
Peer hives in this swarm. The tab is hidden when the
`state.peer_hives` array from `/api/state` is empty (i.e. no
`services.hyperhive.swarm.peers` are configured). When at least
one peer is present the `hidden` attribute is removed and the tab
becomes active.
`state.peer_hives` array from `/api/state` is empty — i.e. when
`services.hyperhive.swarm.hives` holds no hive other than this one.
When at least one peer is present the `hidden` attribute is removed
and the tab becomes active.
**P33R H1V3S** — each peer renders as a card row: a hexagon icon
(`⬡`), the peer's DNS domain as the primary name, and the peer
@ -619,15 +619,16 @@ URL opens the peer hive's dashboard in a new tab.
### Backend wiring
The host daemon reads `services.hyperhive.swarm.peers` from the
nix config (an attrset keyed by peer domain), serialises each
entry as `{ name, url }` into `state.peer_hives: Vec<PeerHiveView>`,
The host daemon reads `services.hyperhive.swarm.peerHives` from the
nix config (the `swarm.hives` directory minus this hive), serialises
each entry as `{ name, url }` into `state.peer_hives: Vec<PeerHiveView>`,
and includes the field in the `/api/state` snapshot. `tabs.js`
reads `state.peer_hives` on every `refreshState` call and calls
`swarm.js::renderPeerHives(peers)`, which rebuilds the `#peers-section`
div from scratch.
The `name` field is the peer's DNS domain (the attrset key); `url`
The `name` field is the peer's DNS domain (its entry's `domain`, not
the attrset key — the key is the hive's name); `url`
is `https://{domain}/`. Both are derived from the env var
`HYPERHIVE_PEERS` (a JSON array of `{ domain, cert_fingerprint }`
objects) that the nix module writes into the c0re container