Files
home-network-k3s-impl/clusters/base/homepage.yaml
jakman85andClaude Opus 5 02c58aae15 fix(homepage): the C2 root hid a running service — Crafty had no tile
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 <[email protected]>
2026-09-13 16:28:21 -05:00

47 lines
2.4 KiB
YAML

---
# Flux Kustomization: Homepage landing dashboard — reconciles ./platform/homepage.
#
# POST-PLATFORM TIER (dependsOn platform-config). Homepage is a LEAF landing UI at the apex
# home.keithjackson.dev. It depends on the trusted wildcard TLS cert + the shared Gateway (incl. the
# `https-apex` listener) + split-horizon DNS — all brought up by `platform` (controllers) and
# `platform-config` (the wildcard Certificate, cilium L2 VIP, Gateway). It therefore MUST NOT live in
# the gating `platform` tier: a UI whose pod can be unhealthy would keep `platform` not-Ready, and
# while `platform` is not-Ready NOTHING downstream reconciles — the exact incident behind the
# headlamp/oauth2-proxy moves (DECISIONS-LOG: "Headlamp gating stall"). Same lesson, same fix: a leaf
# that can be legitimately unhealthy reconciles in its OWN post-platform Kustomization.
#
# NON-GATING (wait:false): nothing in the graph dependsOn homepage (apps waves gate on
# platform-config, not on this), and a dashboard pod can be long-not-Ready during a cold start.
# wait:false guarantees its health can NEVER gate anything, even if a future resource is (mistakenly)
# pointed dependsOn it.
#
# NO SOPS decryption stanza: this component carries no encrypted Secret (plain manifests + a config
# ConfigMap with no API keys), so — unlike headlamp/oauth2-proxy — clusters/dev does NOT patch it.
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: homepage
namespace: flux-system
spec:
interval: 10m
retryInterval: 2m
timeout: 5m
prune: true
wait: false
dependsOn:
- name: platform-config # wildcard TLS + Gateway (incl. https-apex listener) + split-horizon VIP first
sourceRef:
kind: GitRepository
name: flux-system
path: ./platform/homepage
# 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
name: cluster-vars