Records the decisions rather than only the code: - POLL not ACK, decided on Scenario B against the ACTUAL promises — the no-target message gives no deadline and the card says 'within a day', so a 5-minute tick is inside both and no text needed changing. If either promise tightens to minutes, go ACK-driven. - The marker question: applied_marker lives in the guest's DataDir, which a rebuild destroys, so it cannot suppress a legitimate re-run. Left alone. - R-220 candidate (b), corroborated rather than a wider prefix, reading /proc/mounts because the lsblk args are pinned in sudoers. Live: Scenario C proven on demo-hp WITH a positive control — the job ran once and logged nothing. A first reading counted 2 lines that turned out to be the start-up reconcile, not the retry; the instrument was corrected before the conclusion. Scenarios A and E are deliberately NOT live-proven here: both need a rebuilt box, and that state arises naturally in Part 4.
5.9 KiB
REPORT — felhom-controller v0.203.0 (+ felhom-agent v0.127.0)
The two dead ends that kept the recovery journey failing are closed in code. R-218's consume half and R-220 (both halves: the host-side detection and the customer-facing refusal).
1. R-218 — which retry shape, and why (§7.1)
Poll, on a 5-minute scheduler tick, driven from the box's own published declaration
(OffboxReportStatus().State) — the very statement the hub acts on, so the two cannot disagree
about whether a retry is wanted.
Decided on Scenario B, measured against the actual promises:
| surface | what it promises |
|---|---|
| the no-target unlock message | „…amint megvannak, a mentéseid listája megjelenik…" — no deadline |
| the backups card | „…Ha egy napon belül nem áll be, jelezd az üzemeltetőnek." — within a day |
A 5-minute tick is inside both by a wide margin, and it needs no hub change (which §0 expected). No text needed changing. If either promise ever tightens to minutes, the ACK-driven shape is the one to reach for.
It stops by construction (Scenario C) and the settle gate is kept (Scenario D) — the retry goes
through ReconcileWhenSettled, unchanged.
2. The marker question (§7.2) — answered, and left alone
applied_marker lives at <DataDir>/offbox/applied_marker — inside the guest's data dir, which a
rebuild destroys. It therefore cannot suppress a legitimate post-rebuild re-run, and it is not part
of this defect. Untouched.
3. R-220's shape (§7.3) — corroboration, not a wider prefix
Candidate (b), the claimed check distinguishing our own mount from a foreign one — because the host and its knowledge survive the rebuild while the guest's registry does not. Candidate (a) (a cleanup that clears the raw mounts) would have made correctness depend on a step running, and a step that does not run leaves exactly today's defect.
The discriminator is corroborated: a non-managed mountpoint is forgiven only when the same device
is ALSO mounted under /mnt/felhom-drives — a pairing only our enrolment produces.
/proc/mounts, not lsblk MOUNTPOINTS, because the lsblk invocation is pinned verbatim in the
sudoers file and changing it would have coupled this fix to a config rollout.
The fence holds and has its own test (Scenario F): /srv/data, /media/photos,
/mnt/someone-elses-disk, /var/lib/other are all still refused. Fail-safe: an unreadable mount
table corroborates nothing.
4. Every changed Hungarian string
The deploy refusal (R-220, Scenario G). Was:
„A megadott tárhely nem azonosítható regisztrált meghajtóként, ezért alkalmazás adatkönyvtáraként nem használható. Válasszon a listából csatlakoztatott meghajtót."
Now:
„A megadott tárhely nem azonosítható regisztrált meghajtóként, ezért alkalmazás adatkönyvtáraként nem használható. Ha a gépet nemrég telepítettük újra, a meghajtóid megvannak, de még nincsenek újra csatlakoztatva ehhez a géphez — a Tárhely → Meghajtók oldalon csatlakoztathatod őket, és utána indítsd újra a telepítést. Ha ott sem látszanak, keresd a Felhom ügyfélszolgálatát."
No other customer-facing string changed. The NAS refusal is a different situation and is untouched.
5. Tests and red-proofs — every one demonstrated failing, then restored
| Scenario | Test | Red-proof mutation | Result |
|---|---|---|---|
| A | a credential staged after start-up is collected | make RetryIfDeclared return (false, nil) — the pre-v0.203.0 world |
FAILS: "the box declared a need and no reconcile was attempted" |
| C | a healthy box does nothing, and logs nothing | drop the !declared() stop condition |
FAILS: a healthy box reconciles |
| D | the settle gate holds on the retry path | call Reconcile instead of ReconcileWhenSettled |
FAILS: "SETTLE GATE BYPASSED" |
| E | the customer's own drive is offered after a rebuild | remove the felhomOwnedMounts exemption |
FAILS: "device is mounted at /mnt/adatok (sdb)" |
| F | a genuinely foreign mount is still refused | over-widen to any /mnt/* path |
FAILS: "/mnt/someone-elses-disk was offered for formatting" |
| G | an empty list explains itself | restore the old sentence | FAILS: "the refusal tells the customer to choose from a list that may be empty" |
Plus: a nil bridge is a silent no-op; the corroboration requires both mounts of the same device, and another device's managed mount does not vouch for a foreign one.
Green: controller 28 packages ok, agent 29 packages ok, both go vet clean, all gates OK
in both repos.
6. Live checks (§7.4)
Deployed to demo-hp from the published bytes (agent sha verified against the artifact before installing): agent 0.127.0, controller 0.203.0, healthy.
Scenario C — PROVEN LIVE, with a positive control. The retry job is registered
(Registered periodic job: offsite-credential-retry (every 5m0s)), ran once
(Running job: offsite-credential-retry = 1) and produced zero log lines on a box whose tier is
configured. The positive control matters: without it, silence could have meant the job never fired.
(A first reading counted 2 lines and looked like noise; they were the START-UP reconcile's settle-gate
lines, not the retry job — the instrument was corrected before the conclusion.)
Scenarios A and E are NOT live-proven yet, and deliberately so. Both need a rebuilt box: A needs
one declaring needs_credential (no target), E needs one whose registry lost its drives while the raw
mounts survived. Contriving either on a demo box means dismantling its real off-site state; the state
arises naturally in Part 4, which is where they belong and where the last re-walk measured them.
7. Not changed
No hub change. No sudoers, no allowlisted command, no PVE surface. The settle gate, the marker, every other claim signal, and the NAS refusal are untouched.