Correct the Session C audit: the union row is DEDUPED AWAY, not written false

The audit said the union row "writes false" for the guest-path key. That is
wrong, and the next reader would have inherited the error.

Isolated during R-116's Phase 0: RoleForStorage returns RoleSystem whenever
backingDevice == "" (felhom-agent internal/storage/role.go:180-181). When the
device vanishes the target row's role flips to system and it loses its guest
path, but KEEPS its MountPath -- and the union loop skips any drive whose
MountPath is already seen, so the registry row is never emitted at all.

/disks therefore carries NO row with that guest path: isTarget[guestPath] is a
MISSING KEY, not a false value. The practical difference is decisive -- the
obvious fix (set BackupTarget on the union row) could not have worked, because
that row does not exist in the state where the alarm is needed.

The section's own "not isolated" caveat is replaced by the isolated answer.
This commit is contained in:
2026-07-29 23:51:17 +02:00
parent 952ebf4862
commit e87d6b26bb
+16 -7
View File
@@ -153,14 +153,23 @@ The drive is represented by **two `/disks` rows**, and the flag and the guest pa
| the `felhom-backup` storage | Observe path, `felhom-agent/internal/localapi/disks.go:211` (`t.Name == primaryTargetID`) | **true** | set only when role is user-data |
| the registry drive | union path, `disks.go:265-267`**never assigns `BackupTarget` at all** | **false** | `/mnt/felhom-drives/mentes` |
While the device is absent the target-flagged row loses the classification that gives it a guest path,
so `out["/mnt/felhom-drives/mentes"]` is written **false** by the union row and the specific branch is
skipped. On **return** the rows rejoin and the specific event fires — which is exactly the asymmetry
observed. v0.184.1 fixed the *keying* (both keys are mapped); it did not fix the flag being absent from
the row that carries the guest path.
> **CORRECTION 2026-07-29 (R-116 Phase 0).** This section originally said the union row *"writes
> `false`"*. **That is wrong**, and the real mechanism is worse — the union row is not written at all.
>
> The step left un-isolated above has now been isolated: `RoleForStorage` returns `RoleSystem` whenever
> `backingDevice == ""` (`felhom-agent/internal/storage/role.go:180-181`). So when the device vanishes,
> Observe's `exactMountDevice` fails, `t.BackingDevice` becomes `""`, the row's role flips to system and
> it loses its guest path — **but it keeps its `MountPath`**. The union loop skips any drive whose
> `MountPath` is already `seen` (`disks.go:263`), so the registry row is **DEDUPED AWAY ENTIRELY**.
>
> `/disks` therefore carries **no row with that guest path at all**: `isTarget[guestPath]` is a
> **missing key**, not a `false` value. The practical difference is decisive — the obvious fix (set
> `BackupTarget` on the union row) **could not have worked**, because that row is not emitted in the
> state where the alarm is needed.
*(The precise role-classification step that drops the guest path while absent was not isolated — the
two-row split and the observed absent/return asymmetry are the evidence.)*
On **return** the rows rejoin and the specific event fires — which is exactly the asymmetry observed.
v0.184.1 fixed the *keying* (both keys are mapped); it did not fix the flag being absent from the row
that carries the guest path.
**Filed as R-116.** Not fixed: a defect found in a validation run is a finding.