The vault was 155 pages / 31,210 lines, most of it measurement ledgers for payloads that no longer run. A throughput figure for a runtime nobody operates is not a record: AI moves faster than the vault, so the number is wrong before anyone reads it, and a wrong number in a runbook gets believed. Per the new purpose test in `AGENTS.md` → *Documentation Policy*, it is destroyed. Gone (`.AGENTTRASH/20261019-destruction/`, KILL-LIST.txt is the manifest): - the `frank-medium` endpoint and its five era pages, `frank-npu`, FastFlowLM, the ikllama/kingjones/dealign/frank-redo eras, the ling/swift15/freetoken/ubatch campaign pages, qwen3.8 spec-matrix and strix-optimizations, the two "Running Qwen3.6 …" pages; - the whole `Pipeline Parallelism/` folder (no live script passes a pipeline flag) and the multi-device/x4-pair/hybrid/offload experiment pages; - every vLLM page — no vLLM endpoint exists on this fleet; - `LLM/deployment.md` (`Architecture/Deployment Flow.md` is the test-referenced owner) and the external surveys (SGLang, Lemonade, llama.cpp forks/diff, self-hosted app census, the TTS survey) that were obsolete by construction; - `log.md`, 2,380 lines. Git holds the chronology; a causal law belongs to the page that owns the thing it governs, never to a diary. Survivors: 101 pages, 17,542 lines, 0 OKF violations, 0 unresolved links. Eras tables keep the window, payload, runtime, reason and rollback pointer; the rate columns are blanked. The live shapes stay verbatim — those numbers are what the deployer and `models.yml` consume.
7.7 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | |||||
|---|---|---|---|---|---|---|---|---|---|
| reference | Homepage Status Probes | How probe targets are chosen, the three false-down shapes, the triage procedure, and the e2e gate interactions. |
|
2026-10-05T00:00:00-07:00 |
Homepage Status Probes
The homepage is a static site —
shared/homepage/{index.html,admin.html,app.js,style.css,services.json,docs.html}
— served from /srv/homepage on dankclaw only (deploy_homepage in
scripts/deploy-remote.sh refuses other targets). A checker
(scripts/homepage-status.py, run by the homepage-status.timer unit) probes
each card's target and writes /srv/homepage/status.json (mode 0644 so
Caddy can serve it — losing the mode 403s the page).
The checker's vantage and its three false-down shapes
The checker probes TCP/HTTP from the host netns. It only has three states
— wip | up | down; there is no "unknown", so an unprobeable service can
never render honestly and must be dropped or re-pointed, not "fixed".
- TLS-only app probed with
method:"http". Plex Media Server serves TLS only on32400; plain-HTTP GET → TLS alert → curl exit 52, code000→ card says down while PMS answers200over HTTPS. Fix:"method":"tcp"(connect is the honest liveness signal; the public URL stays HTTP because Caddy re-keys). - Retired port. The Hermes card probed
127.0.0.1:8090after the compose→quadlet move moved the dashboard to9119and the webui to8787; nothing listened on 8090, so a healthy stack readdown. - Unpublished port / wrong netns.
gitea-postgres(db:5432, netsystemd-gitea),searxng-valkey(valkey:6379, netsystemd-searxng) andalloy(OTLP 12345) publish no ports. Container DNS aliases are netns-scoped, so from the host these are unreachable by construction — no probe value makes them honest. Drop those cards.
A host-vantage probe can only reach a listener published to the host (rootlessport/pasta); unpublished ports are invisible from the host netns. See Container Host Reachability for the netns rules.
Triage procedure
- Read the card's probe target in
shared/homepage/services.json; note method (tcpvshttp). - Does that port have a host-visible listener?
podman ps -a --format '{{.Names}}|{{.Status}}', then per containerpodman inspect <c> --format '{{json .NetworkSettings.Networks}} {{.HostConfig.NetworkMode}}'andpodman port <c>(empty output = published nothing → structurally unprobeable from the host). - Probe from the correct vantage: from a bridge-net container the host
is its gateway IP (
/proc/net/route, e.g.10.89.1.1ondankclaw_default) — nothost.containers.internal(169.254.1.2) which belongs to the defaultpodmannet (10.88.0.0/16). Probe with bash/dev/tcp(nopython3/ipin these images); escape loop vars so they expand insidepodman exec bash -c. - Classify: real outage (container exited — read
State.ExitCode: 137 = SIGKILL, 143 = SIGTERM/manual stop;OOMKilled=falserules out the OOM killer) vs false down (running + unreachable target). - Fix: re-point or re-method for HTTP/TLS mismatches; drop cards whose only exposure is an internal netns; never invent a probe target.
- Verify by re-running the checker path, not by eyeballing: after deploy,
re-read
/srv/homepage/status.jsonand diff thedownlist before/after.
Removing a card's probe key without a code change crashes the checker
(svc["probe"] KeyError) — dropping the whole entry is the only zero-code
fix. The description field is consumed only by app.js descHTML(), so
adding a details object (role/spec/inputs/use) is schema-safe:
tests/homepage_config.bats checks only name/category/section/probe.
Local render check (before every deploy)
The page fetches services.json + status.json at load; file:// is
CORS-blocked, so serve over HTTP:
cd shared/homepage
python3 -c "import json; s=json.load(open('services.json')); \
json.dump({'services':[{'name':x['name'],'state':'up'} for x in s]}, open('status.json','w'), indent=2)"
python3 -m http.server 8899 --bind 127.0.0.1
Then in the browser: load http://127.0.0.1:8899/index.html, wait ~1.5 s
(panels render after the async fetch; checking immediately returns 0 panels)
extract via tab.evaluate — LLM cards render .desc-role/.desc-spec/
.desc-inputs/.desc-use from the card's details object, other cards a
plain .desc; getComputedStyle(el).color confirms tones. Screenshot for
visual proof. Expected local noise: deployed.js 404s (baked in at deploy
time) — harmless.
The scratch status.json is untracked and NOT git-ignored — move it to
shared/homepage/.AGENTTRASH/ after the check (repo policy: never rm).
CSS palette lives in style.css :root (--fg bright green, --dim dim,
--head pale, --link cyan, --wip yellow, --down red). Add new tones as
--* vars and include any new .desc-* class in the html[data-bare="1"]
reset so ?bare=1 strips it to black.
Deploy
./scripts/deploy.sh dankclaw --service homepage --skip-e2e
Copies the assets to /srv/homepage, regenerates deployed.js (git commit
datetime), restarts the homepage-status timer. Verify live:
ssh dank@192.168.0.143 'grep … /srv/homepage/…'.
--skip-e2e is justified for homepage-only changes when the Mac mini is
asleep: the e2e admin crawl (tests/e2e/specs/11-admin.spec.ts:24) walks
Prowlarr at 192.168.0.112:8989 on FrankBook-Pro; an asleep mini (ARP STALE,
no remote wake) times out that test — a pre-existing environmental failure,
not a regression. All non-Mac-mini e2e tests pass.
e2e raw-IP *arr failures — probe from the browser's box, not a peer
When 11-admin fails with ERR_CONNECTION_TIMED_OUT, the instinct is "the
Mac is asleep". Sometimes true; not always. Playwright runs on the dev box,
so a healthy probe from dankclaw proves nothing about the browser's path:
# 1. From the box that RUNS the browser:
curl -s -o /dev/null -w '%{http_code}\n' --max-time 7 http://192.168.0.112:8989/
# 2. From a LAN peer:
ssh dankclaw 'for p in 8989 7878 9696; do curl -s -o /dev/null -w "$p %{http_code}\n" \
--max-time 6 http://192.168.0.112:$p/; done'
# 3. Liveness (ICMP, not TCP):
ping -c 2 -W 3 192.168.0.112
| peer probe | dev-box probe | ping | meaning |
|---|---|---|---|
| 200 | 200 | ok | transient — re-run the spec |
| timeout | timeout | fails | Mac asleep; wake, ports return in seconds |
| 200 | rc=28 | ok | path problem, not sleep — ICMP allowed, TCP blocked. Waking cannot help |
Third row: confirm the Mac is innocent through the dankclaw jump
(pgrep -fl socat; netstat -an | grep -c 8989; loopback
curl http://127.0.0.1:8989/ → 200; /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate → disabled). Forwarders up + loopback 200 ⇒ the block is
between the dev box and the Mac.
Don't hold a deploy hostage to a known-environmental red gate: verify the
deployed service directly (its own ledger/health/real completion), state
the gate was skipped or partially red and why (--skip-e2e prints the
warning, so the skip is recorded), and report the residual gap plainly
("29/30 e2e pass; 11-admin fails on Sonarr's raw IP from the dev box; peer
probe returns 200; deploy verified by other means"). Do not weaken or skip
the spec — it guards a real SSO-plus-RBAC contract.
Related
- Container Host Reachability — the netns rules behind the vantage
- Observability Provisioning — the monitoring stack reading the same fleet
- Deploy State Triage — service-scoped deploys and the e2e gate
- Testing Policy — the seam/e2e contract this page's checks live in