From 02c58aae150d5fac4723d91f3ec2f2ffea62d9e3 Mon Sep 17 00:00:00 2001 From: Keith Jackson Date: Sun, 13 Sep 2026 16:21:44 -0500 Subject: [PATCH] =?UTF-8?q?fix(homepage):=20the=20C2=20root=20hid=20a=20ru?= =?UTF-8?q?nning=20service=20=E2=80=94=20Crafty=20had=20no=20tile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The R-C2-01 check added in the previous commit is RED on main for a real reason. platform/crafty/httproute.yaml serves crafty.${BASE_DOMAIN} on the shared Gateway, clusters/base/crafty.yaml reconciles it (dependsOn platform-config, wait:false), the web UI is Keycloak-gated by a per-pod oauth2-proxy sidecar — and nothing on the operator's front door linked to it. The service was running and the root did not admit it existed. R-C2-01: "The root `home.keithjackson.dev` MUST serve a UI that surfaces the services running in the cluster and links to them." An unsurfaced route is a requirement gap, not a missing nicety, and it is the exact failure mode nothing else in the gate notices: every cluster test stays green, the apex answers 200, and the estate is one service larger than the dashboard says. This is the SAME defect the unmerged 49c160d found on 2026-09-07 (feat/coverage-debt- paydown, ~107 commits behind main). That branch was never merged, so the gap survived — re-fixed here against today's tree, in token form (`crafty.${BASE_DOMAIN}`, not the literal hostname that branch predated). Grouped under Media because Crafty manages game servers; Platform would be equally defensible and purely cosmetic. The tile also does duty for the L4 game ports (crafty-mc.${BASE_DOMAIN}, TCP 25565-25567 / UDP 19132-19134), which have no browsable URL of their own — the check reports those as an advisory rather than requiring a link. ALSO: clusters/base/homepage.yaml's postBuild comment claimed "Homepage references no ${VARS} today; the substitution is retained for parity". That is no longer true and the claim is dangerous, because it invites someone to delete the substitution as dead weight. This component now references ${BASE_DOMAIN} in httproute.yaml's apex hostname AND in every tile href; without substitution the token is applied literally, the apex route binds a host matching no listener, every link on the root is dead, and Flux still reports Ready. Comment corrected, and the property is asserted by c2-root-surface (5) so it cannot rot back. Verified: conformance/tests/l0-static/c2-root-surface -> check OK, 49 assertions. Co-Authored-By: Claude Opus 5 --- clusters/base/homepage.yaml | 8 ++++++-- platform/homepage/configmap.yaml | 12 ++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/clusters/base/homepage.yaml b/clusters/base/homepage.yaml index 716b83d..e55e8ab 100644 --- a/clusters/base/homepage.yaml +++ b/clusters/base/homepage.yaml @@ -34,8 +34,12 @@ spec: kind: GitRepository name: flux-system path: ./platform/homepage - # Homepage references no ${VARS} today; the substitution is retained for parity with the other - # tiers / future overlay knobs. + # LOAD-BEARING, not parity decoration (the comment here used to say the opposite). This component + # references ${BASE_DOMAIN} in TWO places: httproute.yaml's apex hostname, and EVERY tile href in + # configmap.yaml. Without this substitution the token is applied LITERALLY — the apex route binds + # the host `${BASE_DOMAIN}`, which matches no Gateway listener, and every link on the operator's + # front door points at a host that does not exist — while Flux still reports this Kustomization + # Ready. It fails OPEN. Asserted by conformance/tests/l0-static/c2-root-surface (5). postBuild: substituteFrom: - kind: ConfigMap diff --git a/platform/homepage/configmap.yaml b/platform/homepage/configmap.yaml index 8819a10..809e517 100644 --- a/platform/homepage/configmap.yaml +++ b/platform/homepage/configmap.yaml @@ -81,6 +81,18 @@ data: href: https://qbittorrent.${BASE_DOMAIN} description: Download client (VPN egress) icon: mdi-download-network + # Crafty Controller — a running, north-south-exposed web UI (platform/crafty/httproute.yaml, + # reconciled by clusters/base/crafty.yaml) that this dashboard did NOT surface until + # 2026-09-13. R-C2-01 says the root MUST surface "the services running in the cluster and + # links to them", so an unsurfaced route is a requirement gap, not a styling preference — + # conformance/tests/l0-static/c2-root-surface fails on one now. Grouped under Media because + # it manages game servers; regrouping it under Platform would be purely cosmetic. The game + # ports themselves (crafty-mc.${BASE_DOMAIN}, TCP 25565-25567 / UDP 19132-19134) are an L4 + # LoadBalancer with no browsable URL, so this tile is how they are surfaced. + - Crafty: + href: https://crafty.${BASE_DOMAIN} + description: Minecraft server manager (Keycloak-gated) + icon: mdi-minecraft - Network & Infra: - Pi-hole: