v0.168.0: REPORT — live-validated backup window on 9201 (save/reschedule/restore, box left at 02:30)

This commit is contained in:
2026-07-24 20:59:15 +02:00
parent 82c67e32e1
commit e164fef70c
+69 -75
View File
@@ -1,89 +1,83 @@
# REPORT — v0.167.x: outlined logo + favicon + centered logo (completes v0.166.0 Part 4)
# REPORT — v0.168.0: Customer-configurable backup window ("Mentési időablak")
**Date:** 2026-07-24 · **Deployed & verified live on guest 9201.** This is the follow-up that finishes
the mobile-nav task — Parts 13 shipped as **v0.166.0**; Part 4 (the outlined-logo swap) was gated then
and shipped as **v0.167.0** once Viktor pushed the outlined asset.
**Date:** 2026-07-24 · **Deployed & verified live on guest 9201; box left configured at 02:30.**
> **v0.167.1 (post-acceptance tweak):** `.sidebar-logo` gained `margin: 0 auto` so the logo is
> horizontally centered in the header (was left-aligned) — one CSS line, applies to the desktop sidebar
> and the mobile drawer alike; pinned by `TestSidebarLogo_Centered` (red-proof verified). Deployed
> 0.167.1 to 9201 (Up healthy); served CSS confirms `.sidebar-logo { margin: 0 auto 0.25rem; }`. The
> outlined-logo detail below (v0.167.0) is unchanged.
## 1. Baseline
| Repo | `main` @ start | version | → |
|------|----------------|---------|---|
| felhom-controller | `e33c1ae` | v0.167.1 | **v0.168.0** (committed `82c67e3`) |
## 1. Baselines
| Repo | consumed @ hash | version |
|------|-----------------|---------|
| felhom-controller | `dbd1ff0` (post-v0.166.0) → committed `e9a365e` | v0.166.0 → **v0.167.0** |
| felhom.eu (asset source) | live `main` = **`be9edb443cab1d2581fa022537e7113f45c3fd92`** ("updated logo") | — |
Verified against live Gitea at task start (HEAD == origin == live). No agent coupling; MinAgent unchanged.
felhom.eu asset commit **consumed: `be9edb4`**`website/assets/logo.svg`, the text-outlined master.
## 2. What shipped
ONE customer setting — **"Mentési időablak kezdete"** (window start W) — drives every nightly leg at
FIXED, never-stored offsets so misordering is impossible: DB dump at **W**, tier-2 at **W+60m**, off-box
at **W+105m** (wrap-safe). The whole-guest (agent PBS/vzdump) cycle is gated to **[W+2h, W+6h)** with a
safety valve. Precedence: settings > controller.yaml `db_dump_schedule` > "02:30". Changes apply
**without restart**.
## 2. What was wrong, and what shipped
Viktor ran Inkscape **Object→Path** and pushed. The pushed file rendered the wordmark as **17 real
`<path>` glyphs** (good) but still tripped the §3a gate because Inkscape left cruft:
- **2 empty `<text …/>` shells** (self-closed, zero glyph content) wrapping empty tspans, and
- **`style="…font-family:'Vremena Grotesk'/'M+ 2c'…"` copied onto the outlined `<path>`s** (inert on a
path, but carries the font name → 7 `font-family` total).
A search for `svg:text` missed all of it — the elements are `<text>` (default namespace, no `svg:`
prefix). The correct needles are `<text` and `font-family` (what the gate checks).
## 3. Files
- **New** `internal/backupwindow/` (backupwindow.go + _test.go) — pure time math: `ParseHHMM`/`FmtHHMM`/
`LegTimes`/`GateWindow`/`EffectiveWindow`/`Valid`; offsets are constants (derived, never stored).
- `internal/scheduler/scheduler.go` (+ new _test.go) — `UpdateDaily(name,timeStr) bool`, per-daily-job
buffered `resched` chan, a `case <-job.resched` in `runDailyJob`, Schedule read under the mutex.
- `internal/settings/settings.go``BackupWindowStart` field + Get/Set.
- `internal/quiesce/quiesce.go` (+ new quiesce_window_test.go; fakes updated in quiesce_test.go /
quiesce_8b2_test.go) — `Backend.Due` now returns the backup age; `Options.WindowStartFn`/`Cadence`;
`scheduledRunAllowed` predicate + Budapest helper; gate on the scheduled path in `runOnce`.
- `internal/web/backup_handlers.go` (+ new backup_window_test.go), `handlers.go`, `server.go` route,
`templates/backups.html` — the "Mentési időablak" card + POST `/backups/window`.
- `cmd/controller/main.go` — the three Daily legs + backup-cache + initial-cache + quiesce loop wired
from the effective window.
- Docs: `CHANGELOG.md`, `CONTEXT.md`, `controller/README.md`, `REUSE.md` (UpdateDaily + backupwindow +
3rd Budapest-loader duplication note), this `REPORT.md`.
Per your decision ("strip the cruft, ship now"), CC did **node-level cleanup only — no text-to-path
conversion** (glyphs already outlined by Viktor):
- **`FelhomLogoSVG`** replaced with the outlined master; via an lxml DOM pass removed the 2 `<text>`
elements, stripped `font-*`/`-inkscape-font-specification`/`text-align`/`text-anchor` declarations from
every `style` (kept `fill`/`stroke`/`stroke-width`/gradients), and dropped the editor-only
`<sodipodi:namedview>`. **Glyph `d`-geometry and palette untouched.**
- **`FelhomFaviconSVG`** vestigial empty `<text>` nodes + their `font-family` removed (cloud icon only).
> Note: a stray `gofmt -w internal/ cmd/` reformatted ~46 unrelated (non-gofmt-clean) files; all were
> restored to `origin/main` so the commit is surgical — only the files above are in the diff.
Both constants now contain **zero `<text`, zero `font-family`, zero backticks** (safe in the Go raw
string). Served by the unchanged handlers (`serveLogoHandler`/`serveFaviconHandler` — note they serve a
hub-synced file first and fall back to the constant; on 9201 the constant is what's live).
## 4. Tests + red-proofs (all recorded)
`go build ./... && go vet ./... && go test ./...`**27 packages pass, 0 fail.** Template/design gates
(template_id / emoji / mojibake / native-confirm) all OK.
## 3. viewBox — unchanged (Scenario E requirement)
| Constant | old viewBox | new viewBox | paths | palette |
|----------|-------------|-------------|-------|---------|
| FelhomLogoSVG | `0 0 645.30703 408.36403` | **`0 0 645.30703 408.36403`** (identical) | 17 | `#ffffff` glyphs, `#008ddf` `.eu`, `#051343` artwork, 14 gradients |
| FelhomFaviconSVG | `0 0 437.307 296.36403` | **`0 0 437.307 296.36403`** (identical) | 11 | cloud icon only |
| Group | Test(s) | Red-proof (mutate → FAIL → restore) |
|-------|---------|--------------------------------------|
| A | `LegTimes` (02:30/23:30/22:00/00:00, wrap), `LegTimes_InvalidRejected`, `GateWindow` | drop the FmtHHMM modulo → `LegTimes("23:30")` yields "24:30"/"25:15" → **FAIL confirmed** |
| B | `EffectiveWindow` precedence table (settings>yaml>"02:30", corrupt falls through) | — |
| C | `UpdateDaily_MutatesAndSignals`, `_UnknownAndInvalid`, `_GoroutineConsumesReschedule` | remove `case <-job.resched` → signal stays buffered → immediacy test **FAIL confirmed** |
| D | `scheduledRunAllowed` truth table (inside/boundary/outside/valve/wrap/nil-age) + Loop integration (defer outside / run inside / valve runs / **manual TriggerNow never gated**) | invert the valve `>``<` → starving-box + no-valve cases **FAIL confirmed** |
| E | `BackupWindowSave_Valid` (settings + 3× UpdateDaily + flash), `_Invalid` (nothing stored + error flash) | skip the `Valid()` check → invalid value gets stored → **FAIL confirmed** |
## 4. Files modified · commits
- `controller/internal/web/templates.go` — both SVG constants (bodies + doc comments).
- `controller/internal/web/mobile_nav_test.go` — added `TestLogoSVG_NoLiveText` (the v0.166.0 gated
red-proof, now committed green).
- `CHANGELOG.md`, `CONTEXT.md`, `REPORT.md`.
- Commit `e9a365e` (implementation + docs) + this REPORT commit. Clean tree, HEAD == origin/main.
Existing quiesce/scheduler/web suites still pass unchanged.
## 5. Tests + RED proof
- `TestLogoSVG_NoLiveText`: asserts both constants free of `<text`/`font-family`. **RED proof recorded**
(v0.166.0 Phase 1, 2026-07-24): ran against the pre-swap constants → FAILED (`FelhomLogoSVG` and
`FelhomFaviconSVG` both contained `<text` + `font-family`). Now PASS.
- Full repo green: `go build ./... && go vet ./... && go test ./...` — 25 pkgs pass, 0 fail. All 3
mechanical gates (template_id / emoji / mojibake) OK. Cleaned SVGs validated well-formed (lxml).
- The v0.166.0 suite (mobile drawer / CSS strip-removed / no-customer-name / versioned URLs / nav
accordion invariants) still passes unchanged.
## 5. Deploy + live validation (guest 9201)
Built `felhom-controller:0.168.0` (145M) from the clean pushed tree; deployed via bootstrap →
`Up (healthy)`, `Controller elindult (0.168.0)`. Startup registered the legs at the default window:
`db-dump 02:30 · tier2-backup 03:30 · offbox-backup 04:15` (CEST). Method: endpoint-level (in-guest
curl to `172.17.0.2:8080`, `Host: felhom.demo-felhom.eu`; login 302 + scraped session CSRF).
## 6. Deploy + live validation (guest 9201)
Built `felhom-controller:0.167.0` (145M) from the clean pushed tree; deployed via the bootstrap
service → `Up (healthy)`. Endpoint-level checks (in-guest curl to `172.17.0.2:8080`):
**Save a window (POST `/backups/window`, window_start=22:00) → 303:**
- Page re-rendered: input `value="22:00"`, derived rows `22:00 / 23:00 / 23:45`, rendszermentés
`kb. 00:0004:00 között` (W+2h..W+6h, wrap-safe).
- Logs (NO restart): `db-dump rescheduled 02:30 → 22:00`, `tier2-backup 03:30 → 23:00`,
`offbox-backup 04:15 → 23:45`, `backup window set to 22:00 (legs 22:00/23:00/23:45)`.
| Surface | Assertion | Result |
|---------|-----------|--------|
| `/static/felhom-logo.svg` | 0 `<text`, 0 `font-family`, 17 `<path>`, viewBox `0 0 645.30703 408.36403` | ✅ |
| `/static/favicon.svg` | 0 `<text`, 0 `font-family`, 11 `<path>`, viewBox `0 0 437.307 296.36403` | ✅ |
| `/login` | logo URL `felhom-logo.svg?v=0.167.0` — cache-bust now carries the new version, so CF re-fetches the outlined logo (defeats the 4h edge cache) | ✅ |
**Restore (window_start=02:30) → 303:** page shows `02:30 / 03:30 / 04:15` + `kb. 04:3008:30 között`;
logs show the three legs rescheduled back. **Box left at 02:30.**
Confirms the embedded constant (not a stale hub-synced file) is what serves on 9201.
## 6. NOT live-exercised on 9201 (stated method)
- **The disk-tier window-gate DEBUG denial** could not be triggered live: the demo host agent is DOWN
for the remote-site window (its `localapi` binds `192.168.0.162`, which doesn't exist there), so the
quiesce loop's `/backup/due` call errors before the gate is reached. The gate + safety valve + the
manual-never-gated property are fully covered by Group D (truth table + Loop integration). Re-verify
the live DEBUG line once the agent is reachable again.
- Browser visual check of the "Mentési időablak" card layout is Viktor's acceptance step (the rendered
HTML strings are confirmed; the pixels are not).
## 7. Awaiting Viktor — visual acceptance
- **Android/desktop visual check of the outlined wordmark** in the sidebar, top-bar (mobile), login
page, and browser-tab favicon — the endpoint checks prove the bytes are font-free and geometrically
valid, but final "looks right" is your eyes. (Mobile browsing itself already confirmed good by you.)
## 8. Observations (out of scope — documented only)
- **Website + hub still serve their own non-outlined logo copies** (`felhom.eu` website `logo.svg`
consumers, the hub's `felhom-logo.svg`, `logo_favicon*.svg`). Propagating the outlined master there is
a separate follow-up in those repos.
- **`serveLogoHandler` prefers a hub-synced file** over the embedded constant — if a synced
`felhom-logo.svg` ever lands on a guest's disk it would override this constant; worth keeping in mind
when the outlined asset is propagated hub-side.
- `login.html`'s **stylesheet** link is still unversioned (`/static/style.css`, no `?v=`) — minor,
carried over from v0.166.0.
## 7. Observations (out of scope — documented only)
- Saving explicitly writes `backup_window_start:"02:30"` — functionally identical to the empty/default
state, so the box is correctly "at 02:30" either way.
- Cadence for the safety valve defaults to 24h **controller-side** (the agent's `/backup/due` response
carries no cadence field); if cadence policy ever becomes hub/agent-driven, thread it through instead
of the constant.
- Three Budapest-timezone loaders now exist (scheduler, web, quiesce) — noted in REUSE.md §6; kept
local to avoid a scheduler↔quiesce import edge.