Session C: R-113/R-114/R-112 PROVEN LIVE; C5 fails on a new defect (R-116)

Full ISO/PAIRING run on a fresh nested box. Agent 0.114.0 came from the Day-0
manifest -- the SHIPPED binary -- so C5 tested the real artifact. Controller
0.186.0 hand-deployed after install per the §3.1 ruling; the vouched golden
bakes 0.185.1, so C3/C4 prove the code not the shipped golden, and that lag is
filed against R-115 rather than a new ID.

R-113 PROVEN: detach 18:43:50, gate fired 18:43:54 -- four seconds, where E-2d
measured zero over 4.5 minutes -- and SetDisconnected was reached. It fired on
exactly the shape that defeated it: raw /mnt/mentes NOT mounted while the bind
/mnt/felhom-drives/mentes still read /dev/sdb[/felhom-data].

R-114 PROVEN: with the target absent the page rendered the absent copy, the
system-disk copy 0 and the offer block 0. Both of E-2d's falsehoods are gone.

R-112 PROVEN: the banner reached a customer's page for the first time. Healthy
renders nothing, proven POSITIVELY -- idle delta 0 /backup/tiers calls, page
load delta +1, single caller, so the seam ran and chose silence.

C5 FAILED on a fourth, separate defect. The alarm fires but as the GENERIC
storage_disconnected, while the recovery is the SPECIFIC backup_target_restored
-- a pair an operator cannot match, which is what notifyDriveReturned's own
comment forbids. backup_target_absent count 0 across the run. Root cause: the
drive is TWO /disks rows and BackupTarget and GuestPath sit on different ones;
absent they separate, on return they rejoin. v0.184.1 fixed the keying, not
this. Only reachable because R-113 made the gate fire at all. Filed as R-116.

Mirror + over-correction guard PASS: non-target drive -> storage_disconnected,
backup_target_absent 0; both drives present -> 0 ABSENT lines and the target
stayed healthy. Caveat recorded: the mirror passes trivially because the target
also produced the generic event.

E-2 and E-2d CLOSED as partially proven with R-116 the one named open leg, per
the runbook's §9 rule decided in advance rather than mid-run.

Capability map NOT touched: it has no E-2 rows at all, so nothing could move to
PROVEN-LIVE. Creating them is a design act, not a validation act.

