# Phase 2 — the new guards against each other. VERDICT: **FAIL (one real defect found)** Five of six sub-tests ran; 2.6 needs Phase 4's app and is deferred there. | # | test | verdict | one sentence | |---|---|---|---| | 2.1 | rehydrate vs capture | **FAIL — R-412** | the capture won, and rebuilt the primary **hollow**: 185 664 B → 4 382 B, `volume_dumps: None` | | 2.2 | rehydrate then mirror | **PASS (partial)** | the secondary survived byte-identical (`3e26592f…`), but the mirror run did not target this app, so R-403's guard was **not** exercised — deferred to Phase 5's 03:30 job, which is the natural test | | 2.3 | stale scratch marker | **PASS** | a planted `deadbeef / full:true / 2020` marker was fully replaced by `180c5933 / full:false / now` | | 2.4 | two restores at once | **PASS** | exactly one refusal, exactly one completion | | 2.5 | proof during other runs | **PASS, with the runbook's premise corrected** | see below | | 2.6 | legitimately-empty unit | deferred to Phase 4 | no such app exists on the box yet | ## The defect — R-412, and it is the natural instance of R-403's shape I removed `opengist`'s primary unit. The 5-minute capture rebuilt it with compose and manifest and **no volume tar**; the off-site backup then pushed that hollow unit and logged `backed up opengist (… 0 mandatory path(s))` — **a success line over a backup holding none of the app's data**. The newest off-site snapshot `35ba9fe7` is hollow. **The capture is not wrong in isolation** — R-403 deliberately refused to guard it, because a capture describing an empty tree as empty is correct. What is wrong is that **nothing between the capture and the push notices a unit that had dumps yesterday and has none today.** ## And then the thing that makes tonight worth it — R-413 The R-87 proof, rotating normally, reached `opengist` and returned **`verdict:"fail"`, `volumes_expected_none_captured: opengist_data`**, with one `offsite_proof_empty` at severity `error`. The four apps ahead of it in the rotation all passed. **Yesterday's session had to hand-build its failing case and declare it; tonight the product produced one by itself and the guard caught it.** ## 2.5 — the runbook's premise was wrong, and the behaviour is right The runbook expected the proof to skip during a Tier-2 run. **It did not skip** (`stack:privatebin`, `verdict:pass`, due-ness advanced 6→7). Established rather than assumed: `RunTier2` contains **zero** `acquireRunning` calls and **zero** references to restic — it is a purely local rsync mirror that cannot collide with the repository. The proof correctly skipped during the **off-site backup** (`skipped:true`, due-ness held at 7), which is the operation that does share the repo. ## Deliberately left in place `opengist` stays hollow-primary / complete-secondary overnight. That is **exactly** Phase 5's first injected fault, and letting the real 03:30 `tier2-backup` meet it is a better test than forcing one. Restored in Phase 7. Its live app data is untouched and healthy throughout.