v0.151.0 — the Megosztás page stops reloading, and says how to connect

S-1: /sharing/status coerced idle->running on the PHASE channel, so the first
poll of every steady-state page load reported a terminal job that never ran and
the client's repaint-reload fired ~1.2s apart, forever. The coercion's real duty
(liveness must never be contradicted) belongs to the 'running' LEVEL field
beside it, and is now pinned by its own regression test.

S-4 core: a terminal 'running' is served exactly once, so a REAL bring-up cannot
re-arm the reload on the page it just caused. failed/needs_password/in-flight
are never consumed. Unified async-job feedback stays the ROADMAP item.

S-2/S-5: new connect card with the Windows form, the Mac form and the direct
smb://<IP>, read from the SAMBA container's netns (the controller is on a docker
bridge and would answer 172.x). Derived per render, cached nowhere - the address
is a DHCP lease. Underivable => the line is omitted.

sharing.html's <script> block is byte-identical to v0.150.0. Red-proofed three
ways. 23/23 packages green.
This commit is contained in:
2026-07-20 10:46:21 +02:00
parent 8db9232dea
commit badf17bebd
13 changed files with 663 additions and 14 deletions
+45
View File
@@ -1,5 +1,50 @@
## Changelog
### v0.151.0 — the Megosztás page stops reloading, and says how to connect (2026-07-20)
Closes **S-1**, **S-2**, **S-5** and the core of **S-4** from
`felhom.eu/documentation/audits/DIAG-sharing-2026-07-20.md`.
**S-1 — `/sharing` reload-looped about once a second, for every customer with sharing enabled.**
`GET /sharing/status` carries two things that mean different things to the client: `phase` (the
ensure JOB — the page answers a terminal `running` with a one-shot `location.reload()`, because the
„Állapot" badge is server-rendered) and `running` (the service LEVEL, straight from the liveness
probe). v0.147.0 coerced `idle``running` on the PHASE channel so that a missing job could never
contradict a live container. That duty was real, but it belongs to — and was already discharged by —
the `running` field beside it; on the phase channel the same value reads as a fresh success edge. The
poll's `tick()` runs synchronously at script end, so the FIRST poll of every steady-state page load
reported a terminal job that had never run, scheduled a reload 1.2s later, and the new page did it
again. The coercion is gone: no job, no edge. The defensive intent it was written for is now pinned
by its own named regression test on the `running` field.
**S-4 (core) — a REAL bring-up is now reported exactly once.** Without this the loop would return
after every future image update: the finished job outlives the reload it triggered, so the next page
load found `phase:"running"` waiting for it. `consumeIfRunning` serves a terminal `running` once and
clears it — and only while the single-flight slot is free, since the job goroutine sets the phase
before its deferred `release()` and eating it in that window would lose the success the customer is
waiting on. `failed` and `needs_password` stay sticky (their client path stops the timer and shows a
card with NO reload, so stickiness is informative and cannot loop), and in-flight phases are never
consumed. Accepted cost, stated rather than hidden: with two tabs open during a bring-up only the
first gets the success banner — both still show the true state, which comes from the level channel.
The unified async-job feedback layer remains the ROADMAP item; this is the minimal contract fix.
**S-2 + S-5 — the page now names both ways in.** It had only ever shown the configured NetBIOS name,
so a customer whose network fails to resolve it had no fallback but a guess — and the guess that
produced the diagnosis was the Proxmox HOST's address, which never ran smbd. New
„Csatlakozás a megosztáshoz" card: the Windows form, the Mac form, and the direct `smb://<IP>`.
The address comes from `stacks.SambaLANAddress()`, which reads the guest's netns through the SAMBA
container (`network_mode: host`) — the controller is on a docker bridge and would answer `172.x`,
the same trap `setup.DetectLocalIPs` needs `HOST_IP` for. Reading it there also makes it the right
kind of true: it is the address smbd is bound to, not merely one the box owns. **Derived per render
and cached nowhere** — the guest holds it by DHCP, so a stored copy eventually misdirects people
(S-5) — and an underivable address omits the line, because no address beats a wrong address.
`sharing.html`'s `<script>` block is byte-identical to v0.150.0: both fixes are server-side, so the
client contract is proven fixed rather than papered over. `infra.SambaHostInterface` replaces the
third `eth0` literal (smb.conf, `FELHOM_IFACE`, and now the address read must name the same nic).
Red-proofed three ways — reinstating the coercion, deleting the serve-once clear, and memoizing the
derived address each turn the corresponding test red. 23/23 packages green.
### v0.150.0 — green gate restored + the export link stops leaking the CSRF token (2026-07-20)
**F7 / R-53 — `app_export.html` built the app's public URL from the CSRF token.** The line read