Teardown clean: pvesm status after == before (local-lvm 38.78%), guest 9201 and
drill-r50 untouched. Customer delete attempted and correctly refused while the
host still reads ONLINE; command recorded for once it ages to DOWN.
This commit is contained in:
2026-07-29 20:55:48 +02:00
parent af518ba151
commit 06d7788392
4 changed files with 321 additions and 5 deletions
+94
View File
@@ -0,0 +1,94 @@
# REPORT — Session C: R-113, R-114, R-112 proven on a real box; C5 fails on a new defect (2026-07-29)
`RUNBOOK-session-c-2026-07-29.md`. Full evidence: `documentation/audits/SESSION-C-2026-07-29.md`.
Root `REPORT.md` untouched.
## Verdicts
| Claim | Fix | Verdict |
|---|---|---|
| **C4** — offer appears and moves the target | R-112 | ✅ **PASS** |
| **C3** — absent target tells the truth, offers nothing | R-114 | ✅ **PASS** |
| **C5**`backup_target_absent` + `backup_target_restored` | R-113 | ❌ **FAIL** — generic alarm, specific recovery → **R-116** |
**All three shipped fixes work.** R-113's gate fires in **4 seconds** (E-2d measured zero over 4½
minutes). R-114's message is correct. R-112's banner reaches the customer. C5 fails on a **fourth,
separate defect that was unreachable until R-113 made the gate fire at all.**
## What the drill box ran
Agent **0.114.0 from the Day-0 manifest** — the shipped binary, so C5 tested the real artifact and
closed R-115's observation 1 for R-113. Controller **0.186.0 hand-deployed** after install (§3.1
ruling (a)); the vouched golden bakes 0.185.1, so **C3/C4 prove the code, not the shipped golden**
that lag is filed against R-115, not a new ID.
## The three headline observables
**R-113** — detach at 18:43:50, gate at **18:43:54**, on exactly the shape that defeated it before:
```
raw /mnt/mentes : NOT mounted
bind /mnt/felhom-drives/mentes : /dev/sdb[/felhom-data] <- the stale bind SURVIVED
```
**R-114** — with the target absent: absent copy 1, **system-disk copy 0**, **offer block 0**. Both of
E-2d's falsehoods gone.
**R-112** — banner element 1 and the never-configured copy in the HTML; after the wizard, the offer
with `data-path="/mnt/felhom-drives/mentes"`. Healthy renders nothing, **proven positively**: idle
delta 0 `/backup/tiers` calls, page-load delta **+1**, single caller ⇒ the seam ran and chose silence.
**Decline path proven** (registration confers no role), `restart_required:true`, agent did **not**
self-restart, in-flight check recorded before I restarted it, wrapper created the storage at the
drive's own mountpoint.
## C5's failure
```
absent : Event pushed: storage_disconnected (error) <- GENERIC
return : Event pushed: backup_target_restored (info) <- SPECIFIC
```
`backup_target_absent` count **0** across the whole run. The alarm and its recovery cannot be matched
— precisely what `notifyDriveReturned`'s own comment forbids.
**Root cause (R-116):** `driveTargetByPath` builds `out[GuestPath] = d.BackupTarget`, but the drive is
**two `/disks` rows** and the flag and the guest path sit on different ones — the `felhom-backup`
storage row carries `BackupTarget: true` and gets a guest path only while classified user-data; the
registry union row carries the guest path and **never assigns `BackupTarget`**. Absent ⇒ they separate
⇒ generic. Return ⇒ they rejoin ⇒ specific. v0.184.1 fixed the *keying*, not this.
## Mirror + over-correction guard — PASS, with a caveat
Non-target drive detached ⇒ `storage_disconnected`, `backup_target_absent` count 0. **Over-correction
guard passes**: both drives present ⇒ 0 ABSENT lines, target stayed healthy — R-113's stricter presence
did not make a healthy drive read absent. **Caveat: the mirror passes trivially**, because the target
also produced the generic event; it confirms no over-correction but cannot confirm discrimination.
## Record
- `OPEN-ITEMS.md`**R-113, R-114, R-112 → SHIPPED + PROVEN-LIVE**; **R-116 opened** (READY (S), P1);
**E-2 and E-2d CLOSED as partially proven** with R-116 as the one named open leg, per the runbook's
§9 decided-in-advance rule.
- `ROADMAP.md` — R-116 under P1.
- **Capability map NOT touched** — it still has **no E-2 / backup-target rows at all**, so no row could
be moved to PROVEN-LIVE. Creating them is a design act, not a validation act. Third session running
that this has been noted.
## Teardown
VM destroyed, storage removed, **`pvesm status` after == before** (`local-lvm` 38.78 %), guest 9201 and
`drill-r50` untouched. **Customer ruling: DELETE**; attempted and correctly refused (`host … is
ONLINE`) — deletable once the destroyed host ages to DOWN (>1 h), command recorded in `OPEN-ITEMS.md`.
## What did not happen
`backup_target_absent` never fired, so its severity, Hungarian copy and hub routing remain unexercised
— R-116 blocks them. The offer was accepted via the endpoint the button POSTs, not a browser click (no
browser automation on DooPlex); the rendered control and its non-auto-submission were verified in HTML.
The stale bind still naming a dead device node after return was observed, not investigated.
## The arc
E-2 ends here. Its stated definition of done is **R-106 + R-109, R-108 and D5** — none of which this
detour touched. The detour was worth taking: it found six real defects (R-111 through R-116), four of
them customer-affecting, none of which any unit suite had caught.
@@ -0,0 +1,220 @@
# SESSION-C-2026-07-29 — R-113, R-114, R-112 proven on a real box; C5 fails on a new defect
**Run:** `RUNBOOK-session-c-2026-07-29.md`, executed by CC on DooPlex, 2026-07-29.
**Session C of three.** A → R-113 (agent v0.114.0) · B → R-114 + R-112 (controller v0.186.0) · **C → this.**
| Claim | Fix | Verdict |
|---|---|---|
| **C4** — the offer appears and moves the target when accepted | R-112 | ✅ **PASS** |
| **C3** — with the target absent the customer is told the drive is missing, and offered nothing | R-114 | ✅ **PASS** |
| **C5** — drive loss produces `backup_target_absent` (error) and `backup_target_restored` (info) | R-113 | ❌ **FAIL** — the alarm fires, but as the **generic** event; the recovery is the **specific** one. Unmatched pair → **R-116** |
**All three fixes are proven to work.** R-113's gate fires, R-114's message is correct, R-112's banner
reaches the customer. C5 fails on a **fourth, separate defect** that only became reachable *because*
R-113 made the gate fire at all — it could not have been seen before.
---
## 1. Baselines, and what the drill box actually ran
| Artifact | Vouched / used | How it got there |
|---|---|---|
| agent | **0.114.0** | **from the Day-0 manifest**`Artifact manifest served for sess-c (agent=0.114.0 golden=0.185.1)`. C5 therefore tested the **shipped** binary, closing R-115 observation 1 for R-113 |
| golden | 0.185.1 | vouched; bakes controller 0.185.1 |
| controller | **0.186.0** | **hand-deployed after install** (§3.1 ruling (a)) via the bootstrap path — `0.185.1 → 0.186.0`, `Up 21 seconds (healthy)` |
| hub | 0.81.0 | unchanged |
| host-install | 1.22.0 | unchanged |
Repos at run time: controller `b331f18`, agent `b58d7bc`, felhom.eu `af518ba`, all clean.
**§3.1 ruling — (a), deploy 0.186.0 by hand.** A bake is its own session and would have inserted one
before any verdict; the install path is already proven by E-2d. **Caveat, as required: C3/C4 prove the
CODE, not the SHIPPED GOLDEN.** The vouched golden lagging a controller release is R-115's shape and is
filed there, not as a new ID.
**§3.2 cadence** — `driveGateLoop` registered `server.go:224`, defined `intermediary.go:328`, ticker
**30 s** (`:339`) ⇒ C5 budget 60 s. **§3.3** — SCSI hot-detach, volume survives as `unused0`.
Fence re-measured before and after: `local-lvm` **38.78 %** both times.
## 2. Timeline (VM 9301 `sessionc`, nested PVE on demo-hp)
| UTC | Event |
|---|---|
| 18:29 | VM created — one disk, q35/OVMF SB-off, `hotplug disk`, outside the `felhom` pool |
| 18:33:47 | registered unclaimed, pairing code `2XT-3PV` |
| 18:34:08 | **bound to `sess-c` by CC** — no operator STOP (E-2d retired it) |
| 18:34:57 | manifest served: **agent 0.114.0**, golden 0.185.1 |
| 18:38:03 | `controller_started (0.185.1)` — install complete, bind→controller in **3 m 55 s** |
| ~18:40 | controller **0.186.0** deployed; dashboard claimed with the emailed code |
| 18:43:50 | **target drive hot-detached** |
| **18:43:54** | **gate fired — 4 seconds** |
| 18:47:01 | reattached |
| 18:47:24 | gate RETURNED (23 s) |
| 18:50:32 | non-target drive detached (mirror) |
| 18:50:54 | gate fired (22 s) |
## 3. C4 — PASS (R-112 + the assign flow)
**The banner reached a customer's page for the first time.** E-2d could only prove the JSON.
Never-configured box, before any second drive:
```
GET /backups http=200
banner element : 1
never-configured copy : 1 <- "ugyanazon a lemezen van" IS in the HTML
absent copy : 0
offer block : 0 <- correct: no eligible drive registered yet
```
After attaching a 100 GB disk and bringing it in **through the dashboard wizard**:
```
banner element : 1 offer block : 1 data-path="/mnt/felhom-drives/mentes"
```
**Decline path — PROVEN.** After registering and *not* accepting: `target` still `local`, **no**
`felhom-backup` storage, `agent.json` `local_backup_target = local`. Registration confers no role.
**Accept:** `{"assigned":"/mnt/felhom-drives/mentes","restart_required":true}`.
**The agent did NOT self-restart**`ActiveEnterTimestamp` 20:35:15 CEST, unchanged at 20:42:20.
**In-flight check performed and recorded before restarting:** 0 `vzdump` processes, 0 backup lines in
the agent journal (5 min), 0 running PVE tasks. Wrapper created `dir: felhom-backup, path /mnt/mentes,
is_mountpoint 1` — the drive's **own** mountpoint.
**After restart, healthy renders nothing — and it is proven POSITIVELY, not by an empty page:**
```
banner element 0 · offer block 0 · degraded copy 0 · absent copy 0
/backup/tiers calls before 6 · after idle 8s 6 (delta 0) · after page load 7 (delta +1)
```
That call has exactly one caller (`resolveBackupTargetState`), so **the seam ran and chose silence**.
## 4. C3 — PASS (R-114)
With the target drive detached, the customer's page:
```
banner element : 1
ABSENT copy (correct) : 1 <- "vissza nem csatlakoztatod"
system-disk copy (BAD): 0 <- E-2d saw THIS
offer block (BAD) : 0 <- E-2d offered the VANISHED drive
```
API: `{"degraded":true,"target":"felhom-backup","message":"A rendszermentés meghajtója nem érhető el —
amíg vissza nem csatlakoztatod, a teljes rendszermentés nem készül el."}`
Both of E-2d's falsehoods are gone.
## 5. C5 — FAIL, and R-113 is nonetheless PROVEN
**R-113 works. This is the headline.** E-2d measured **zero** gate activity over 4½ minutes. Here:
```
18:43:54 [INFO] [settings] Storage path /mnt/felhom-drives/mentes disconnected=true
18:43:54 [WARN] [gate] drive ABSENT /mnt/felhom-drives/mentes — stopped+blocked 0 app(s): []
```
**4 seconds**, and `SetDisconnected` reached — the flag R-114 and the offer suppression depend on.
And it fired on **exactly the shape that defeated it before**:
```
raw /mnt/mentes : NOT mounted <- device-bound, died with the device
bind /mnt/felhom-drives/mentes : /dev/sdb[/felhom-data] <- the stale bind SURVIVED
```
The bind outlived the device, as always; the gate now sees past it.
**What fails is which event is sent.**
```
absent : Event pushed: storage_disconnected (error) <- GENERIC
return : Event pushed: backup_target_restored (info) <- SPECIFIC
```
C5 required `backup_target_absent`. It never fired — `backup_target_absent` count **0** across the run.
Worse than a missing label: the alarm and its recovery are a **mismatched pair**, which is precisely
what `notifyDriveReturned`'s own comment forbids — *"a target that alarmed as backup_target_absent has
to recover as backup_target_restored, not as a generic reconnect the operator cannot match"*. Here it
is inverted: generic alarm, specific recovery.
### Root cause, established at source
`notifyDriveAbsent` (`intermediary.go:635-646`) branches on `isTarget[path]`, built by
`driveTargetByPath` (`:602-616`) as `out[GuestPath] = d.BackupTarget` / `out[MountPath] = d.BackupTarget`.
The gate's `a.Path` is the **guest** path.
The drive is represented by **two `/disks` rows**, and the flag and the guest path sit on different ones:
| Row | Source | `BackupTarget` | `GuestPath` |
|---|---|---|---|
| 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.
*(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.)*
**Filed as R-116.** Not fixed: a defect found in a validation run is a finding.
## 6. Mirror scenario + over-correction guard — PASS, with a caveat
A **non-target** drive (`adat`, 70 GB, registered but never assigned) detached at 18:50:32:
```
18:50:54 [WARN] [gate] drive ABSENT /mnt/felhom-drives/adat — stopped+blocked 0 app(s)
18:50:54 [INFO] Event pushed: storage_disconnected (error) — Meghajtó váratlanul leválasztva: Adat meghajto
backup_target_absent count : 0 storage_disconnected count : 1
```
**Over-correction guard — the real risk of R-113 — PASSES.** With both drives present the gate produced
**0** ABSENT lines, and the target stayed `degraded:false` with banner element 0 throughout the whole
mirror sequence. R-113's stricter presence did not make a healthy drive read absent.
**Caveat, stated rather than glossed:** because the *target* drive also produced the generic event, the
mirror passes **trivially**. It confirms no over-correction; it cannot confirm specific-vs-generic
discrimination, because nothing produced the specific event on absence at all.
## 7. Findings
1. **R-116 (new)** — the absent alarm is generic while the recovery is specific; the pair cannot be
matched by an operator. Root cause §5. **This defect was unreachable before R-113**: the gate never
ran, so the branch was never taken. Fixing one bug exposed the next, which is what a validation run
is for.
2. **The stale bind survives a return, still naming a dead device node.** After the drive came back as
`/dev/sdc`, `findmnt /mnt/felhom-drives/mentes` still read `/dev/sdb[/felhom-data]` while the state
reported `degraded:false`. E-2d noticed this and did not chase it; it is now confirmed. Whether apps
writing through that path reach the live device was **not** established — worth its own look.
3. **The capability map still has no E-2 / backup-target rows at all**, so no row could be moved to
PROVEN-LIVE. Creating them is a design act, not a validation act; filed rather than invented (third
session in a row this has been noted).
## 8. Teardown
VM 9301 destroyed `--purge`, `sc-images` storage removed, scratch dir removed.
**`pvesm status` after == before** (`local-lvm` **38.78 %**, `felhom-backup` 931059224 KiB available).
**Guest 9201 and `drill-r50` untouched.**
**Customer ruling: DELETE** (R-93's lesson — no half-real fixtures). Attempted and **correctly refused**:
`delete sess-c REFUSED: host sess-c-8158e4 is ONLINE`. The VM is destroyed so no further reports come;
the host ages OK → WARN (30 m) → DOWN (>1 h) and is then deletable. Command, unchanged from E-2d:
```
POST /configs/sess-c/delete ack_hosts=1 ack_reset=1 ack_purge=1 confirm_id=sess-c expect_hosts=1
```
## 9. What did not happen
- **`backup_target_absent` never fired**, so its severity, its Hungarian customer copy and its hub
routing are all still unexercised end-to-end. R-116 blocks them.
- **The offer control was accepted via the endpoint it POSTs**, not by a browser click — no browser
automation exists on DooPlex. The rendered control, its `data-path` and its non-auto-submission were
verified in the HTML.
- The stale-bind-after-return question (finding 2) was observed, not investigated.
File diff suppressed because one or more lines are too long
+1
View File
@@ -21,6 +21,7 @@
| ID | Item | Size | Status | Notes / map rows flipped |
|----|------|------|--------|--------------------------|
| R-115 | **Publishing is a remembered step — forgotten within eight hours of being documented as forgettable** | M | idea — **WAITING-ON-OPERATOR**, 2026-07-29 | A box installs the agent from a Gitea generic package the hub explicitly vouches, never from git. Nothing in the build, deploy or session-end path publishes or checks that a version was published, so **"deployed" and "installable" are independent states that drift silently**. **Instance 1 — R-111** (morning): 17 agent releases v0.97.0v0.113.0 stranded; a new customer would have installed without the whole R-82 tiered-backup arc plus F-CRIT-2 and F-REBOOT. Found only because the E-2d Phase 0 gate happened to look. **Instance 2 — agent 0.114.0** (same afternoon): the R-113 fix, built and pushed at `b58d7bc`, deployed to felhom-pve, never published — which blocked Session C, since a fresh drill box would have installed 0.113.0 and proven the bug rather than the fix. **The finding is the RECURRENCE, not either instance** — both are fixed. R-111 named this leg in its own text (*"decide whether publishing joins the release train rather than staying a remembered step"*) and closed SHIPPED without it; it recurred the same day, which is the evidence that **a note is not a mechanism**. **Class: → R-29, one layer up** (a control that exists and is never walked) — deliberately NOT given a second ID. **Filed as its own item rather than reopening R-111** because R-111's finding (the channel *was* stale) is closed and verified end-to-end by the E-2d install, while the process defect that caused it is a distinct problem with a distinct fix and a distinct owner. **Operator's decision, mechanisms first:** (a) publish as a step in the build/release path so deployed and installable cannot diverge; (b) a gate that refuses to deploy an unpublished+unvouched version — strongest, fails closed; (c) a session-end checklist entry; (d) accept manual + a pre-Session-C verification. **(a)/(b) are mechanisms, (c)/(d) are reminders — and R-29's whole finding is that reminders do not hold.** No code written when filed, by design |
| R-116 | **The drive-absent alarm and its recovery are a mismatched pair — generic on the way out, specific on the way back** | S | idea — **PROVEN LIVE 2026-07-29** | Absent fires `storage_disconnected`; return fires `backup_target_restored`. `backup_target_absent` never fires at all (count 0 across a full Session-C run), so an operator gets an alarm they cannot match to its recovery — exactly what `notifyDriveReturned`'s own comment forbids. Root cause: `notifyDriveAbsent` (`intermediary.go:635-646`) branches on `isTarget[a.Path]` with `a.Path` the GUEST path, and `driveTargetByPath` (`:602-616`) builds it as `out[GuestPath] = d.BackupTarget` — but **the drive is TWO `/disks` rows and the flag and the guest path sit on different ones**: the `felhom-backup` storage row has `BackupTarget: true` (`felhom-agent/internal/localapi/disks.go:211`) and gets a guest path only while classified user-data, while the registry union row has the guest path and **never assigns `BackupTarget`** (`disks.go:265-267`). Absent ⇒ the flagged row loses its guest path ⇒ the union row writes `false` ⇒ generic. On return the rows rejoin ⇒ specific. v0.184.1 fixed the KEYING, not this. **Only reachable because R-113 made the gate fire at all.** Fix likely agent-side; decide the repo first. Blocks E-2's C5. Evidence: `audits/SESSION-C-2026-07-29.md` §5 |
| R-113 | **The drive-absent gate cannot fire on device loss — E-2b's alarm is wired to an unreachable condition** | M | idea — **PROVEN LIVE 2026-07-29** | `planDriveGates` (`felhom-controller/internal/web/intermediary.go:216-262`) treats a path as present by OR-ing in `d.BoundUnderParent`, which the agent derives from `GuestSeesMount()`*"is this path a mount target in the guest's `/proc/<pid>/mountinfo`"* (`internal/localapi/disks.go:210`). The raw drive mount is a **device-bound systemd unit** and dies with the device; **the agent's own bind under the shared parent is not device-bound and its mountinfo entry outlives the device**, so the gate reads it as present and `notifyDriveAbsent` is never called. Live on a fresh box: target drive hot-detached, agent said `enrolled drive absent by UUID` every 20 s for 4½ min, controller logged **0** `[gate]` lines, hub received **zero** events — neither `backup_target_absent` nor the generic `storage_disconnected`. Not a virtualisation artefact (device-bound-mount vs manual-bind is the same on metal); caveat: SCSI hot-detach, physical unplug not staged. **Sixth instance of seam-built-but-never-wired — E-2b wired the seam to a condition that cannot occur.** Evidence: `audits/E2D-fresh-vm-2026-07-29.md` §5.2 |
| R-112 | **E-2's degraded banner and offer have no UI consumer — correct endpoint, invisible to the customer** | S | idea — **PROVEN LIVE 2026-07-29** | `GET /api/storage/backup-target` returns byte-exact Hungarian copy (verified on a live box), and nothing in the product asks for it: `grep 'backup-target'` across every `*.html`/`*.js`/`*.css`**0 hits**; no template references `OfferPath`/`Degraded`/the copy; `resolveBackupTargetState` and `degradedMessageFor` are consumed **only** by the JSON handler, with **no page handler injecting the state**. Decisive contrast: the templates fetch **18 distinct `/api/storage/*` endpoints**`backup-target` and `backup-target/assign` are the only two with zero references. The handler's own comment calls itself *"the dashboard's source for the degraded banner and the offer"*. v0.185.1 shipped as *"the offer endpoints were mounted where nothing routed to them"* and fixed the **mount**, stopping one layer short of the **render**; its test pins dispatch, not reachability. **Fifth instance of the class. Fix R-114 first** — wiring this alone starts showing customers a wrong message. Evidence: `audits/E2D-fresh-vm-2026-07-29.md` §5.1 |
| R-114 | **On target-drive loss the customer is told the wrong story and offered the drive that vanished** | S | idea — **PROVEN LIVE 2026-07-29** | With the assigned target absent the endpoint returned `degraded:true, target:"felhom-backup"` **plus** the *"ugyanazon a lemezen van, mint a rendszer"* message — false, the target is a missing drive, not the system disk — **and** an `offer_path` pointing at the drive that just disappeared. `resolveBackupTargetState` falls through to the generic degraded branch whenever no disk satisfies `d.BackupTarget && d.MountPath != ""`, never distinguishing *never configured* from *configured and now missing*. Shares R-113's root cause (two disagreeing presence signals), different code path and fix. **Invisible today only because of R-112.** Evidence: `audits/E2D-fresh-vm-2026-07-29.md` §5.3 |