docs: migrate reminder/gateway/crash-watch/migrate prose to docs (#715)

This commit is contained in:
damocles 2026-06-01 10:47:09 +02:00
commit 12a26e6cb0
7 changed files with 75 additions and 123 deletions

View file

@ -162,6 +162,31 @@ Transient broker errors (sqlite lock contention, etc.) get the same
fan-out pass; a broker error on a one-shot is not retried (the
operator advisory and `last_result` are the only audit trail).
### Reminder delivery: file-path semantics
A reminder may carry a `file_path` (the agent-visible path inside its
container, e.g. `/agents/<name>/state/foo.md`). On delivery hive-c0re:
1. **Translates** the container path to the host path
(`/var/lib/hyperhive/agents/<name>/state/foo.md`) so c0re can write
from outside the container.
2. **Validates** the path: rejects anything outside the agent's own state
subtree, containing `..` (path traversal), or with an empty relative
tail. On rejection the write is skipped and the original message is
delivered inline with a warning — the reminder still fires.
3. **Defends against symlink escape**: after `create_dir_all`, the parent
dir is canonicalized and re-verified to live under the agent's host
state root. The final file is opened with
`O_NOFOLLOW | O_CREAT | O_TRUNC` so an existing symlink at the
basename cannot redirect the write to an arbitrary host path.
4. **Writes the body to disk** and delivers a short pointer message in its
place, keeping the agent's inbox / wake-prompt small while the bulky
payload is read out of band.
Atomicity of the inbox INSERT + `reminders.sent_at` UPDATE is handled
inside `Broker::deliver_reminders_batch`; the scheduler only computes the
body strings before calling it.
### Destroy semantics
`HostRequest::Destroy { name, purge }` is the lifecycle tear-down,

View file

@ -114,6 +114,35 @@ TCP loopback upstream in `agents.conf` (deterministic port from
`agent_web_port(name)`). A future cleanup will drop the TCP fallback
once every agent's flipped.
## Agent port map (`agent-ports.json`)
`/var/lib/hyperhive/agent-ports.json` is a flat JSON object keyed by
logical agent name → TCP web port:
```json
{
"iris": 8178,
"atlas": 8304,
"argus": 8267,
"damocles": 8549
}
```
Written alongside `agents.conf` on every topology change. Ports come from
`lifecycle::agent_web_port(name)` — a pure FNV-1a hash of the name,
reproducible from the name alone. The manager is excluded: the gateway
routes `/` directly to c0re's dashboard upstream, not through a
per-agent `/agent/<name>/` prefix.
The file doubles as a human-readable audit artifact — `cat agent-ports.json`
shows every registered sub-agent and its deterministic port assignment. TCP
loopback upstreams in `agents.conf` reference these ports for agents that
haven't opted into unix-socket mode yet.
Both `agent-ports.json` and `agents.conf` use atomic `<path>.tmp` +
`rename()` writes so a crashing c0re process never leaves a partial or
unparseable file behind.
## Dashboard link shape (gateway vs direct)
When the gateway is in front, the SW4RM tab builds per-agent links