phase: 31_gateway_route_readability

**Phase 31 verification complete — all 5 tasks already in `complete/`; this was the final verification pass.**

Verified / changed
- Re-ran every phase-31 artifact live and green: `verify-31-page-only.py` 6 PASS/0 FAIL; browser pass `31-route-readability.cjs` **64 PASS / 0 FAIL** (exit 0); `27-task02-mobile-audit.cjs` **371 PASS / 0 FAIL / 0 FINDING** (exit 0); rebuilt `data/logs/31-route-readability.out` as the 4-part transcript.
- Added the 4 degradation-arm screenshots the criterion asked for but the pass lacked (`31-gateway-{unconfigured,unreachable,no-nginx,sockets-quiet}.png`) — 12 frames now, one per arm.
- Grep criteria: no gateway connector rule uses `border-strong`; no verdict token in the gateway CSS section or `page-gateway.js` beyond the `alerts.py`-owned `.warn`; exactly 4 `addEventListener` calls (none for the switch); `routeInConfig()` returns `true`; **no `.py` under `src/dashboards/` changed**.

Tests / lint (all 100% green)
- `uv run pytest` → **1796 passed, 16 skipped**; `--cov` → **98.94%** (floor 94); `ruff check src tests agent` → All checks passed; `pyright` → 0 errors; `node --check` clean; `bash .agents/validate.sh` → **exit 0**.
- `uv run pytest -m live --live` → **12 passed / 0 failed**; `./scripts/dev-server.sh status` → all **10 sources ok**.

