From 53604a6127499b4b5dc93a7954e6542f6c5e2e4f Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Sat, 1 Aug 2026 22:56:26 +0200 Subject: [PATCH] docs(monitor): record phase 1 as deployed + prod verification results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 is live on cochi. The deploy exercised the rotation path on its own — monitor came up against the pre-restart latest.log, Minecraft created a new one, tailer reported rotations:1 and kept streaming — which was the single failure this design was most likely to hit. Also records the one known cosmetic gap: a delete-then-recreate rotation takes the "file was gone" branch, so the rotations counter does not tick. Streaming is unaffected. Co-Authored-By: Claude Opus 5 (1M context) --- plan/23-monitor.md | 45 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/plan/23-monitor.md b/plan/23-monitor.md index 7e0c8b9..3738ed6 100644 --- a/plan/23-monitor.md +++ b/plan/23-monitor.md @@ -247,16 +247,17 @@ tail-across-rotation. None of it is in the tiles. Once a password-gated page shows raw log lines, everything after is a small additive commit with a rolling one-container restart. -### Phase 1 — thin slice: logs only +### Phase 1 — thin slice: logs only — **DONE, live on cochi 2026-08-01** -- [ ] DNS A record for `monitor.${BASE_DOMAIN}`; add to `LE_SUBDOMAINS`; issue cert. -- [ ] `docker/monitor/` — Go service: ring buffer, tailer (inode/shrink reopen), +- [x] DNS A record for `monitor.${BASE_DOMAIN}`; add to `LE_SUBDOMAINS`; issue cert. + (DNS already resolved — the zone has a wildcard, so no record was needed.) +- [x] `docker/monitor/` — Go service: ring buffer, tailer (inode/shrink reopen), cold-start backfill, `GET /api/log?since=`, `GET /healthz`, embedded UI. -- [ ] `ui/index.html` — log pane, sticky autoscroll, filter, level chips. -- [ ] compose service (no `ports:`, `mc_data:/data:ro`). -- [ ] `caddy/conf.d/80-monitor.caddy` + `MONITOR_USER`/`MONITOR_PASSWORD_HASH`. -- [ ] nginx vhost + `MONITOR_ENABLED` gate; render + reload. -- [ ] Deploy with `--hard` (world downtime). Verify below. +- [x] `ui/index.html` — log pane, sticky autoscroll, filter, level chips. +- [x] compose service (no `ports:`, `mc_data:/data:ro`). +- [x] `caddy/conf.d/80-monitor.caddy` + `MONITOR_USER`/`MONITOR_PASSWORD_HASH`. +- [x] nginx vhost + `MONITOR_ENABLED` gate; render + reload. +- [x] Deploy with `--hard` (world downtime, 0 players online). Verified below. ### Phase 2 — tiles @@ -301,3 +302,31 @@ Then the one that actually matters, because it is the failure this design is most likely to hit: **restart the Minecraft server and confirm the stream keeps moving.** That is the rotation path, it fires on every deploy, and a broken tailer stays HTTP-200 while going silent. + +### Phase 1 results (cochi, 2026-08-01) + +The deploy itself exercised the rotation path: monitor came up while the old +`latest.log` still existed, Minecraft then created a new one, and the tailer +reported `rotations: 1` and kept streaming. Verified in prod: + +| Check | Result | +|---|---| +| `GET /` no creds / wrong creds / right creds | 401 / 401 / 200 | +| TLS | `CN=monitor.ulicraft.net`, Let's Encrypt | +| Buffer after boot | 908 lines, `tail.ok: true` | +| Stream advancing | +109 lines in 12s, `dropped: 0`, `reset: false` | +| Rotation across the MC restart | `rotations: 1`, stream uninterrupted | +| Port 8080 from the internet | connection refused | +| `docker compose port monitor 8080` | `:0` (nothing published) | +| Host listeners on :8080 | none | + +Also exercised locally before deploy, against a synthetic log: backfill capped +to buffer size, partial (unterminated) lines withheld until their newline lands, +`mv`-style rotation, in-place truncation, delete-and-recreate, ring overflow +(`dropped: 15, reset: true`), a cursor from the future, malformed `since` (400), +unknown path (404). + +**Known cosmetic gap:** a rotation done as delete-then-recreate (rather than +`mv`) does not increment the `rotations` counter — the tailer takes the +"file was gone, reopen" branch instead of the rotation branch. Streaming is +unaffected; only the displayed count is.