docs(web-ui): refresh matrix-accounts page for heartbeat + age-dimming + problem+json

The M4TR1X ACC0UNTS section described the pre-heartbeat state: a
snapshot 'written at startup / rewritten each daemon (re)start' with an
'ambiguous' as_of, and the live-status dot as a 'dashboard-side
follow-up'. All three shipped since:

- the daemon now force-rewrites the snapshot every ~30s (heartbeat), so
  as_of advances while alive and a stalled value is an honest dead-daemon
  signal — documented, with the full dot state table (green / dim-green
  'no heartbeat' age case / amber container-down + offline / grey);
- the login endpoint moved to /api/matrix-account-login and its failure
  body is RFC 9457 application/problem+json (message in detail), not the
  old 4xx { error } — corrected, with the 400/500 status scheme.
This commit is contained in:
iris 2026-06-22 15:56:50 +02:00 committed by mara
commit 4342a50895

View file

@ -231,20 +231,37 @@ read from `GET /api/matrix-accounts?agent=<name>` →
`{ accounts: [ { name, homeserver, token_present, live, user_id } ], as_of_unix }`.
`token_present` is whether a token is **stored**; `live`, `homeserver`,
and `user_id` are backfilled from the matrix daemon's
`matrix-accounts.json` snapshot — a host-visible file the daemon writes at
startup after its sessions restore (an account with a token but absent
from the snapshot reports `live: false`). `as_of_unix` is the snapshot's
mtime (null when absent), so the dot can show "live as of N ago". The
snapshot is rewritten each daemon (re)start, so an old `as_of_unix` is
ambiguous (stable uptime vs dead daemon) — the live-status dot rendering
(3-state + snapshot-age tooltip, cross-referencing container-running
state) is the dashboard-side follow-up.
`matrix-accounts.json` snapshot — a host-visible file the daemon
**force-rewrites every ~30s** (a heartbeat), so `as_of_unix` (the
snapshot mtime) advances while the daemon is alive and a *stalled* value
genuinely means "stopped publishing", not just "old snapshot". An account
with a token but absent from the snapshot reports `live: false`.
The status dot renders these states:
- **green**`live` and the container is running: online.
- **dim green**`live` but `as_of_unix` hasn't advanced in > ~90s (3
missed heartbeats) while the container is *not* down: the daemon stopped
publishing, so the snapshot's `live` is no longer trustworthy (likely
dead/wedged). Labelled "online · no heartbeat".
- **amber**`live` but the container is **down** (a stopped container
⟹ a dead daemon, so the snapshot is stale); also the `token_present &&
!live` "provisioned but offline" case.
- **grey** — no token (not provisioned).
The container-down cross-reference (`/api/state`) takes precedence over
the age check. `as_of_unix` is tooltipped ("live as of N ago") throughout
so freshness is always legible. When `live` is absent (an older backend
without the snapshot) the dot falls back to a token-present rendering.
The provision form (account name, homeserver, login method) posts
`POST /matrix-account-login` (`x-www-form-urlencoded`, operator-auth):
`POST /api/matrix-account-login` (`x-www-form-urlencoded`, operator-auth):
fields `agent, account, homeserver, mode=password|token, user_id?,
password?, token?` → `2xx { ok, user_id }` on success or
`4xx { error }` on failure. The host coordinator performs the login
password?, token?` → `200 { ok, user_id }` on success. Failures come back
as RFC 9457 `application/problem+json` (`{ type, title, status, detail }`)
with the human-readable message in `detail` and the status code reflecting
the cause (400 for a validation error, 500 for a login / `whoami` /
internal failure); the page reads `detail` for display. The host coordinator performs the login
(password) or validates the token (`whoami`) and writes the bearer to
the agent's `matrixAccounts.<account>.tokenFile` via the same
privileged write path as the hive-internal `matrix-token`; the token is