From e366f599f368dbe78a9d94e9c276ebba15849f8e Mon Sep 17 00:00:00 2001 From: ducoterra Date: Fri, 23 Oct 2026 22:56:21 -0400 Subject: [PATCH] phase: 30_gateway_connection_map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Phase 30 final verification pass — all 6 tasks already in `complete/`, so this was the phase-completion pass.** - **Verified (re-run, not trusted):** `/gateway` serves exactly two panels (nginx→haproxy, `GATEWAY_CARD_KEYS`); haproxy rows `.solo` straight across, nginx `:443` branched with one tick per leaf (18 live, fixture 17); every pipe computes the theme `--ok` in dark+light, animates only at count ≥1, fully static under `prefers-reduced-motion`; switch = `role="switch"`+`aria-checked`+`aria-disabled`, no listener, footer+title name the missing write path; zero non-GET requests anywhere. - **Live read-only re-run** (`data/logs/30-final-live-verify.out`): 17 PASS — `warnings: []`, 6 haproxy frontends→own `server`, `:443` 18 map leaves incl. `default→127.0.0.1:4443`, `:4443` 6 / `:8443` 3, `:80` bare listener, no `unmatched`/`outbound`/`by_port`/`partial`, no `9120`; inbound reconciliation **page 16 = kernel 16**; `gateway` block = the 12 declared keys; no `gateway:config` alert on a clean config. `git diff --stat agent/ deploy/` empty; agents 1.2.0 (gateway) / 1.1.0 ×2, all `tls`, `bundle_rev 2`. - **Tests/lint (exact):** `uv run pytest` → **1791 passed, 16 skipped**, exit 0 · `bash .agents/validate.sh` → **exit 0**, `--cov` **98.94%** (floor 94), `ruff check src tests agent` clean, `pyright` 0 errors, `node --check` all page scripts, hygiene clean · `uv run pytest -m live --live` → **12 passed** · `uv pip list --outdated` empty · `./scripts/dev-server.sh status` → **10 sources ok**, `gateway` included · browser pass `30-connection-map.out` 63 PASS/0 FAIL (5 screenshots at 1440/360) · `30-final-mobile-audit.out` 371 PASS/0 FAIL/0 FINDING, exit 0, nine pages. - **Docs fixed:** README `alerts.py` bullet omitted phase 30's keyword-only `gateway_payload` and its one `warn` config-integrity row (+suppression) — added; overview ingress line labelled a dated reading. AGENTS gap 13 corrected 391 px → **361 px** (task 05's pill took 30 px), "task 06 measured" → "phase 29 measured", coverage figure un-pinned to 98.9 %, live-suite count noted (12 today), "all five pages" severity sentence clarified for `/gateway`'s existence-only palette. Everything else reviewed in full and **verified consistent**. - **Defect fixed:** duplicated footer-assertion block at the end of `tests/test_api.py::test_the_switch_is_built_and_explicitly_unwired` (one copy removed). - **Notable:** `NOTES.md` is empty in the working tree — both items in it (non-mTLS agents, disappearing admin links) landed in phases 24 and 20; left cleared. Fixture/live `map`-count drift (17 vs 18) is recorded in AGENTS.md, not silently re-captured. - **Next pending phase:** none — `30_gateway_connection_map` was the only entry in `.agents/phases/todo/`. --- .../30_gateway_connection_map/00_phase.md | 64 + .../01_the_connection_graph.md | 78 + .../02_the_join_simplified.md | 43 + .../03_config_warnings.md | 63 + .../04_page_two_tables.md | 68 + .../05_lines_and_switches.md | 96 ++ .../06_docs_and_verify.md | 52 + ...30_gateway_connection_map__00_phase.a1.err | 0 .../30_gateway_connection_map__00_phase.a1.md | 9 + ...eway_connection_map__00_phase.a1.md.status | 1 + ...teway_connection_map__00_phase.a1.validate | 69 + ...ection_map__01_the_connection_graph.a1.err | 0 ...nection_map__01_the_connection_graph.a1.md | 17 + ..._map__01_the_connection_graph.a1.md.status | 1 + ...n_map__01_the_connection_graph.a1.validate | 74 + ...nection_map__02_the_join_simplified.a1.err | 0 ...nnection_map__02_the_join_simplified.a1.md | 15 + ...n_map__02_the_join_simplified.a1.md.status | 1 + ...on_map__02_the_join_simplified.a1.validate | 74 + ..._connection_map__03_config_warnings.a1.err | 0 ...y_connection_map__03_config_warnings.a1.md | 22 + ...ction_map__03_config_warnings.a1.md.status | 1 + ...ection_map__03_config_warnings.a1.validate | 74 + ..._connection_map__04_page_two_tables.a1.err | 0 ...y_connection_map__04_page_two_tables.a1.md | 22 + ...ction_map__04_page_two_tables.a1.md.status | 1 + ...ection_map__04_page_two_tables.a1.validate | 75 + ...nnection_map__05_lines_and_switches.a1.err | 0 ...onnection_map__05_lines_and_switches.a1.md | 26 + ...on_map__05_lines_and_switches.a1.md.status | 1 + ...ion_map__05_lines_and_switches.a1.validate | 75 + ..._connection_map__06_docs_and_verify.a1.err | 0 ...y_connection_map__06_docs_and_verify.a1.md | 13 + ...ction_map__06_docs_and_verify.a1.md.status | 1 + ...ection_map__06_docs_and_verify.a1.validate | 69 + AGENTS.md | 467 ++++-- README.md | 148 +- src/dashboards/alerts.py | 68 +- src/dashboards/api.py | 152 +- src/dashboards/sources/gateway.py | 911 ++++++++---- src/dashboards/web/pages/gateway.html | 153 +- src/dashboards/web/static/dash.css | 272 +++- src/dashboards/web/static/page-gateway.js | 887 +++++++----- src/dashboards/web/static/page-index.js | 46 +- tests/test_alerts.py | 186 ++- tests/test_api.py | 1262 ++++++++++++++--- tests/test_collectors.py | 2 +- tests/test_gateway_source.py | 999 +++++++++++-- tests/test_live_fleet.py | 62 +- tests/test_poller.py | 28 +- uv.lock | 190 +-- 51 files changed, 5419 insertions(+), 1519 deletions(-) create mode 100644 .agents/phases/complete/30_gateway_connection_map/00_phase.md create mode 100644 .agents/phases/complete/30_gateway_connection_map/01_the_connection_graph.md create mode 100644 .agents/phases/complete/30_gateway_connection_map/02_the_join_simplified.md create mode 100644 .agents/phases/complete/30_gateway_connection_map/03_config_warnings.md create mode 100644 .agents/phases/complete/30_gateway_connection_map/04_page_two_tables.md create mode 100644 .agents/phases/complete/30_gateway_connection_map/05_lines_and_switches.md create mode 100644 .agents/phases/complete/30_gateway_connection_map/06_docs_and_verify.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__00_phase.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__00_phase.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__00_phase.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__00_phase.a1.validate create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__01_the_connection_graph.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__01_the_connection_graph.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__01_the_connection_graph.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__01_the_connection_graph.a1.validate create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__02_the_join_simplified.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__02_the_join_simplified.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__02_the_join_simplified.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__02_the_join_simplified.a1.validate create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__03_config_warnings.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__03_config_warnings.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__03_config_warnings.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__03_config_warnings.a1.validate create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__04_page_two_tables.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__04_page_two_tables.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__04_page_two_tables.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__04_page_two_tables.a1.validate create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__05_lines_and_switches.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__05_lines_and_switches.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__05_lines_and_switches.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__05_lines_and_switches.a1.validate create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__06_docs_and_verify.a1.err create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__06_docs_and_verify.a1.md create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__06_docs_and_verify.a1.md.status create mode 100644 .agents/reports/30_gateway_connection_map/30_gateway_connection_map__06_docs_and_verify.a1.validate diff --git a/.agents/phases/complete/30_gateway_connection_map/00_phase.md b/.agents/phases/complete/30_gateway_connection_map/00_phase.md new file mode 100644 index 0000000..bbce773 --- /dev/null +++ b/.agents/phases/complete/30_gateway_connection_map/00_phase.md @@ -0,0 +1,64 @@ +# Phase 30 — The gateway connection map: two config-derived tables, joined lines, green = in the config + +**Source:** operator request, 2026-10-23 (post-phase-29 review of `/gateway`) +**Story:** n/a +**Context:** `src/dashboards/sources/gateway.py` (the join this phase rewrites), `agent/host_agent.py` **1.2.0** (its `haproxy` / `nginx` / `sockets` sections — the *only* upstream this phase reads, and it needs **no agent change**), `tests/fixtures/gateway_haproxy.cfg` + `gateway_nginx_main.conf` + `gateway_nginx_conf_d_http.conf` + `gateway_nginx_stream_d_stream.conf` + `gateway_proc_net_tcp{,6}.txt` (the verbatim captures the graph is pinned to), `src/dashboards/api.py` (`/api/gateway/*`, the `/api/summary` `gateway` block), `src/dashboards/alerts.py` (the reachability-only rule this phase changes by decision), `src/dashboards/web/pages/gateway.html` + `static/page-gateway.js` + `static/dash.css` (the pipe vocabulary), `tests/test_gateway_source.py`, `tests/test_api.py` (the served-bytes pins this phase deliberately rewrites). + +## Objective + +`/gateway` becomes the **connection map** it was meant to be: **two tables — nginx and haproxy** — in which every row is a connection **that exists in a config file**, drawn as a line that physically joins its inbound end to its outbound end (haproxy straight across; nginx branching out of `:443` to the services the stream `map` routes to), each line **green because the config says it exists**, each line carrying the **switch** shape from the operator's sketch (built, visible, not yet wired). The socket table is demoted to a number beside the line instead of deciding its colour or its existence; the `stream map` card and the `unmatched` card are gone; anything the two configs do not describe is **not reported at all**, and the warnings that remain are **config-integrity** problems — a backend no frontend routes to, a `proxy_pass $var` with no `map` — surfaced as a warnings panel on the page and one alert row on `/`. + +## Scope decisions taken with the operator (binding for this phase) + +| # | Decision | Consequence | +|---|----------|-------------| +| 1 | **Green means "in the config."** | Every configured connection draws green. Colour is an **existence state**, not a verdict: `severity.py` still has no `gateway.*` row and no payload key carries `severity`. Red is the **off** state (a route switched out of the config), styled now, unreachable until the write path exists. | +| 2 | **Motion means "a socket is open this instant."** | The dash animates while that pipe's live count is ≥ 1 and sits still otherwise. No rolling/recent-peak derivation, no speed tied to volume. | +| 3 | **The switch is built, not wired.** | Real `