Completion criteria: colour (33/33 rows every segment `--gate-on`, dark `rgb(63,185,80)` + light `rgb(26,127,55)`, zero grey dashes) ✔ · inbound-first rows + filter (33/33 line 1 = `out.selectors`, line 2 = `→ host:port · kind`; `stackexpected` → **6** rows, not the overview's "five" — the capture declares 6 such routes; tallies byte-identical `10/33/16/0`, zero requests) ✔ · trunk motion truth table + `null` arm prints `n/a` never `0` + reduced-motion stills 43 paths and every knob ✔ · screenshots/transcripts ✔ · payload page-only ✔ (literal byte-diff of a live socket table can never pass; answered by the no-`.py`-diff + shape-equality proof, as recorded in the transcript) · no behaviour change elsewhere ✔.

Docs: fixed 6 inconsistencies — two identifiers split across line breaks (`test_the_pipe_animation_stills_in_both_states_under_reduced_motion`, `32_gateway_resolved_target_liveness`), stale "sixteen routes" count, stale "four machines/hosts" in README **and** AGENTS (fleet is three), "three fields"→"three field types", gap-14 headline wording; updated the pass's screenshot list.

Deviations: `uv pip list --outdated` shows one advisory (`starlette 1.9.0 → 1.10.0`) — not upgraded, this phase moved no dependency (rule 8 / DoD apply "if deps moved"). `TODO.md` carries two new operator disk requests, left untouched.

Next pending phase: `32_gateway_resolved_target_liveness`.
This commit is contained in:
2026-10-25 05:32:30 -04:00
parent e366f599f3
commit 25fd74b7c5
52 changed files with 3434 additions and 181 deletions
+833 -26
View File
@@ -5842,6 +5842,10 @@ def test_the_gateway_surface_is_gets_only_and_the_write_stays_the_ups_one(
#: `nginx.map_targets.*` / `haproxy.frontends.*` (neither is a row any more: the fan-out arrives as
#: `connections[]` carrying its own `out.kind`, which
#: `test_the_stream_map_is_rendered_inside_nginx_and_nowhere_else` pins), and added `warnings.*`.
#: Phase 31 task 02 put the four `connections.out.*` paths to a second use: they are exactly what the
#: leaf row's two text helpers index (`inboundText` → `selectors` then `kind`, `counterpartText` →
#: `host` + `port`), so `test_the_leaf_row_leads_with_the_inbound_word` resolves the same tuple the
#: page reads against a live document and a rename fails by name rather than printing `undefined`.
GATEWAY_PAGE_FIELDS = (
"host", "supported", "why", "agent_version",
"listeners.port", "listeners.source", "listeners.domains", "listeners.connections",
@@ -6034,6 +6038,29 @@ def test_every_pipe_is_an_accessible_image_built_from_the_payload(client) -> Non
trunk = js[js.index("function renderTrunk("):js.index("function renderLeaves(")]
for fact in ("listener.connections", "listener.clients", "listener.domains"):
assert fact in trunk, f"the trunk stopped saying {fact}"
# Phase 31 task 03: the trunk now draws a line as well as printing words, so it is an image with
# a name of its own. **Two** pipe builders' outputs must carry one shape, because the moment one
# of the two lines loses its `role` or its sentence it is an unnamed stroke beside a named one.
assert js.count("createElementNS(SVG_NS, 'svg')") == 1, \
"a second place now constructs an `<svg>`, so the leaf's run and the trunk's stub can "\
"drift apart in geometry, class shape or accessibility"
assert "buildPipe(true)" in js and "li.appendChild(buildPipe())" in js, \
"one of the two lines is no longer built by the one builder"
stub = js[js.index("function buildPipe("):js.index("function routeInConfig(")]
assert "'pipe pipe-trunk' : 'pipe'" in stub, \
"the trunk's stub no longer shares `.pipe` with the leaf's run, so its states are its own"
assert "trunkAria(" in trunk, "the trunk's line has no accessible sentence of its own"
assert "svg.setAttribute('role', 'img')" in trunk, \
"the trunk's line is an unnamed shape: a screen reader gets the panel and none of its ports"
# Phase 31 task 05 measured this in a browser: `title` is a reflected IDL attribute of
# `HTMLElement` and **not** of `SVGElement`, so `svg.title = …` invents a JavaScript property no
# tooltip ever reads. The trunk's sentence has to go on as an attribute or the port's number is
# ink with no explanation on hover — which is what the served code had been doing.
assert "svg.setAttribute('title', aria)" in trunk, \
"the trunk's tooltip is no longer a real attribute: on an `<svg>` an assignment to `.title` " \
"is a property no hover reads"
assert "svg.title =" not in trunk, \
"`svg.title = …` looks like a tooltip and is not one on an SVGElement"
# upstream text reaches the page through textContent and title, and nothing else …
assert "innerHTML" not in rendered
assert "textContent" in js and "escapeHtml" not in js, \
@@ -6056,6 +6083,15 @@ def test_a_pipe_moves_only_while_it_carries_a_connection(client) -> None:
* `on` / `off` — "a proxy config declares this route" — decides **stroke only**
(`test_a_connection_is_green_because_it_is_in_the_config`).
Phase 31 task 03 added a **second** pipe — the trunk's short stub — and with it a second source of
truth, which is the part worth pinning. A leaf reads `connections[].connections` (the sockets at
that route's endpoint); a trunk reads `listeners[].connections`, which `/proc` states as the
ESTABLISHED sockets whose **local** end is that listen port. The trunk's number is therefore a
claim about a **port** and **never about a leaf**: `:4443` moving does not mean `nextcloud` has
traffic, and that is why the trunk's sentence names the port and no endpoint
(`test_the_trunk_pipe_is_an_accessible_image_of_its_port`). Both pipes use the same two class pairs
and neither may borrow the other's colour, motion or accessible name.
The keyframe's only property stays `stroke-dashoffset`: the dash travelling is the whole
animation, and animating a colour would put a number's judgement inside a line. And
`vector-effect="non-scaling-stroke"` stays in the script: the pipe is stretched to the card's
@@ -6088,6 +6124,27 @@ def test_a_pipe_moves_only_while_it_carries_a_connection(client) -> None:
"the live test is no longer the connection count itself"
assert 'vector-effect' in js
# …and the trunk's stub, whose `live` comes from a **different payload path** and may only ever
# come from that one. A leaf answers "is a socket open on this route?"; a trunk answers "is a
# socket arriving on this port?" — the port's number belongs to the trunk as a whole, so crediting
# it to one of the leaves under it would be a claim `listeners[]` cannot make.
trunk = js[js.index("function renderTrunk("):js.index("function renderLeaves(")]
assert "const count = listener.connections" in trunk, \
"the trunk no longer reads its own `listeners[].connections` field"
assert "const measured = typeof count === 'number' && isFinite(count)" in trunk, \
"the trunk no longer separates `0` (measured, idle) from `null` (not measured)"
assert "svg.classList.toggle('live', measured && count > 0)" in trunk, (
"the trunk's motion is no longer the port's own count — either it animates on an unknown "
"(a `null` read as traffic) or it stopped animating on a busy port at all")
assert "svg.classList.toggle('still', !measured || count === 0)" in trunk, \
"the trunk has no static state, so an unknown reads as motion"
for leaf_field in ("conn.connections", "endpointText", "out.selectors", "connections.shared"):
assert leaf_field not in trunk, (
f"the trunk reads {leaf_field} — a trunk's line is a fact about a **port** and may never "
"be derived from a leaf's endpoint, or one stub would move for one route out of sixteen")
assert "const live = typeof conn.connections === 'number'" in js, \
"the leaf's motion no longer keys on its own endpoint count"
def test_a_connection_is_green_because_it_is_in_the_config(client) -> None:
"""`--gate-on` is the whole colour story, and it answers *does the config say so*.
@@ -6135,6 +6192,507 @@ def test_a_connection_is_green_because_it_is_in_the_config(client) -> None:
assert "const on = routeInConfig(conn)" in js
def test_the_whole_route_takes_one_existence_class(client) -> None:
"""One class on the `<li>` paints the spine, the tick, the run **and** the switch.
The operator's complaint was about ink they could see: *"Why are the dotted lines on the left
grey? Shouldn't those be green too? They're active."* Phase 30 applied the existence pair to
`.pipe-path` alone, so every route drew its last third in the config's green and the rest of its
length in structural grey — a picture that contradicted the page's own claim on all 33 rows.
Phase 31 task 01 moves the state onto the **row**: `renderLeaf` toggles `on`/`off` on the `<li>`
off the same value it colours the `<svg>` with, and four rules reach the two halves of the spine
and the tick out to the switch from that one class.
Two rules keep that from being a colour change with no contract behind it:
* The base connector rules declare `transparent`. An SVG path with no `stroke` is invisible for
free; a border's default colour is `currentColor`, so "a row built and never rendered draws
nothing" has to be **written down** for a border the way the missing `stroke` does for a path.
* The switch keeps taking its colour from `[aria-checked]` (phase 30's pin, asserted again here).
The row is now painted by two selectors — `.gate-link.on` and `[aria-checked]` — both driven
from one value, and a pin on only one of them is how the two halves of a row end up disagreeing.
"""
section = _code(_css_section(_css(client), "gateway pipes"))
rules = [(" ".join(sel.split()), body)
for sel, body in re.findall(r"([^{}]+)\{([^}]*)\}", section)]
def painted(selector: str) -> list[str]:
"""Bodies of the rules whose selector **list** names `selector` exactly."""
return [body for sel, body in rules
if selector in [part.strip() for part in sel.split(",")]]
for segment in (".gate-link.on::before", ".gate-link.on::after", ".gate-link.on .gate-elbow"):
bodies = painted(segment)
assert bodies, f"nothing paints {segment} from the row's `on` class — that segment of the " \
"route is still structural ink, which is the defect this task was written to close"
assert "var(--gate-on)" in " ".join(bodies), \
f"{segment} takes its colour from somewhere other than the existence pair"
for segment in (".gate-link.off::before", ".gate-link.off::after", ".gate-link.off .gate-elbow"):
bodies = painted(segment)
assert bodies, f"nothing paints {segment} from the row's `off` class, so the pair is half a " \
"vocabulary for the connectors and a route could never be drawn out of the config"
assert "var(--gate-off)" in " ".join(bodies), \
f"{segment} takes its colour from somewhere other than the existence pair"
# Geometry, no colour: a row the payload pass never reached must draw no dashed ink at all.
for selector, prop in ((".gate-link::before", "border-left"),
(".gate-link::after", "border-left"),
(".gate-elbow", "border-top")):
value = _declarations(section, selector).get(prop, "")
assert value.endswith("transparent"), (
f"{selector} declares {value!r} instead of a dashed border whose colour is "
"`transparent` — an uncoloured border is `currentColor`, so an unrendered row would draw "
"a line in whatever colour its text happens to be")
assert "--border-strong" not in section, (
"a gateway connector still reads the structure token: the row's green has to run from its "
"trunk to its endpoint, and one grey segment of it says the route is not in the config")
js = _code(client.get("/static/page-gateway.js").text)
leaf = js[js.index("function renderLeaf("):js.index("function groupElement(")]
assert "const on = routeInConfig(conn)" in leaf, \
"the row's state no longer comes from the one reading of the payload"
for target in ("li", "svg"):
assert f"{target}.classList.toggle('on', on)" in leaf, \
f"`on` is no longer written on the {target}, so part of the route colours itself "\
"without the payload saying the route exists"
assert f"{target}.classList.toggle('off', !on)" in leaf, \
f"`off` is not written on the {target} beside `on` — one row could show both states"
assert leaf.index("const on = routeInConfig(conn)") < leaf.index(
f"{target}.classList.toggle('on', on)"), (
f"the {target}'s state is set before the payload is read")
row = js[js.index("function leafRow("):js.index("function renderLeaf(")]
assert "li.className = 'gate-link'" in row
assert "classList" not in row, \
"a row now ships a state class before any payload reached it, so an unrendered leaf draws a "\
"confident route"
# …and the two halves of the row that already had the pair still take it the same way, so the
# connectors joining them cannot arrive on a third vocabulary.
assert _declarations(section, ".pipe.on .pipe-path").get("stroke") == "var(--gate-on)", \
"the run no longer colours from the pair the connectors do"
assert "var(--gate-on)" in _declarations(section, ".gate-switch").get("border", ""), \
"the switch's on-state border is no longer the existence pair"
assert "var(--gate-off)" in _declarations(
section, '.gate-switch[aria-checked="false"]').get("border-color", ""), \
"the switch's off state has no colour, so `[aria-checked]` is decoration again"
def rendered_trunk(row: dict[str, Any]) -> dict[str, Any]:
"""What one trunk prints, claims and animates, recomputed from the payload as a **second** reading.
The `rendered_leaf` idiom, for the same reason: there is no JS runner (a locked anchor), so the
sentence and the two classes are re-derived here from the literals the served-byte pins below
assert verbatim. `renderTrunk` prints `N live` / `n/a` in `.pipe-count` and `trunkAria` says the
port's sentence; a rename or a paraphrase on either side therefore fails a pin **and** moves what
this mirror prints. Nothing here reads a leaf: the trunk's whole claim is about its port.
"""
port = f":{row['port']}"
count = row["connections"]
measured = isinstance(count, (int, float)) and not isinstance(count, bool)
if not measured:
aria = f"{port} \u2014 connections on this port are unknown: the socket table did not answer"
else:
how_many = "no" if count == 0 else str(count)
verb = "connection is" if count == 1 else "connections are"
aria = f"{port} \u2014 {how_many} {verb} open on this port right now"
return {"count": "n/a" if not measured else f"{count} live",
"aria": aria,
"live": bool(measured and count > 0),
"still": not measured or count == 0,
# a trunk row exists because a config names the port, which is the existence fact
"on": True}
def test_the_trunk_pipe_is_an_accessible_image_of_its_port(client, gateway_client,
gateway_snapshot) -> None:
"""Every trunk draws a short line that moves on **its port's** count and says so in one sentence.
The operator's complaint (2026-10-23): *"The only animated line is `:443 -> 127.0.0.1:4443`."*
On the live ingress almost every leaf endpoint is a **name** the page cannot resolve, so its count
is a dash and its line is still — while the kernel states, for the port itself, how many
ESTABLISHED sockets have it as their local end. That figure is a real measurement, and it is the
only live number this page can print until name resolution lands, so the trunk draws it as a line.
The claim has to stay a **port** claim. `:4443` moving does not mean `nextcloud`'s route carries
those sockets, so the sentence names the port and no endpoint, in all three arms:
:4443 \u2014 9 connections are open on this port right now
:4443 \u2014 no connections are open on this port right now
:4443 \u2014 connections on this port are unknown: the socket table did not answer
and the unknown arm never prints `0` — neither in the sentence nor in `.pipe-count` (rule 2). The
three blocks below are the three ways that goes wrong: the pipe stops being a named image; the
sentence paraphrases "on this port" away or names an endpoint; or the unknown arm is treated as
zero and a silent router starts looking like an idle one.
"""
js = _code(client.get("/static/page-gateway.js").text)
# (1) the stub is built by the one pipe builder and lands inside the trunk, after the count.
group = js[js.index("function groupElement("):js.index("function trunkAria(")]
assert "wrap.querySelector('.gate-trunk').appendChild(buildPipe(true))" in group, (
"the trunk no longer draws a line, or draws it somewhere other than the trunk itself \u2014 "
"an `<svg>` cannot come from the `innerHTML` template, which is why it is appended")
assert group.index("pipe-count") < group.index("buildPipe(true)"), \
"the stub is no longer the count's neighbour at the trunk's right edge"
# (2) the sentence: three arms, every word pinned, and nothing but `listeners[].connections`.
aria = js[js.index("function trunkAria("):js.index("function renderTrunk(")]
assert "`${port} \u2014 connections on this port are unknown: the socket table did not answer`" in aria, \
"the unknown arm no longer says `unknown` \u2014 it must not read as an idle port (rule 2)"
assert "open on this port right now" in aria, \
"the measured arms stopped naming the port as the subject of the sentence"
assert "'no'" in aria and "'connection is'" in aria and "'connections are'" in aria, \
"the measured arms stopped saying 0 as `no` and 1 as `connection is`"
assert "(group.listener || {}).connections" in aria, \
"the sentence no longer reads the port's own figure"
for leaf_field in ("conn.", "out.", "endpointText", "selectors", "host", "clients"):
assert leaf_field not in aria, (
f"the trunk's sentence reaches for {leaf_field} \u2014 the sockets a port counts belong to "
"the trunk as a whole, and naming a route would credit them to one leaf")
# (3) the classes, and the `null` arm that must not move and must not print `0`.
trunk = js[js.index("function renderTrunk("):js.index("function renderLeaves(")]
assert "svg.hidden = group.listener == null" in trunk, \
"a group with no listener row now draws a stub for a port nobody read"
assert "svg.classList.toggle('on', group.listener != null)" in trunk, \
"the stub stopped taking its colour from the existence fact the trunk row itself is"
assert "svg.classList.toggle('off', false)" in trunk, \
"`off` is no longer cleared on the trunk, so a re-used group could keep a stale state"
# (4) the fixture render, both directions of the rule, over the captured ingress and over the
# socket table going quiet (`sockets_silent`, which is what the agent's unreadable
# /proc/net/tcp{,6} actually produces).
answered = gateway_client.get("/api/gateway/snapshot").json()
listeners = answered["listeners"]
assert listeners, "the capture names no port, so this pin would prove nothing"
endpoints = {f"{c['out']['host']}:{c['out']['port']}" for c in answered["connections"]}
busy = [row for row in listeners if row["connections"]]
idle = [row for row in listeners if row["connections"] == 0]
assert busy and idle, (
f"the capture reports {sorted(r['port'] for r in busy)} busy and "
f"{sorted(r['port'] for r in idle)} idle \u2014 both arms need a port in them to be pinned")
for row in listeners:
printed = rendered_trunk(row)
assert printed["live"] == bool(row["connections"]), \
f":{row['port']} animates on something other than its own non-zero count"
assert printed["live"] != printed["still"], \
f":{row['port']} is both moving and still \u2014 the two arms are one class each"
assert printed["aria"].startswith(f":{row['port']} \u2014"), \
"the sentence no longer leads with the port it is about"
for endpoint in endpoints:
assert endpoint not in printed["aria"], (
f"the trunk of :{row['port']} names the endpoint {endpoint} \u2014 a port's count is "
"not that route's traffic")
# both directions of "never `0` for an unknown"
assert (printed["count"] == "n/a") == (row["connections"] is None), \
f":{row['port']} prints {printed['count']!r} for a count of {row['connections']!r}"
# …and the other half of the same honesty: a port the table *did* answer with nothing on it
# says so. `0` is a measurement here, not an absence, and it is the reason the trunk prints
# `n/a` for the unknown instead of one word for both facts.
if row["connections"] is not None:
assert printed["count"] == f"{row['connections']} live", \
f":{row['port']} hid a count the socket table actually reported"
assert rendered_trunk(busy[0])["live"], "a port the kernel reports traffic on sits still"
assert not rendered_trunk(idle[0])["live"], "an idle port animates \u2014 motion became a guess"
silent = gateway_source.parse(gateway_snapshot("sockets_silent"), "gateway")
quiet = silent["listeners"]
assert quiet and all(row["connections"] is None for row in quiet), \
("`sockets_silent` no longer yields null listener counts, so this no longer exercises the "
"arm the page has to render as `n/a`")
for row in quiet:
printed = rendered_trunk(row)
assert printed["on"] and not printed["live"] and printed["still"], (
f":{row['port']} is not green-and-motionless with the socket table quiet \u2014 the "
"configs are still drawn and nothing is claimed about traffic")
assert printed["count"] == "n/a", \
f":{row['port']} prints {printed['count']!r} instead of `n/a` when nobody measured"
assert printed["count"] != "0 live", "an unanswered socket table became a claimed zero"
assert "unknown" in printed["aria"] and "did not answer" in printed["aria"], \
f":{row['port']}'s sentence hides that the reading is missing"
assert not any(rendered_trunk(row)["count"] == "0 live" for row in quiet), \
"a page with no socket table printed `0 live` somewhere"
def _leaf_haystack(row: dict[str, Any]) -> str:
"""The one string the filter can see about one route, as `page-gateway.js` composes it."""
out = row.get("out") or {}
port = (row.get("in") or {}).get("port")
parts = ["" if port is None else str(port), out.get("host"), out.get("name"), out.get("kind"),
*(out.get("selectors") or [])]
return " ".join(p for p in parts if isinstance(p, str) and p).lower()
def _trunk_haystack(port: int, listener: dict[str, Any]) -> str:
"""The same for a trunk: the port as the page prints it, then its domains and clients."""
parts = [f":{port}", *(listener.get("domains") or []), *(listener.get("clients") or [])]
return " ".join(p for p in parts if isinstance(p, str) and p).lower()
def filter_view(snapshot: dict[str, Any], query: str) -> dict[str, Any]:
"""What the page leaves standing for one query, derived as a **second** reading.
There is no JS runner (a locked anchor), so this is `rendered_leaf`'s idiom: the rules are
re-applied here from the payload, and the served-byte pins in the test below are what keep the
mirror honest — `haystack` indexes `in.port`, `out.host`, `out.name`, `out.kind`, `out.selectors`;
`trunkHaystack` indexes `:${port}`, `domains`, `clients`; a trunk that matches keeps **all** its
leaves; a group stands when it or one of its routes answers. A rename on either side therefore
fails a pin *and* changes what this mirror prints.
Returns the panels' worth of groups plus the two numbers the count chip prints, both over leaf
routes: `standing` and `total`.
"""
needle = query.strip().lower()
groups: list[dict[str, Any]] = []
standing = 0
for key in ("nginx", "haproxy"): # the order `CARDS` declares
by_port: dict[int, dict[str, Any]] = {}
for row in snapshot["listeners"]:
if row["source"] != key:
continue
by_port.setdefault(row["port"], {"panel": key, "port": row["port"],
"listener": None,
"connections": []})["listener"] = row
for row in snapshot["connections"]:
if row["source"] != key:
continue
by_port.setdefault(row["in"]["port"],
{"panel": key, "port": row["in"]["port"], "listener": None,
"connections": []})["connections"].append(row)
for port in sorted(by_port):
group = by_port[port]
trunk_hit = needle in _trunk_haystack(port, group["listener"] or {})
leaves = []
for row in group["connections"]:
shown = trunk_hit or needle in _leaf_haystack(row)
leaves.append({"id": row["id"], "hidden": not shown})
if shown:
standing += 1
groups.append({"panel": key, "port": port, "trunk_hit": trunk_hit,
"hidden": bool(needle) and not trunk_hit
and not any(not leaf["hidden"] for leaf in leaves),
"leaves": leaves})
return {"groups": groups, "standing": standing, "total": len(snapshot["connections"])}
def test_the_filter_narrows_the_map_without_asking_anything(client, gateway_client) -> None:
"""One field, four rules, and not one extra request.
The operator's complaint is a reading-speed one: *"I want to find a domain."* This ingress routes
33 of them off two config files, and a page that draws all 33 every 30 s makes that a scan. The
field is an **eye, not a query**, and the four halves of that sentence are the four ways the
feature could go wrong:
* **It matches payload text and nothing else.** `in.port`, `out.host`, `out.name`, `out.kind`,
`out.selectors` for a route, `:${port}` + `domains` + `clients` for a trunk. No DNS (the module
still resolves no name), no re-ranking, no rule about `.reeselink.com` — a query can never
invent a route, because there is no other text to match.
* **It costs nothing.** The repaint runs on `state.snapshot`; a keystroke that re-fetched would be
a poll per character and a lie about what changed.
* **It hides rows, it does not remove them.** `li.hidden` in the patch pass, so a route the query
hides keeps its identity, its state classes and its place for the next poll.
* **It moves nothing else.** The four header tallies are the payload's figures, the warnings panel
is a different claim, and the charts follow the panel: beside a filtered map the header still
says what the whole ingress declares and carries.
"""
js = _code(client.get("/static/page-gateway.js").text)
# (1) the matcher's whole vocabulary: five payload fields for a route, three for a trunk.
hay = js[js.index("function haystack("):js.index("function trunkHaystack(")]
assert "String((conn.in || {}).port ?? '')" in hay, \
"the inbound port is no longer searchable — `4443` is the second thing an operator types"
for field in ("out.host", "out.name", "out.kind", "out.selectors"):
assert field in hay, f"the filter no longer sees {field}"
assert "toLowerCase()" in hay, "the match became case-sensitive on a page of lowercase domains"
for absent in ("conn.connections", "severity", "metric", "getaddrinfo", "split(",
"endsWith", "startsWith", "slice("):
assert absent not in hay, (
f"the matcher reached for {absent} — it may read what the payload calls a route, never "
"what it reports about it, and never resolve a name")
trunk = js[js.index("function trunkHaystack("):js.index("function filtering(")]
for field in ("group.port", "listener.domains", "listener.clients"):
assert field in trunk, f"the trunk no longer answers for {field}"
# (2) the repaint path: the payload in hand, no network, and no re-entry into the poll.
panels = js[js.index("function renderPanels("):js.index("function pruneCards(")]
assert "fetchJSON" not in panels and "refresh(" not in panels, (
"the filter path dials something — it is an eye over `state.snapshot`, and a keystroke must "
"cost no request (nor may it re-enter `refresh()`, which fetches a history pair per panel)")
wiring = js[js.index("function initFilter("):js.index("function pruneCards(")]
assert "state.filter = event.target.value.trim()" in wiring, \
"the filter stopped taking its needle verbatim-and-trimmed from the field"
assert "event.key !== 'Escape'" in wiring, \
"Escape no longer clears the field, so getting out of a filter means backspacing it"
assert "fetchJSON" not in wiring and "refresh(" not in wiring
count = js[js.index("function renderFilterCount("):js.index("function initFilter(")]
assert "`${standing} of ${total} routes`" in count, \
"the chip stopped counting leaf routes the way the panels draw them"
assert "chip.hidden = true" in count, \
"the count stays on screen beside an empty field — ink about nothing"
# (3) the tallies and the warnings list never move, because neither is a route.
for name, end in (("renderHeader", "async function refresh("),
("renderWarnings", "function dotFor(")):
body = js[js.index(f"function {name}("):js.index(end)]
for leak in ("state.filter", "filtering(", "haystack(", "leafShown(", "trunkShown("):
assert leak not in body, (
f"{name} now reads {leak} — the header's four figures and the warnings count are the "
"payload's own and must keep saying what the whole ingress declares")
# (4) rows are hidden, not removed, inside the patch pass that already holds them.
leaves = js[js.index("function renderLeaves("):js.index("function renderGroups(")]
assert "li.hidden = shown !== null && !shown[index]" in leaves, (
"a leaf is no longer hidden by index into the group's own connection list — the one form "
"that cannot credit a count to the wrong row")
refusal = leaves[leaves.index("const emptyId"):]
assert ".hidden" not in refusal, (
"the trunk's refusal sentence is being hidden by a route's rules — it belongs to the trunk, "
"so this fleet's `:80` is found by typing `80` and by nothing a route says")
assert ".remove()" not in leaves, \
"the filter deleted a row; removal belongs to a route leaving the config"
groups = js[js.index("function renderGroups("):js.index("function familyWord(")]
assert "el.hidden = !visible" in groups, "a trunk is no longer hidden as a whole"
assert "const shown = trunk ? null : group.connections.map(leafShown)" in groups, (
"a trunk that answered the query no longer keeps its whole fan-out — typing `4443` asks for "
"the port, and every route on it is part of the answer")
assert "const visible = !filtering() || trunk || shown.some(Boolean)" in groups, (
"a group is no longer standing on \"the trunk or one of its routes\", which is the one rule "
"that decides whether a port disappears from the map")
assert "none.hidden = !stranded" in groups and \
"const stranded = filtering() && groups.length > 0 && standing === 0" in groups, (
"the panel's no-match sentence is no longer keyed on all three of: the filter is up, there "
"were groups, and the query hid every one of them")
assert '[data-k="no-match"]' in groups and 'no route matches' in groups, \
"a panel whose every group is hidden now says nothing at all"
# (5) the capture, through the mirror: the four answers the field has to give.
payload = gateway_client.get("/api/gateway/snapshot").json()
total = len(payload["connections"])
assert total > 10, "the capture routes too little for a filter to prove anything"
everything = filter_view(payload, "")
assert everything["standing"] == total and not any(
leaf["hidden"] for group in everything["groups"] for leaf in group["leaves"]), \
"an empty query hides something — it must be the same page as no query at all"
assert not any(group["hidden"] for group in everything["groups"]), \
"an empty query hid a trunk"
brain = filter_view(payload, "brain")
shown = [leaf["id"] for group in brain["groups"] for leaf in group["leaves"]
if not leaf["hidden"]]
assert brain["standing"] == len(shown) > 1, \
"`brain` matched nothing but the brain routes"
assert all("brain" in _leaf_haystack(next(c for c in payload["connections"]
if c["id"] == leaf_id))
for leaf_id in shown), "`brain` showed a route it does not appear in"
assert all(c["id"] in shown for c in payload["connections"]
if "brain" in _leaf_haystack(c)), "`brain` lost a route it appears in"
assert any(group["port"] == 443 and not group["hidden"] for group in brain["groups"]), \
"the trunk the brain routes hang off was hidden with the rest of its fan-out"
assert brain["standing"] < total, "nothing was filtered out at all"
port4443 = filter_view(payload, "4443")
for group in port4443["groups"]:
if group["port"] == 4443:
assert not group["hidden"] and all(
not leaf["hidden"] for leaf in group["leaves"]), \
":4443 did not keep its whole fan-out — typing a port asks for the port"
else:
assert group["hidden"], f":{group['port']} survived a query for :4443"
nothing = filter_view(payload, "no-such-domain-anywhere")
assert nothing["standing"] == 0 and all(group["hidden"] for group in nothing["groups"]), \
"a query that matches nothing left a row or a trunk on the page"
# (6) a trunk answers for **itself**: a client address is the listener's own payload, and typing
# it is a question about the port, so every route under it stays as part of the answer.
client_row = next((row for row in payload["listeners"] if row["clients"]), None)
assert client_row, "the captured socket table names no client, so this arm cannot be exercised"
by_port = filter_view(payload, client_row["clients"][0])
home = next(group for group in by_port["groups"] if group["port"] == client_row["port"])
assert home["trunk_hit"] and not home["hidden"], \
f"typing {client_row['clients'][0]!r} did not match :{client_row['port']}'s own row"
assert all(not leaf["hidden"] for leaf in home["leaves"]), \
"a trunk that matched lost leaves of its fan-out"
def test_the_filter_field_is_markup_the_sheet_and_nobody_else_uses(client) -> None:
"""The field is pinned markup, on one page, wearing the sheet's one field skin.
Three absences carry as much as the two presences. **No other page ships `type="search"`**: the
shared rule is what makes a field match the theme, and a page growing its own styled box is how a
control stops following a theme change. The base rule is `max-width: 18rem; min-width: 0` and the
≤640 px block makes it `width: 100%` — a 33-name ingress is exactly the case for typing into the
field on a phone, and a field that keeps 18 rem of cap there is a field with two characters of
visible text. And `.gate-filter` carries no `:hover`, no `cursor` and no `transition`: the
connection map owns one interactive-looking thing (the unwired switch's knob) and this is not it.
"""
css = _css(client)
shared = _declarations(css, 'input[type="text"], input[type="password"], input[type="search"]')
for prop in ("background", "color", "border", "border-radius", "padding", "font"):
assert shared.get(prop), f"the shared field rule no longer declares {prop}"
assert shared.get("border") == "1px solid var(--border)", \
"the field skin drifted from the sheet's own border token"
section = _code(_css_section(css, "gateway pipes"))
base = _declarations(section, ".gate-filter")
assert base.get("max-width") == "18rem", \
f"the field is capped at {base.get('max-width')!r} rather than 18rem"
assert base.get("min-width") == "0", \
"without `min-width: 0` the field cannot shrink, so a long placeholder grows the page head"
# The phone override lives in the gateway section's own ≤640 px block and says only that one thing.
mobile = section[section.index("@media (max-width: 640px)"):]
reach = re.search(r"\.gate-filter\s*\{([^}]*)\}", mobile)
assert reach, "the field is not full-width at the phone break — 33 domains want a real field"
wide = _declarations(mobile, ".gate-filter")
assert wide.get("width") == "100%", f"the phone rule reads {wide} rather than `width: 100%`"
assert wide.get("max-width") == "none", (
f"{wide} lifts the width but not the 18rem cap, so the field is still 288 px on a 320 px page")
for selector, body in re.findall(r"([^{}]*\.gate-filter[^{}]*)\{([^}]*)\}", _code(css)):
assert ":hover" not in selector, f"the filter grew a hover affordance: {selector.strip()}"
assert "cursor" not in body and "transition" not in body, (
f"the field advertises itself as a pointer control: {body.strip()}")
pages = {path: client.get(path).text for path in (*MARKUP_PAGES, "/login")}
html = pages[GATEWAY_PAGE]
head = html[html.index("Connection map"):]
field = next(tag for tag in re.findall(r"<input[^>]*>", head) if 'id="gate-filter"' in tag)
chip = next(tag for tag in re.findall(r"<span[^>]*>", head) if 'id="gate-filter-count"' in tag)
for attr in ('type="search"', 'class="gate-filter"', 'autocomplete="off"', 'spellcheck="false"'):
assert attr in field, f"the filter field lost {attr}"
assert 'aria-label="Filter routes by domain, endpoint or port"' in field, \
"the field has no accessible name — a placeholder is a hint, not a label"
assert "placeholder=" in field, "the field no longer says what it matches on"
assert 'class="chip faint"' in chip and "hidden" in chip \
and 'aria-live="polite"' in chip, f"the count chip is {chip}"
for other, page in pages.items():
if other != GATEWAY_PAGE:
assert 'type="search"' not in page, f"{other} grew a second search field"
# one no-match sentence per panel, and it ships hidden like every conditional sentence here
for key in ("nginx", "haproxy"):
card = html[html.index(f'data-gate="{key}"'):]
card = card[:card.index("</article>")]
assert card.count('data-k="no-match"') == 1, \
f"the {key} panel has no single no-match sentence"
assert 'data-k="no-match" hidden' in card, f"the {key} no-match sentence ships visible"
assert 'data-k="empty"' in card, \
f"the {key} panel lost the sentence for a config that names no port — the filter's " \
"sentence is a different fact"
# the footer says what the field does and does not touch, once
foot = " ".join(html[html.index("<footer class="):].split())
assert "hides the routes whose own labels do not contain what you typed" in foot, \
"the page stopped saying out loud that the filter asks for nothing"
assert "the tallies, the warnings and the charts above it are still the whole ingress" in foot, \
"the sentence no longer names the three things a filter must not quietly narrow"
for junk in ("no page narrates", "every value is scraped", "filters live, nothing is stored"):
assert junk not in foot, f"the footer grew flavour text: {junk}"
def test_haproxy_draws_straight_across_and_nginx_branches(client) -> None:
"""The geometry the operator asked for, in four rules and zero JavaScript.
@@ -6157,8 +6715,12 @@ def test_haproxy_draws_straight_across_and_nginx_branches(client) -> None:
before = _declarations(section, ".gate-link::before")
after = _declarations(section, ".gate-link::after")
for name, rule in (("::before", before), ("::after", after)):
assert rule.get("border-left") == "2px dashed var(--border-strong)", \
f"the spine's {name} half lost its dashed border"
# `transparent`, not a colour: this rule is the branch's *geometry*, and the ink arrives from
# the row's state class (`test_the_whole_route_takes_one_existence_class`). A colour here would
# be a row drawing a confident line before any payload said the route exists.
assert rule.get("border-left") == "2px dashed transparent", (
f"the spine's {name} half no longer declares a dashed, colourless border — geometry "
"belongs on the row and colour belongs to `.gate-link.on`/`.off`")
assert rule.get("position") == "absolute" and rule.get("left") == "0", \
f"the spine's {name} half no longer sits in the row's gutter"
assert before.get("top") == "calc(var(--gate-leaf-gap) / -2)", \
@@ -6175,8 +6737,10 @@ def test_haproxy_draws_straight_across_and_nginx_branches(client) -> None:
"`--gate-leaf-gap` is no longer declared in `:root`"
assert _declarations(section, ".gate-link:first-child::before, .gate-link:last-child::after").get(
"display") == "none", "the fan-out grew a spine past its first and last branch"
assert "2px dashed" in _declarations(section, ".gate-elbow").get("border-top", ""), \
"the tick from the spine to the switch is gone, so a leaf no longer reaches its trunk"
elbow = _declarations(section, ".gate-elbow").get("border-top", "")
assert "2px dashed" in elbow and elbow.endswith("transparent"), (
"the tick from the spine to the switch is gone, or coloured itself, so a leaf no longer "
"reaches its trunk in the same ink as its run")
solo = _declarations(
section, ".gate-group.solo .gate-link::before, .gate-group.solo .gate-link::after")
@@ -6221,6 +6785,14 @@ def test_the_pipe_animation_stills_in_both_states_under_reduced_motion(client) -
Phase 30 task 05 added the third name, and it is not decoration: the switch's knob slides on a
`transition` of its own, and a block that stills the pipes while the thumb keeps sliding is the
phase-18 lesson half-applied — the operator asked for no motion, not for less of it.
Phase 31 task 03 added a **second pipe** (the trunk's stub) and deliberately added no fourth name.
That works only because of how the two names are written, so it is pinned rather than assumed: the
selectors are **descendant** (`.pipe.live .pipe-path`), and the stub is built by the same
`buildPipe(trunk)` with the same `pipe pipe-trunk` class list and the same `.pipe-path` child. A
rule that reaches `.pipe.live .pipe-path` therefore reaches a trunk's path too. The failure this
prevents is the quiet one: someone gives `.pipe-trunk .pipe-path` its own `animation` to make the
stub "nicer", and the block below stops covering it.
"""
code = _code(_css(client))
block = re.search(r"@media\s*\(prefers-reduced-motion:\s*reduce\)\s*\{(.*?)\n\}",
@@ -6236,16 +6808,36 @@ def test_the_pipe_animation_stills_in_both_states_under_reduced_motion(client) -
"the named rules stopped stilling the animation"
assert _declarations(block.group(1), ".gate-switch-thumb").get("transition") == "none", \
"the switch's knob still slides when the operator asked for no motion"
# The two names are descendant selectors, which is the whole reason a second pipe needs no third:
# `.pipe.live` is on the `<svg>` (leaf or trunk) and `.pipe-path` is its child in both cases.
assert all(name.endswith(" .pipe-path") for name in named), (
f"the stilling rules are {sorted(named)} — a rule aimed at `.pipe.live` alone would not "
"reach the `<path>` that carries the `animation`, and would not reach a trunk's either")
# …and every animated thing on the page is in this block, counted rather than trusted: a third
# `transition` added to the map later has to be named here, not assumed to be covered.
animated = {".pipe.live .pipe-path", ".pipe.still .pipe-path", ".gate-switch-thumb"}
section = _code(_css_section(_css(client), "gateway pipes"))
transitioned = {" ".join(sel.split()) for sel, body in
re.findall(r"([^{}]+)\{([^}]*)\}", _code(_css_section(_css(client),
"gateway pipes")))
re.findall(r"([^{}]+)\{([^}]*)\}", section)
if "transition:" in body or "animation:" in body}
assert transitioned <= animated, (
f"{sorted(transitioned - animated)} animates in the gateway map without being stilled")
# The trunk's stub must earn that coverage rather than assume it: it exists because `buildPipe`
# makes it (one class shape for both lines) and it owns no motion declaration of its own.
js = _code(client.get("/static/page-gateway.js").text)
assert "function buildPipe(trunk = false)" in js and "'pipe pipe-trunk'" in js, \
"`.pipe-trunk` is no longer produced by the one pipe builder, so it is a second component "\
"with a class shape this block does not reach"
stub_rules = [body.strip() for sel, body in re.findall(r"([^{}]+)\{([^}]*)\}", section)
if ".pipe-trunk" in sel]
assert stub_rules, "the stylesheet lost the trunk stub's rule"
for body in stub_rules:
assert "animation" not in body and "transition" not in body, (
f"the trunk stub styles motion itself ({body!r}), which the stilling block above does "
"not name — motion belongs on `.pipe.live .pipe-path` and nowhere else")
def test_no_gateway_count_is_coloured_by_a_verdict(client) -> None:
"""The pipes and switches colour from **existence**, and the verdict vocabulary stays out.
@@ -6275,6 +6867,18 @@ def test_no_gateway_count_is_coloured_by_a_verdict(client) -> None:
section = _code(_css_section(_css(client), "gateway pipes"))
for token in ("--ok", "--warn", "--fail", ".ok", ".warn", ".fail", "severity"):
assert token not in section, f"the gateway stylesheet section paints with {token}"
# Phase 31 task 01 extended that single vocabulary to the **whole** row, and the two halves of
# this assertion are the same claim read two ways: every connector takes the existence pair, and
# nothing in this section any longer has a reason to name the structure token. `--border-strong`
# was where the spine and the tick lived while only the run went green, so its absence here *is*
# the statement "a route is green from its trunk to its endpoint, or grey for all of it".
assert "--border-strong" not in section, (
"a gateway connector reads structure ink again — the spine halves, the tick, the run and the "
"switch are one existence claim and must take `--gate-on`/`--gate-off` together")
for connector in (".gate-link.on::before", ".gate-link.on::after", ".gate-link.on .gate-elbow",
".gate-link.off::before", ".gate-link.off::after",
".gate-link.off .gate-elbow"):
assert connector in section, f"the row's state class no longer paints {connector}"
js = _code(client.get("/static/page-gateway.js").text)
for helper in ("severityFrom", "severityFor", ".severity"):
assert helper not in js, f"/gateway grades a number with {helper}"
@@ -6365,12 +6969,14 @@ def test_the_page_reports_no_card_and_no_cell_for_sockets_the_configs_do_not_nam
def test_the_page_says_where_a_line_comes_from_and_where_its_count_cannot(client) -> None:
"""Three footnotes, one per claim the page is allowed to make, and not one more.
"""Four footnotes, one per claim the page is allowed to make, and not one more.
Why the page draws a line at all (the config declares the route) and what its motion means (a
socket is open this instant, so a resting line is not a dead one); why an endpoint written as a
**name** carries no number (nothing here resolves one, so a dash is not a fault); and what the
switch does **not** do (toggling a route needs a config write path this app does not have).
**name** carries no number (nothing here resolves one, so a dash is not a fault); what the switch
does **not** do (toggling a route needs a config write path this app does not have); and — since
phase 31 task 04 — what the filter box does to the map and what it leaves alone (the tallies, the
warnings and the charts keep describing the whole ingress, because the field asks for nothing).
Each lives in the footer exactly once — the page does not repeat a why-line per panel, and it
does not need to: an uncounted line prints `—` and the footnote is the sentence that explains it
(rule 2).
@@ -6381,8 +6987,8 @@ def test_the_page_says_where_a_line_comes_from_and_where_its_count_cannot(client
"the no-DNS rule is the page's single footnote about a missing count — printed once")
assert "animates" in footer, "the animation rule lost its footnote"
band = footer[:footer.index("</footer>")]
# Three paragraphs and nothing else: one sentence per claim, in one ink band under the panels.
assert band.count("<p") == 3, f"the footer is {band.count('<p')} paragraphs, not three"
# Four paragraphs and nothing else: one sentence per claim, in one ink band under the panels.
assert band.count("<p") == 4, f"the footer is {band.count('<p')} paragraphs, not four"
assert "<span" not in band, "the footer grew a second element inside a sentence"
assert "the config says the route exists" in band, "the page stopped saying what a line means"
assert "not wired up" in band and "write" in band, \
@@ -6466,8 +7072,43 @@ def test_the_gateway_page_keeps_its_last_drawing_when_a_poll_fails(client) -> No
"and the reason has to be printed where the operator is already looking"
def test_a_clipped_pipe_label_keeps_its_full_text_on_the_element(client) -> None:
"""The ellipsis is only honest while the whole string is on the element, and pinned so.
def rendered_leaf(row: dict[str, Any]) -> dict[str, str]:
"""The two lines and the two long strings one leaf row prints, derived as a **second** reading.
There is no JS runner (a locked anchor), so this is `endpoint_sums`' idiom: the figure is
recomputed here from the payload, and the served-byte pins are what keep the mirror honest —
`inboundText` joins `out.selectors` and falls back to `out.kind`, `endpointText` is `out.host`
+ `:` + `out.port`, `counterpartText` is `ARROW` + endpoint + ` · out.kind`, and `leafTitle` /
`leafAria` compose those same two from the literals asserted verbatim below. A rename on either
side therefore fails a pin **and** changes what this mirror prints, which is the pair of
guarantees a page with no test runner can actually make.
"""
out = row["out"]
host = out["host"] or "?"
port = out["port"]
endpoint = f"{host}{'' if port is None else f':{port}'}"
kind = out["kind"]
inbound = " ".join(out["selectors"]) or kind
pair = (f"{inbound} " if inbound else "") + f"→ {endpoint}" + (f" · {kind}" if kind else "")
shared = " — this endpoint is shared with another route" if row["shared"] is True else ""
bits = [f"connection from :{row['in']['port']} to {endpoint}"]
if out["selectors"]:
bits.append("reached by " + ", ".join(out["selectors"]))
if out["name"]:
bits.append(f"server {out['name']}")
if row["shared"] is True:
bits.append("this endpoint is shared with another route")
bits.append("in the config")
bits.append("connections not attributed" if row["connections"] is None
else f"{row['connections']} live connections")
return {"line1": inbound,
"line2": f"→ {endpoint}" + (f" · {kind}" if kind else ""),
"title": pair + shared,
"aria": ", ".join(bits)}
def test_a_clipped_pipe_label_keeps_its_full_text_on_the_element(client, gateway_client) -> None:
"""The ellipsis is only honest while **both ends** are on the element, and pinned so.
Phase 29 task 06 measured 28 of 42 labels ellipsised at 1440 px and found the old fix (letting the
label wrap) worse than the clip — the flex line squeezed the name to seven characters of a
@@ -6476,17 +7117,29 @@ def test_a_clipped_pipe_label_keeps_its_full_text_on_the_element(client) -> None
endpoint labels clip at 1440 px (a 391 px target column) and **27 of 33** do at 360 px (177 px), so
what remains is a phone column-width fact (AGENTS.md gap 13) and not a lost one.
What makes the ellipsis a truncation and not a lost fact is that the row carries the whole string
— endpoint *and* the config's own selector — as its `title`, and the line's `aria-label` carries
the full endpoint whatever the eye can see. Both halves are pinned here, because the day either
one goes the ellipsis starts eating the page's answer in silence. Task 06 re-counts the clipped
labels on the new row shape.
Phase 31 task 02 made that sentence twice as important, because the row now prints two strings and
both are the answer: `brain.reeseapps.com` on line 1 and
`→ reeseapps-brain-of-reese.reeselink.com:443` on line 2. So the claim is strengthened from "the
target survives the clip" to **every inbound word and the whole `host:port` appear in full in the
row's `title` *and* in the pipe's `aria-label`**, for every route the capture declares. Three
things make that true rather than aspirational: neither text helper cuts a string (no `slice`, no
`substring`, no ellipsis character — an ellipsis is CSS's job and CSS does not touch `title`),
`leafTitle` composes `inboundText` with `endpointText`, and `leafAria` names the endpoint and every
selector. The payload half then runs that over the real rows, longest name included.
"""
css = _code(_css(client))
assert _declarations(css, ".pipe-name").get("text-overflow") == "ellipsis", \
".pipe-name no longer truncates, so re-measure the wrap decision this pin documents"
assert _declarations(css, ".gate-selector").get("text-overflow") == "ellipsis", \
"the selector line no longer truncates — the row's tooltip is what makes that honest"
"the trunk's name line no longer truncates — its `title` is what makes that honest"
# …and the leaf's counterpart line, which is now the longer of the row's two strings and so the
# one that actually clips. Same trio, same reason: a truncation is only honest while `title` and
# the `aria-label` below carry the whole thing.
end = _declarations(css, ".pipe-end")
assert end.get("text-overflow") == "ellipsis", \
".pipe-end no longer truncates — re-measure which of the row's two lines clips (gap 13)"
assert end.get("min-width") == "0" and end.get("white-space") == "nowrap", \
".pipe-end lost part of the truncation trio, so a long counterpart grows the card"
# …and the two declarations that decide *how much* it truncates. Task 06 measured the old page
# showing seven characters of a 40-character target, because a `nowrap` flex row shrinks the name
# to what the chip, the footnote and the `flex: none` count leave. `max-content` as its base size
@@ -6504,15 +7157,155 @@ def test_a_clipped_pipe_label_keeps_its_full_text_on_the_element(client) -> None
js = _code(client.get("/static/page-gateway.js").text)
row = js[js.index("function renderLeaf("):js.index("function groupElement(")]
assert "const text = endpointText(conn.out)" in row, \
"the label and the tooltip must be built from one string, not two"
assert "const inbound = inboundText(conn.out)" in row, \
"the row no longer builds both of its strings from one pair of helpers"
assert "li.title = title" in row, "a clipped connection line lost the full text on the element"
title = js[js.index("function leafTitle("):js.index("function buildPipe(")]
assert "endpointText(conn.out)" in title and "selectorText(conn.out)" in title, \
"the row's tooltip stopped carrying the endpoint and the config's own selector"
assert "inboundText(out)" in title and "endpointText(out)" in title, \
"the row's tooltip stopped carrying one of the row's two ends — half a route is no answer"
aria = js[js.index("function leafAria("):js.index("function buildPipe(")]
assert "endpointText(out)" in aria, \
"the accessible sentence stopped carrying the whole endpoint a clipped label truncates"
assert "endpointText(out)" in aria and "selectors.join" in aria, \
"the accessible sentence stopped carrying the whole endpoint or every inbound word"
# Nothing in the row's text helpers may cut a string. The CSS ellipsis is honest only because the
# data behind it is whole, and a `slice(0, 30)` in `counterpartText` would eat the tooltip too.
helpers = js[js.index("function endpointText("):js.index("function buildPipe(")]
for cutter in ("slice(", "substring(", "substr(", "trim(", "\u2026"):
assert cutter not in helpers, (
f"a leaf's text helpers cut strings with {cutter!r} — truncation belongs to CSS so the "
"`title` and the `aria-label` can carry the whole route (gap 13)")
# …and the claim over every route the captured ingress actually declares, longest name first:
# `reeseapps-brain-of-code.reeselink.com:443`, 41 characters, is this fleet's longest endpoint and
# the one the 17-row `:443` fan-out clips at a phone width.
rows = gateway_client.get("/api/gateway/snapshot").json()["connections"]
assert rows, "the captured ingress declares no routes, so this pin would prove nothing"
longest = max(rows, key=lambda r: len(f"{r['out']['host']}:{r['out']['port']}"))
longest_text = f"{longest['out']['host']}:{longest['out']['port']}"
# 42 characters, which is the figure AGENTS.md gap 13 measures the phone clip against. The name
# itself is pinned as a family rather than a string because this fleet has two 41/42-character
# neighbours (`…-brain-of-reese` and `…-brain-of-code`) and which one is longest is a fact about
# `stream.conf`, not a contract; the **length** is the thing the clip depends on.
assert len(longest_text) == 42 and longest["out"]["host"].startswith("reeseapps-brain-of-"), (
f"the fleet's longest endpoint is now {longest_text!r} ({len(longest_text)} chars) — gap 13's "
"clip measurement and gap 13's prose both have to be re-read")
for conn in rows:
printed = rendered_leaf(conn)
whole = f"{conn['out']['host']}:{conn['out']['port']}"
for surface in ("title", "aria"):
assert whole in printed[surface], (
f"{whole} is not whole in the row's {surface} — gap 13: whatever CSS clips, the "
"element has to carry the full counterpart")
for selector in conn["out"]["selectors"]:
assert selector in printed["title"] and selector in printed["aria"], (
f"the inbound word {selector!r} is missing from a surface that is supposed to survive "
"the clip — the row's answer is *which domain goes where*, so both ends are needed")
def test_the_leaf_row_leads_with_the_inbound_word(client, gateway_client) -> None:
"""Line 1 is the domain the operator types; line 2 is the counterpart it flows to.
The operator's complaint (2026-10-23): *"I can't tell which `reeseapps.com` or
`stackexpected.com` addresses flow to their reeselink counterparts (very important)."* Phase 30
drew the **target** on the primary line and demoted the inbound `server_name` / `map` key to an
11px faint qualifier, which is exactly backwards from the question the page exists to answer. So
the row re-ranked: `.pipe-name` is the config's inbound word and `.pipe-end` is
`→ host:port · kind` underneath it.
Three pins keep that from being a cosmetic swap that quietly invents something:
* `inboundText` reads `out.selectors` and falls back to `out.kind` — **never** `out.host`, because
picking the target as the "best name" is a fact the two config files never stated (rule 2);
* all the selectors are joined, so a merged connection (two vhosts claiming one
`(in_port, endpoint)`) shows both rather than the page choosing one;
* every field the two helpers index is in `GATEWAY_PAGE_FIELDS` **and** resolves on a live
`GET /api/gateway/snapshot` row, in both directions, so a rename in `sources/gateway.py` fails
this test by name instead of printing `undefined` beside a healthy ingress.
The last block is the complaint itself, asserted on the capture: the `brain.reeseapps.com` leaf of
nginx's `:443` reads that domain on line 1 and
`reeseapps-brain-of-reese.reeselink.com:443` on line 2, every haproxy leaf leads with its `backend`
name, and no row's primary line is empty, `null` or `undefined`.
"""
js = _code(client.get("/static/page-gateway.js").text)
# (1) the two text helpers, and the one field each may never read.
head = js[:js.index("function countText(")]
assert "const ARROW = '\u2192'" in head, "the destination marker is no longer a page constant"
inbound = js[js.index("function inboundText("):js.index("function counterpartText(")]
assert "(out || {}).selectors" in inbound and ".join(' ')" in inbound, \
"line 1 stopped printing every selector the config wrote"
assert "(out || {}).kind" in inbound, \
"a row with no selector has no fallback, so its primary line would be empty"
assert "host" not in inbound and "port" not in inbound, \
"line 1 reaches for the target again — the counterpart is line 2's job and nothing else"
counterpart = js[js.index("function counterpartText("):js.index("function leafAria(")]
assert "${ARROW} ${endpointText(out)}" in counterpart, \
"line 2 stopped marking the endpoint as the destination"
assert "\u00b7 ${kind}" in counterpart, \
"line 2 lost the config's own word for the route kind, so a `map` leaf and a vhost leaf "\
"reaching one address became indistinguishable"
# (2) the call sites: line 1 is the inbound word, line 2 the counterpart, and the primary line
# is never handed the endpoint as its *first* choice.
row = js[js.index("function renderLeaf("):js.index("function groupElement(")]
assert "const inbound = inboundText(conn.out)" in row
assert "const primary = inbound == null ? endpointText(conn.out) : inbound" in row, \
"a row with no selector would print an empty primary line instead of its endpoint"
assert "name.textContent = primary" in row
assert not re.search(r"name\.textContent\s*=\s*endpointText", row), \
"the endpoint is back on the primary line — that is the reading order this task replaced"
assert "setTxt(counterpart, counterpartText(conn.out))" in row, \
"line 2 is no longer the counterpart"
assert "counterpart.hidden = inbound == null" in row, \
"the hidden rule no longer keys on the fallback, so a row could print its target twice"
markup = js[js.index("function leafRow("):js.index("function renderLeaf(")]
assert "counterpart.className = 'pipe-end mono'" in markup, \
"line 2 is no longer mono, so the two hostname columns stopped aligning down a fan-out"
assert "target.appendChild(name)" in markup and "target.appendChild(counterpart)" in markup, \
"the two lines are no longer both children of the target column"
# (3) the field table resolves in both directions for what the two helpers index.
needed = ("connections.out.selectors", "connections.out.kind",
"connections.out.host", "connections.out.port")
for path in needed:
assert path in GATEWAY_PAGE_FIELDS, (
f"the leaf row indexes {path.removeprefix('connections.')} but `GATEWAY_PAGE_FIELDS` "
"does not name it, so a rename in `sources/gateway.py` would print `undefined` here")
payload = gateway_client.get("/api/gateway/snapshot").json()
rows = payload["connections"]
assert rows, "the capture routes nothing, so the field table would resolve over an empty list"
for path in needed:
found, _values = _payload_field(payload, path)
assert found, f"/gateway's row reads {path}, which the payload does not publish"
# (4) the complaint, on the capture: `brain.reeseapps.com` → its reeselink counterpart.
brain = [conn for conn in rows if conn["out"]["selectors"] == ["brain.reeseapps.com"]]
assert brain, "the captured stream `map` no longer routes brain.reeseapps.com"
printed = rendered_leaf(brain[0])
assert printed["line1"] == "brain.reeseapps.com", \
f"line 1 reads {printed['line1']!r}, not the inbound domain the operator reads for"
assert "reeseapps-brain-of-reese.reeselink.com:443" in printed["line2"], \
f"line 2 reads {printed['line2']!r} — the counterpart is what the row exists to show"
assert brain[0]["in"]["port"] == 443 and brain[0]["source"] == "nginx", \
"that leaf no longer hangs off the stream `map`'s port in the nginx panel"
haproxy = [conn for conn in rows if conn["source"] == "haproxy"]
assert haproxy, "the capture's haproxy routes are gone, so this half proves nothing"
for conn in haproxy:
assert rendered_leaf(conn)["line1"] == conn["out"]["selectors"][0], \
"a haproxy leaf no longer leads with its `backend` name"
assert any(rendered_leaf(c)["line1"] == "default" for c in rows), \
"the map's own word for unmapped SNI was paraphrased off the primary line"
for conn in rows:
line1 = rendered_leaf(conn)["line1"]
assert line1 and line1 not in ("null", "undefined", "None"), (
f"a row's primary line prints {line1!r} — every route has an inbound word, and an empty "
"primary line is the bug the fallback exists to prevent")
# (5) the trunk is untouched by the re-rank: it still leads with its port and still refuses in
# the script's own sentence when its config names no target (this fleet's `:80` `return 301`).
trunk = js[js.index("function renderTrunk("):js.index("function renderLeaves(")]
assert "name.textContent !== port" in trunk, "the trunk no longer prints its port as line 1"
assert "no target named in the config" in js, "the `:80` refusal sentence is gone"
def test_the_switch_is_built_and_explicitly_unwired(client) -> None:
@@ -6575,10 +7368,24 @@ def test_the_switch_is_built_and_explicitly_unwired(client) -> None:
for fact in ("endpointText(conn.out)", "selectors", "config", "on ? 'on' : 'off'"):
assert fact in label, f"the switch's name stopped saying {fact}"
# The events this page listens for, as an allow-list rather than a count: `toggle` is the charts
# disclosure, `DOMContentLoaded` is the boot, and the two phase-31 names belong to the filter
# field and to nothing else. **`click` is not on the list** and that is the switch's pin — the day
# a route can be toggled, some code has to dial a config write, and invariant 1 says this app has
# no such thing.
bound = set(re.findall(r"addEventListener\('(\w+)'", js))
assert bound <= {"toggle", "DOMContentLoaded"}, (
assert bound <= {"toggle", "DOMContentLoaded", "input", "keydown"}, (
f"the page now binds {sorted(bound)} — a switch that could be clicked would need a config "
"write path this app does not have (invariant 1)")
assert "click" not in bound, \
"a click handler appeared on /gateway: nothing on this page may write to the fleet"
filter_body = js[js.index("function initFilter("):js.index("function pruneCards(")]
for event in ("input", "keydown"):
assert f"addEventListener('{event}'" in filter_body, (
f"the filter no longer binds {event} in its own function, so the allow-list above is "
"hiding a listener somewhere it cannot be read")
assert js.count(f"addEventListener('{event}'") == 1, \
f"{event} is bound in more than one place on this page"
assert not re.search(r"gate-switch[^\n]*\)\s*\.?\s*addEventListener", js), \
"a listener was bound to the switch itself"