v0.147.0 — feedback slice 1: pressing a button says something
The systemic complaint, twice in one evening: you press a button and nothing happens. No progress, no ETA, no named result. Three worst offenders, fixed on the two patterns already here (deploy 3-step panel, storage-init status poll). No new framework — that is a ROADMAP item; three targeted cards ship tonight. 4a — a verification restore names its result. The flash said the app had been restored "to a verification folder on the drive"; which folder, on which drive, was invisible, so the customer could not go and look at what they had just asked for. Full path now. The restore page gained a listing of existing verification copies (app, size, date, path) — nothing anywhere showed these, so they piled up and the only way to find them was SSH — each with a double-confirmed delete. That delete is the only one this release adds, so it names a STACK, never a path: the Manager resolves the name inside a backups/offsite-restore root it computed itself and refuses anything landing outside. Red-proofed — neutralise the name guard and stack:"" resolves to the offsite-restore ROOT and takes every copy with it. Refusals are asserted as non-effects. 4b — Megosztás enable shows what it is waiting for. Enabling ran ReconcileSamba synchronously inside the POST handler; on a golden without felhom-samba baked that is compose pulling ~100MB, i.e. minutes of an apparently-hung form post followed by "Beállítás mentve." whether or not anything came up. Detached + polled now, distinguishing "képfájl letöltése" from "indítás" — decided BEFORE the work starts, since afterwards the image is always present. Success is probed, not inferred (compose up -d exits 0 on a crash-loop). The password form starts the same job: with UserSet false reconcile deploys nothing, so on a fresh box that is where the pull actually happens. 4c — "Távoli mentés most" streams real progress. restic was already reporting bytes and percent; the runner seam used CombinedOutput() and discarded them. The manual run now passes --json and scans stdout line-by-line: total bytes, percent, current app. Manual only — the nightly stays silent, pinned by a test that fails if it ever passes --json. The poll now arms unconditionally, closing a race the manual trigger always ran: the redirect rendered before the goroutine wrote LastStatus=running, so the poll never armed and the page sat static during the very run just started. Red-proofed twice. Also closes the golden/controller infra-image drift at the source: infra.Images() derives from the existing pins and --print-infra-images exposes it, so the golden bake can stop carrying its own copy. That copy had already drifted — felhom-samba was never added, so the golden baked 3 of 4, which is why enabling Megosztás pulled at runtime in the first place. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Nn3VgQk9iwEGgyx6QJ2NvE
This commit is contained in:
@@ -1,5 +1,73 @@
|
||||
## Changelog
|
||||
|
||||
### v0.147.0 — feedback slice 1: pressing a button says something (2026-07-19)
|
||||
|
||||
Green: `go build ./... && go vet ./... && go test ./...` all pass (23 packages);
|
||||
`template_id_gate` + `emoji_gate` + `native_confirm_gate` + `offbox_rename_gate` +
|
||||
`app_row_dedup_gate` + `mojibake_gate` all PASS. (`docker_run_volume_path_gate` fails on
|
||||
`internal/appexport/estimate.go:179` — **pre-existing on HEAD, untouched by this release**; verified
|
||||
by stashing this work and re-running.)
|
||||
|
||||
**The systemic complaint, twice in one evening: you press a button and nothing happens.** No
|
||||
progress, no ETA, no named result. This slice fixes the three worst offenders using the two patterns
|
||||
already in the codebase (the deploy 3-step panel and the storage-init status poll). It deliberately
|
||||
does **not** introduce a feedback framework — that is a ROADMAP item ("unified async-job feedback"),
|
||||
because three targeted cards are worth shipping tonight and a framework is not.
|
||||
|
||||
- **4a — a verification restore now names its result.** The completion flash said the app had been
|
||||
restored „ellenőrző mappába a meghajtón" — *which* folder, on *which* drive, was invisible, so the
|
||||
customer could not go and look at the thing they had just asked for. It now carries the **full
|
||||
path**. The restore page gained a **„Meglévő ellenőrző másolatok"** listing (app · size · date ·
|
||||
path) — until now nothing anywhere showed what these restores had accumulated, so they piled up
|
||||
and the only way to find them was SSH — each with a double-confirmed **„Másolat törlése"**.
|
||||
- That delete is the **only** delete this release adds, so it names a STACK, never a path: the
|
||||
Manager resolves the name inside a `backups/offsite-restore` root it computed itself and refuses
|
||||
anything landing outside. Red-proofed — neutralise the name guard and `stack: ""` resolves to the
|
||||
offsite-restore ROOT and takes every copy with it. Every refusal is asserted as a **non-effect**
|
||||
(the neighbouring copy and the live data are still on disk afterwards).
|
||||
- `backups/offsite-restore` was open-coded in three places; it now has one home
|
||||
(`offsiteRestoreRootFor`), and a test pins the path in the flash to the path in the listing so
|
||||
the customer can never be told about a directory the page cannot show or remove.
|
||||
|
||||
- **4b — Megosztás enable shows what it is waiting for.** Enabling sharing ran `ReconcileSamba()`
|
||||
**synchronously inside the POST handler**. On a box whose golden had not baked `felhom-samba` that
|
||||
is `compose up -d` pulling ~100MB from a private registry: minutes of an apparently-hung form post,
|
||||
then „Beállítás mentve." whether or not anything had come up. Now detached + polled, with a card
|
||||
that distinguishes **„képfájl letöltése"** (image genuinely absent — the multi-minute case) from
|
||||
**„indítás"** (already baked — seconds). The distinction is decided *before* the work starts,
|
||||
because afterwards the image is always present and the card could never truthfully say „letöltés".
|
||||
- Success is **probed, not inferred**: `compose up -d` exits 0 on a crash-loop, so the terminal
|
||||
state is container liveness. `nil` from reconcile also covers "deliberately deployed nothing
|
||||
because there is no household password yet", which now gets its own message instead of a card
|
||||
spinning forever.
|
||||
- The **password** form starts the same job — with `UserSet` false reconcile deploys nothing, so on
|
||||
a fresh box *that*, not the enable toggle, is where the pull actually happens.
|
||||
|
||||
- **4c — „Távoli mentés most" streams real progress.** restic was already reporting bytes and
|
||||
percentages; the runner seam used `CombinedOutput()` and threw them away. The manual run now passes
|
||||
`--json`, scans stdout line-by-line, and the page shows **total bytes, percent and the app
|
||||
currently being pushed**. Before the scan finishes it says „a mentendő adatok felmérése…" rather
|
||||
than pinning a bar at 0%, which reads as stuck.
|
||||
- **Manual only.** The nightly run stays silent and its output format is untouched — pinned by a
|
||||
test that fails if the scheduled path ever passes `--json` or publishes progress.
|
||||
- The poll now **arms unconditionally**. It used to start only if the page already rendered „Fut…",
|
||||
which loses a race the manual trigger always runs: the POST redirects and the page renders before
|
||||
the detached goroutine writes `LastStatus=running`, so the poll never armed and the customer
|
||||
watched a static page during the very run they had just started.
|
||||
- Red-proofed twice, both confirmed: break the parser → the percent assertion fails; drop the
|
||||
wiring → the `--json` assertion fails. The `--json` stream is tail-bounded (40 lines) so a large
|
||||
backup does not buffer megabytes of status spam for error diagnosis.
|
||||
|
||||
- **Golden/controller infra-image drift closed at the source (supports the agent-side change).**
|
||||
`infra.Images()` derives the list from the existing pins, `--print-infra-images` prints it, and the
|
||||
golden bake now asks the controller binary it is about to bake instead of carrying its own copy.
|
||||
The copy had already drifted: `felhom-samba` was never added to it, so the golden baked 3 of 4 —
|
||||
which is *why* enabling Megosztás pulled at runtime. A test parses the const block out of the
|
||||
source and fails if a pin is added without reaching `Images()`.
|
||||
|
||||
**Live-validated** on demo guest 9201 through the real UI. **No floor change** — Viktor decides floor
|
||||
timing.
|
||||
|
||||
### v0.146.0 — nav polish: styled scrollbars + collapsible sidebar groups (2026-07-18)
|
||||
|
||||
UI-only; no behavioural or backup/restore surface touched. Green:
|
||||
|
||||
Reference in New Issue
Block a user