Files
dashboards/.agents/phases/todo/29_gateway_dashboard_page/02_wiring.md
T
ducoterra 558a83d0be chore(agent): phase roadmap from TODO.md, 2 phases
Convert the gateway-visualisation TODO item into phases 28 (gateway_agent_proxy: agent sections for haproxy/nginx configs + live sockets, 1.2.0, capture, rollout) and 29 (gateway_dashboard_page: source, wiring, API, animated-pipe page, nav, docs). Clear TODO.md.

LLM-Generated: true
2026-10-21 16:24:01 -04:00

4.5 KiB
Raw Blame History

Task 02 — The gateway job: poller, health, alerts, summary, config

Phase: 29_gateway_dashboard_page · Source: TODO.md:3 — the source is a job of its own (the disks:<host> precedent): its own interval, timeout, health record, and events, so a wedged config read ages the pipes instead of blinking /system Story: n/a

Objective

The gateway source runs as its own poller job (the disks: shape — one job dials the same /snapshot the host: job of the gateway host reads, with the gateway's own interval/timeout), so the page ages on its own cadence and a failed poll keeps the last good pipes dimmed instead of zeroing them (invariant 4). The alerts rules keep an unconfigured source silent (invariant 3) and a dead source to exactly one line (the disks echo rule — the gateway job dials the same agent, so its failure carries no new information while the host: job is the voice; a gateway job failing while its host answers — the sections wedged — is the only voice that fault has). /api/summary gains the additive gateway block, /api/config gains the gateway row.

  • ASSUMPTION: the job is gateway (one job, the nut shape — a single source, not per-host: the page is about the one gateway host), DISKS-interval defaults from task 01 (30 s / 10 s), events under the dashboard name gateway.
  • ASSUMPTION: the no-verdict alert rule: the source's payload carries no severity, so alerts.py gains no threshold for gateway — the only alerts a gateway job raises are reachability (stale > 3× its 30 s interval → warn, stopped answering → fail, the disks-echo suppression applied: a dead gateway job while its host: job is also dead adds no line).

Work

  1. src/dashboards/app.py — build_hub: the gateway job (one, not per host) wired the disks: job is wired — the same AgentTls entry the gateway host's host:/disks: jobs use (so a revocation fails all three with one sentence, the task-03 agent_tls_map shape), its parse the sources.gateway.parse + samples pass-through, no RateEstimator (the source takes none — task 01). The job exists only when settings.gateway_enabled (the disks job's configured gate: no job at all when the source is unconfigured, invariant 3).
  2. src/dashboards/alerts.py — the gateway block: the reachability rules per the assumption above; the HREF table gains /gateway; no verdict rule (asserted: a gateway payload with a fabricated severity dict still produces no verdict alert — the module may not have a threshold of its own, the phase-09 disk rule's shape).
  3. src/dashboards/api.py — /api/summary: the additive gateway block ({configured, supported, host, inbound: int (Σ connections), outbound: int, map_targets: int, unmatched: int, states: {gateway: str}} — a configured job with no payload yet is a stub, the system.hosts stub shape); /api/config: the gateway row (GATEWAY_HOST's name + the Target.display_url of the entry it names, redacted — invariant 6's boundary).
  4. tests/test_api.py — the build_hub wiring pins (the job present iff gateway_enabled; the shared AgentTls entry — a revocation written into meta fails the gateway job before any dial, the test_a_revoked_agent_fails_both_of_its_sources_without_a_dial shape extended to three sources); the /api/summary gateway block pin (with and without the source configured — unconfigured: the block is configured: false and absent no dial happens, the spy-pinned shape); the alerts pins (unconfigured → no gateway alert; dead job + dead host → one line, not two; a wedged-sections failure while the host answers → one line naming gateway).

Testing & Quality

  • Unit: the wiring/alerts/summary pins above
  • Coverage: >90% on the modified app.py/alerts.py/api.py branches

Completion Criteria

  • a configured build carries exactly one gateway job on the gateway host's shared TLS entry; an unconfigured build carries none (pinned)
  • a revocation in meta fails the gateway job before any dial (spy-pinned, the host:/disks: pair's shape)
  • /api/summary's gateway block is pinned with and without configuration; the pre-existing blocks are unchanged
  • the alerts pins hold: unconfigured silent, dead-source one line, no verdict rule
  • uv run pytest green, uv run ruff check src tests and uv run pyright clean
  • no behavior change in completed work: the pre-existing jobs, alerts, and summary blocks behave exactly as before