R-302 docs: register rows, the two rules earned twice, STATUS
gates / gates (push) Successful in 27s
gates / gates (push) Successful in 27s
Closes R-296 (verified: shipped in v0.212.0) and R-301 (premise confirmed, fixed in v0.213.0). Files R-302 with WHY the obvious condition was rejected, and R-303 for the missing markOrphaned guard - the co-render is now harmless, not impossible. Bake evidence for golden 0.213.0.
This commit is contained in:
@@ -596,9 +596,11 @@ unrelated finding, which is why the sweep's proposals were renumbered to R-159
|
||||
**R-159 and R-160 are SHIPPED** and are not ranked; they are filed to record the class, and R-159's
|
||||
class (an image `VOLUME` at an unmounted path) is still live — `immich-server` has one today.
|
||||
| **R-295** | **One name per secret — CONTROLLER HALF SHIPPED.** The claim page called the SAME three-word dashboard code „Beállító kód" on the first-time branch and „Visszaállító kód" on the reset branch, while the TEN-word escrow code is „Helyreállítási kód". Two near-homographs for two different secrets; the collision cost a real code. „Visszaállító kód" is **retired** in the controller (`claim.html` label/subtitle/button, `claim.go` print-reset-code + lockout strings); the name is now constant and the SENTENCE changes. Naming only — pinned by `TestResetCode_StillAcceptedOnTheSetupPage`. **HUB HALF NOT DONE (Part 4a, dropped per the session's own drop order):** the hub's send button „Visszaállító kód küldése", the mail subject „Jelszó-visszaállítási kód", its body „Visszaállító kód:", and the mail sending the customer to an „Elfelejtett jelszó" page while a rebuilt box actually serves „A szerver beállítása" | **PARTIAL — controller shipped v0.211.0; hub half OPEN (S)** | R-294 | Apply the same ruling in `felhom.eu/hub`, and make the mail name the page the machine is actually showing | CC |
|
||||
| **R-296** | **The orphan card's OTHER sentence makes the same promise, and the spec says it is fine.** `SPEC-orphan-card-copy-2026-08-10.md` §1 lists `backups_remote.html:98` as *"Accurate; keep"*. It is not: it ends *„A meglévő mentések nem sérültek — a hozzájuk tartozó helyreállítási kóddal később **visszaállíthatók lehetnek**."* — the identical unevaluable promise in a different conjugation, which the spec's own regression guard (`visszaállítható lehet`, singular) does not match. Line 101 was fixed; line 98 was left **deliberately unchanged**: the instruction was not to improvise Hungarian at the customer | **READY (XS) — NEW 2026-08-10** | R-294 | Needs a wording decision, then the same treatment as line 101 and an assertion covering BOTH conjugations | operator + CC |
|
||||
| **R-296** | **The orphan card's OTHER sentence makes the same promise, and the spec says it is fine.** `SPEC-orphan-card-copy-2026-08-10.md` §1 lists `backups_remote.html:98` as *"Accurate; keep"*. It is not: it ends *„A meglévő mentések nem sérültek — a hozzájuk tartozó helyreállítási kóddal később **visszaállíthatók lehetnek**."* — the identical unevaluable promise in a different conjugation, which the spec's own regression guard (`visszaállítható lehet`, singular) does not match. Line 101 was fixed; line 98 was left **deliberately unchanged**: the instruction was not to improvise Hungarian at the customer | **CLOSED — shipped in controller v0.212.0 (R-299); verified: the sentence at backups_remote.html:98 was replaced and the stem guard covers it** | R-294 | Needs a wording decision, then the same treatment as line 101 and an assertion covering BOTH conjugations | operator + CC |
|
||||
| **R-297** | **An install took whatever golden was lying around.** Step 7 of the host installer short-circuited on any local archive with no version compare, no digest and no warning, so the manifest's sha256 — vouching from a different trust root than the code host — was consulted only on the fetch path. Discovery is newest-by-filename: correct by recency, never by verification. A box reinstalled from a stale archive can come back below the version where the off-site recovery screen exists, and below the update floor. Three goldens on `demo-hp` carry controller 0.153.0 and 0.210.0; nothing compared either to the vouched version. **FIXED in `felhom-host-install.sh` v1.26.0** (digest first, then the baked `/etc/felhom-controller-image` tag; auto-discovered mismatch re-fetches, an operator-named mismatch REFUSES; an unreadable manifest refuses). **NOT PUBLISHED and NOT YET OBSERVED FAILING** — the pre-fix stale install was never watched on `drill-r50`, so the `installer-v1.26.0` tag is deliberately not cut | **SHIPPED TO main, UNPUBLISHED (M)** | — | Observe a fresh install taking a stale local golden on `drill-r50` BEFORE publishing; then cut `installer-v1.26.0` and bump both `--ref`s in `webpage.yaml` | CC |
|
||||
| **R-298** | **The `/storage` page's unregistered list is filtered by `role==='user-data'`, so a drive that is also the backup target can never be registered from it.** `storage.html:363` routes anything not `user-data` into the read-only protected group with NO actions. On the rebuilt `demo-hp` the NVMe is deliberately BOTH the user-data drive and the `felhom-backup` target (`/etc/pve/storage.cfg`: `dir: felhom-backup` → `/mnt/nvme-1tb`), so it renders locked. **This is the SECOND reason that page was empty** during the reinstall rehearsal, independent of R-280's candidate-source defect, and R-280's fix does not touch it — attaching is non-destructive, so the format-wizard protection is the wrong gate for a REGISTER action | **READY (S) — NEW 2026-08-10** | R-280 | Split the role gate: `user-data` keeps destructive actions; any mounted role may be REGISTERED | CC |
|
||||
| **R-299** | **The orphan card's OTHER sentence made the same unevaluable promise, and the spec called it accurate.** `backups_remote.html` line 98 — the **always-visible** half of the card, where the paragraph fixed in v0.211.0 renders only after a click — ended *„a hozzájuk tartozó helyreállítási kóddal később **visszaállíthatók lehetnek**"*. It survived for two independent reasons: `SPEC-orphan-card-copy-2026-08-10.md` §1 listed it as *"Accurate; keep"*, and **the regression guard matched one INFLECTION** (`visszaállítható lehet`, singular) which the plural does not contain. **A guard matching one inflection of a Hungarian verb guards one sentence, not the claim.** Guard broadened to the stem `visszaállíthat`; proven by planting the shipped plural (stem guard convicts, old singular guard does not match it at all). Spec corrected in both places. The two accurate halves kept | **CLOSED — controller v0.212.0** | R-294 | — | CC |
|
||||
| **R-300** | **Our own uninstall left the thing that makes our own reinstall refuse.** `--uninstall` removed the dnsmasq snippet and RESTARTED the daemon, leaving it enabled and unconstrained on `0.0.0.0:53`; the next byo install's preflight then hard-refuses with *"a resolver is already bound to :53"* and **the customer goes debugging a home network that was never at fault**. Ownership is now RECORDED at preflight (`dnsmasq_preexisting`) — the only moment it is a fact, since the package is installed by the AGENT (`lanresolver.go:107`), not the installer — and honoured at removal: Felhom's → stop+disable; the owner's → restart only; **no record (every box already in the field) → restart only, fail-safe, with the reason and the exact command logged**. The preflight refusal keeps its two routes and its promise not to touch DNS on a host we do not own, and gains the missing line: when the bound resolver is dnsmasq, it says it looks like ours and names the command. **NOT OBSERVED LIVE — the install→uninstall→install cycle on `drill-r50` was not run**, so `installer-v1.27.0` is NOT cut | **SHIPPED TO main, UNPUBLISHED + UNVERIFIED LIVE (M)** | — | Run the cycle on `drill-r50` (quote the second install refusing before the fix, passing after), together with R-297's stale-golden observation — one drill session covers both; only then publish | CC |
|
||||
| **R-301** | **The abandon countdown banner makes the retired promise a third time, and as a flat statement.** `controller/internal/web/templates/layout.html:143`: *"A korábbi távoli mentéseidet N nap múlva véglegesen töröljük, a kérésed szerint. **Addig még visszaszerezheted őket a helyreállítási kóddal.**"* Unlike the orphan card this one is not hedged at all. **It is probably TRUE where it renders** — it is gated on `backupMgr.AbandonStatus().Active`, i.e. the customer chose to abandon a recovery offer that exists — which is why it was NOT changed (this session was fenced to the orphan card). **But it renders in `layout.html`, i.e. on EVERY page, and a rebuilt box can have an active abandon countdown WHILE its remote store is orphaned**, so a customer can read *"we cannot determine whether these can be opened"* on the backups page and *"until then you can still retrieve them with your recovery code"* in the banner above it, about copies they have no way to tell apart. **Not established:** whether the two sentences refer to the same bytes. The spec anticipated this in its §4 note | **READY (S) — NEW 2026-08-12** | R-299 | Establish whether the two can co-render for one customer and whether they name the same copies; if so, make the banner name WHICH copy | operator + CC |
|
||||
| **R-301** | **The abandon countdown banner makes the retired promise a third time, and as a flat statement.** `controller/internal/web/templates/layout.html:143`: *"A korábbi távoli mentéseidet N nap múlva véglegesen töröljük, a kérésed szerint. **Addig még visszaszerezheted őket a helyreállítási kóddal.**"* Unlike the orphan card this one is not hedged at all. **It is probably TRUE where it renders** — it is gated on `backupMgr.AbandonStatus().Active`, i.e. the customer chose to abandon a recovery offer that exists — which is why it was NOT changed (this session was fenced to the orphan card). **But it renders in `layout.html`, i.e. on EVERY page, and a rebuilt box can have an active abandon countdown WHILE its remote store is orphaned**, so a customer can read *"we cannot determine whether these can be opened"* on the backups page and *"until then you can still retrieve them with your recovery code"* in the banner above it, about copies they have no way to tell apart. **Not established:** whether the two sentences refer to the same bytes. The spec anticipated this in its §4 note | **CLOSED — premise CONFIRMED and fixed in controller v0.213.0 (R-302)** | R-299 | Establish whether the two can co-render for one customer and whether they name the same copies; if so, make the banner name WHICH copy | operator + CC |
|
||||
| **R-302** | **The abandon banner promised retrieval it could not see was still true — fixed by PINNING a fingerprint at the decision.** The countdown strip said *„Addig még visszaszerezheted őket a helyreállítási kóddal"* unconditionally, on every page, and R-301 established it can co-render with the orphan card correctly saying we cannot tell. **THE OBVIOUS CONDITION WAS REJECTED AND HERE IS WHY, so nobody re-proposes it:** the proxy *"does the hub hold a key different from the one I use?"* asks about the WRONG key — the set-aside copies were written under an OLDER key the box no longer has, which is why they were set aside — so on a twice-rebuilt box it answers "promise it" about copies no key on file can open. **Demonstrated, not argued:** under the proxy both Scenario B (package replaced) and Scenario D (legacy countdown) flip back to promising. Instead `startAbandonCountdown` pins `AbandonPinnedEscrowKeySHA256` — the hub's escrow key fingerprint AS CACHED AT THE DECISION — written once, never refreshed; the banner then asks only *"is the hub still holding that same package?"*. **⚠ THE PIN IS A RECORDED ASSUMPTION:** nothing on the box records which key wrote the set-aside copies, so it presumes the package held at the decision is that one — true in the ordinary rebuilt-box story, NOT provable, wrong on a twice-rebuilt box. Recorded in the field comment so it can be narrowed rather than hardening into a fact. Empty is not a match on either side; a countdown started before v0.213.0 carries no pin and takes the cautious branch (deliberately NOT backfilled). **A template sweep found a FOURTH instance** (the backups-page abandon block — same condition applied, since fixing the strip and not the page would leave them contradicting) **and a FIFTH** (the abandon confirmation screen, deliberately LEFT: it renders at the moment of the decision, where the promise is true by construction because that is the package about to be pinned) | **CLOSED — controller v0.213.0** | R-301 | — | CC |
|
||||
| **R-303** | **`markOrphaned` has no guard against an active abandon countdown — the co-render is made HARMLESS, not IMPOSSIBLE.** `ensureOffboxRepo` calls `markOrphaned()` for a claimed box (`offbox.go:804`) with no check on `AbandonAt`, so a later run finding the FRESH store unopenable re-raises the orphan card while the countdown runs. R-302 ensures the two surfaces no longer contradict each other in that state, but the state itself is still reachable and is arguably incoherent: a box counting down to deleting its old history while simultaneously reporting its NEW history is unopenable is in trouble in two ways at once and says so in two separate cards. **Ranked LOW deliberately** — it is a coherence question, not a correctness one, and the wrong fix (suppressing the orphan card during a countdown) would hide a real second fault | **READY (S) — NEW 2026-08-12** | R-302 | Decide whether a countdown should suppress, defer or annotate the orphan card — and beware hiding a genuine second failure | operator + CC |
|
||||
|
||||
Reference in New Issue
Block a user