diff --git a/docs/progress/README.md b/docs/progress/README.md index 46aa7de..37145a9 100644 --- a/docs/progress/README.md +++ b/docs/progress/README.md @@ -203,3 +203,4 @@ Oldest first; append new entries to the bottom. | [hosted-grow-root-disk.md](hosted-grow-root-disk.md) — Grow the hosted image's root filesystem to fill the whole provider disk on boot. The image bakes a fixed **8 GiB** root (sparse raw stays small) but nothing grew it onto the far larger provider disk, so a box ran on ~8 GiB — docker image storage + the brain's SQLite store share that one volume, so a single app install can fill it and the brain's first store write 500s login (the box looks offline though it is up). **Fix:** a runtime `repart.d` definition (`Type=root`, `GrowFileSystem=yes`, no size cap) + a `malmo-grow-root.service` oneshot running `systemd-repart --dry-run=no`, ordered `Before=docker.service host-agent.service` and **fail-closed** (`Requires=` from both, via a docker drop-in and host-agent's unit) so the write-heavy services refuse to start on an un-grown root. Build-time root stays pinned at 8 GiB; the two repart definitions are deliberately separate. Lean set gains `systemd-repart` + `libfdisk1` only (no `libcryptsetup`, cryptsetup cut preserved). Boot-proof asserts the tool is present and the unit reached `active`; real full-disk growth is a provider-box acceptance step. **Known:** the stock `systemd-repart.service` also runs the same config (harmless double execution — idempotent; consolidation deferred pending a live re-test), and a pre-existing unrelated `/setup` 503 boot-proof failure reproduces on clean `main`, tracked separately | done | | [hosted-setup-boot-proof-race.md](hosted-setup-boot-proof-race.md) — Close the `/setup` 503 boot-proof failure [hosted-grow-root-disk.md](hosted-grow-root-disk.md) tracked separately, and confirm the wildcard-TLS/`:443` path is green. The `unseeded` boot polled `POST /api/v1/setup` for **403** but broke on any of `403\|503\|409\|200`, so a transient **503** — Caddy answering "no ready `/api` upstream" in the first second after the control-plane stack comes up, before the brain's listener + dashboard route land — ended the loop and failed the proof, though the box is correct (the brain returns 403 unconditionally on hosted, no 503 path; the diag showed all four containers "Up <1–2 seconds"). **Fix:** break only on a definitive `403\|409\|200` and ride through `502\|503`, exactly as the `/api/v1/me` poll above already does; a genuinely stuck `/setup` still fails after the 30s window. The louder "`:443` never binds" symptom was a **broken-build artifact, not a live regression**: the build-and-boot CI job (`CI / Cloud image`, `publish=false`) passed both the `unseeded` and `seeded` boots (`seeded` hard-asserts `:443` bound + `caddy: wildcard TLS configured`), and every known real-box root cause (`certificates.automate` #301, seed-fetch keep-alive, static resolver) is already fixed in-tree — so no product change. Adds `docs/dev/hosted-boot-proof.md` (runbook: happy-path flow, brain-log milestones, symptom→where-to-look, how to run) and de-stales `TESTING.md`'s `/setup` gate description (the as-built SSO/403, superseding the secret 401/200). Test-lane + docs only | done | | [hosted-grow-root-fs.md](hosted-grow-root-fs.md) — Corrects [hosted-grow-root-disk.md](hosted-grow-root-disk.md)'s "verified on a real provider box" claim. A live acceptance run found the root **partition** grew to the full disk (`systemd-repart` extended it, GPT `GROWFS` bit set) but the **ext4 filesystem inside it stayed at the original 8 GiB** — the disk-full/500 failure mode was not actually closed. Found via the same **Hetzner rescue mode** technique as `hosted-wildcard-cert-automate.md`: booting the (still-running) probe box into rescue and reading its disk + persistent journal directly. **Root cause:** `GrowFileSystem=yes` only sets the GPT `GROWFS` attribute bit; actually growing the mounted root filesystem is normally `systemd-growfs-root.service`'s job, which `systemd-gpt-auto-generator` wires up only when booted with `root=gpt-auto` — Hetzner (and cloud providers generally) boot with an explicit `root=PARTUUID=...` instead, so that generator, and the growfs service, never ran; zero mention of `growfs` anywhere in the boot journal. The existing boot-proof assertion couldn't have caught this: on the QEMU disk (fixed-size, no spare space) growing the filesystem is a no-op regardless of whether the growfs step runs. **Fix:** `malmo-grow-root.service`'s `ExecStart` now calls `systemd-growfs /` (the exact call the generator-driven service would have made) after `systemd-repart`, in the same command rather than a separate `ExecStartPost` — a review catch found `ExecStartPost` runs even on `systemd-repart`'s accepted 76/77 "nothing to grow" exits and has no visibility into which code fired, so it would fail the fail-closed unit on those harmless cases; the merged step only calls `growfs` when `systemd-repart` exits 0 and passes 76/77 through as success. `cloud-assertions.sh` also checks `systemd-growfs` is present in the lean image, and its pass message no longer claims real growth is verified by this lane. **Live acceptance:** re-provisioned onto a real box with the fix; root volume reported 79.99 GB total / 78.21 GB free (was 8.35 GB pre-fix) — filesystem grow confirmed on real hardware. `ENVIRONMENT.md` # Storage corrected to describe the grow as the two explicit steps it actually is | done | +| [oatmeal-home-settings-composition.md](oatmeal-home-settings-composition.md) — Restructure the signed-in **Home + Settings** surfaces onto the Oatmeal composition (**closes #290**, finishes the rollout #261 deferred). Two signature moves applied uniformly: every section title moves from the tiny uppercase-muted `

` label to the shared `components/ui/Heading.vue` **Instrument Serif** display heading (top-level titles `:level=2`; app-detail sub-sections `:level=3`; the app-detail page title drops its bespoke `

` onto ``), and every olive-50 (`bg-card`) panel/row/table container moves from the compact `rounded-xl … px-4 py-3` to the calmer `rounded-2xl … p-5` (the auth cards' radius + cloud spacing). Covers `HomeView` (System health/Household/Yours) + all Settings sections (Account, Notifications, About, Users, Outgoing email, Installed apps, installed-app **detail**) + the desktop nav panel; **Activity** — the only section with no in-page heading — gains a serif "Activity" title. Pure composition: no behavior/IA/routing change, no literal `bg-olive-*`, no raw hex. **Two documented judgement calls**: (1) the Home launcher grids are left **open** (tiles are already olive-50 cards — wrapping them in an olive-50 panel washes their contrast and fights `DASHBOARD.md`'s calm-launcher north star), and (2) the pill `