c297b9f85e
gates / gates (push) Failing after 17s
07-backup-architecture.md: three places said no offsite action unpacks the named-volume tars. R-107 closed in controller v0.218.0; all three corrected with a dated [FACT], the old sentence kept in the past tense. R-102 is NOT closed and the correction says so explicitly. New [DESIGN] paragraph in 6.3: the restore destination is resolved by the same rule as the capture destination, and the wrong-disk refusal applies to apps that have a drive to get wrong. Carries the 13/40 measurement. STATUS.md was internally contradictory - nothing waiting, and one decision waiting, for something the same page recorded as shipped. 218 -> 102 lines; the deciding section now says what happens if nothing is done. R-356 compressed into CLOSED-ITEMS.md; OPEN-ITEMS 327109 -> 325236 bytes. Drill record and 16 evidence files for the live walk on demo-hp.
79 lines
4.8 KiB
Markdown
79 lines
4.8 KiB
Markdown
# DRILL — R-356: the off-site restore for an app with no data drive (2026-08-22)
|
||
|
||
**Subject:** `demo-hp` (Tier 0, disposable), guest 9201, controller **v0.219.0**.
|
||
**Method:** endpoint-level. `claude-in-chrome` is not available on DooPlex, so every action was the
|
||
exact HTTP endpoint the UI's own form posts to — `POST /backup/offbox/run`,
|
||
`POST /backup/offbox/restore`, `POST /backup/offbox/reconstitute` — driven with the session cookie and
|
||
the session CSRF token scraped from the page. No server logic was skipped; only rendering.
|
||
|
||
## What this drill was for
|
||
|
||
Nobody had ever driven an off-site reconstitution to completion for an app whose snapshot contains
|
||
**only** the recovery unit. The R-356 refusal always fired first. So the downstream legs — placement
|
||
mapping, the stat pre-pass, `CheckPlacement`, the safety dump, the DB-service-only window, `volReplay`
|
||
— had never run in that shape. **This was a first-run measurement, not a confirmation.**
|
||
|
||
**Result: every downstream leg held.** No finding was raised against them.
|
||
|
||
## Phase 1 — the driveless class (`privatebin`, `needs_hdd: false`)
|
||
|
||
| step | what happened |
|
||
|---|---|
|
||
| plant | 2 pastes created through PrivateBin's **own JSON API** (`X-Requested-With: JSONHttpRequest`) + 4 files planted directly into the app's named volume, one with a Hungarian accented name |
|
||
| findability control | planted a control string, **found** it, removed it, **failed to find** it — `02` in the evidence dir |
|
||
| off-site | `POST /backup/offbox/run` → snapshot at 11:16:34Z, 2m20s, `status: ok`, store 44.5 → 47.0 MB |
|
||
| destroy | 11 files deleted outright (`rm -rf`, no trash) — `03-destruction.txt` names every one |
|
||
| prepare | `POST /backup/offbox/restore mode=full` → snapshot `306accff` into `/mnt/felhom-drives/hdd_1/backups/offsite-restore/privatebin` |
|
||
| **the scratch shape** | **unit only** — `.../mnt/sys_drive/felhom-data/backups/primary/privatebin/` with `volume-dumps/privatebin_privatebin_data.tar`. The whole dataset is that one tar. This is the shape that had never been driven through. |
|
||
| restore | `POST /backup/offbox/reconstitute` — **no refusal**. Volume replayed, app restarted, healthy. |
|
||
| verify | **15/15 files byte-for-byte identical**, `diff` of the two sha256 manifests is empty |
|
||
|
||
**The accented filename, as explicit hex bytes:**
|
||
`c3a17276c3ad7a74c5b172c5912d74c3bc6bc3b67266c3ba72c3b367c3a9702d723335362e747874`
|
||
(`árvíztűrő-tükörfúrógép-r356.txt`). Non-ASCII never crossed a shell chain: the planting script was
|
||
base64-encoded on DooPlex and decoded inside the guest.
|
||
|
||
**The customer-facing message, verbatim (160 bytes):**
|
||
|
||
> A(z) privatebin: 0 fájl és 1 adatkötet visszaállítva (mentés: 2026-08-22 13:14) — az alkalmazás
|
||
> újraindult. Ennek az alkalmazásnak nincs adatbázisa.
|
||
|
||
**Judged, not merely recorded.** It **names the volume** beside the file count, so it is not the R-354
|
||
shape wearing a new hat: a customer reading it is told what actually came back. There is no warning
|
||
sitting beside a success. The one honest criticism — the first number a customer reads is `0 fájl`,
|
||
and for all 40 driveless apps it will always be 0 — is a wording matter, filed as an observation and
|
||
**not acted on here**.
|
||
|
||
## Phase 2 — the drive class (`calibre-web`, `needs_hdd: true`, `HDD_PATH=/mnt/felhom-drives/hdd_1`)
|
||
|
||
The same walk, to prove the 13-class did not move. The scratch resolved under
|
||
`/mnt/felhom-drives/hdd_1/...` — the app's own drive, not the system data path — and the restore
|
||
placed there. See `11`–`14` in the evidence dir.
|
||
|
||
## Evidence
|
||
|
||
`evidence/` holds every artefact, **copied off `demo-hp` at the end of each phase, before any revert**.
|
||
Nothing was reverted or torn down during this drill, so no intermediate teardown could have taken it.
|
||
|
||
## Deliberately NOT addressed here
|
||
|
||
The message that calls an empty restore a success; the delete guard on verification copies; the
|
||
absence of any readability check on the off-site store (**R-359**). Separate rows, untouched.
|
||
|
||
### Phase 2 result
|
||
|
||
**3/3 files back byte for byte**, accented name included (`Örkény-egyperces-r356.txt`, hex
|
||
`c396726bc3a96e792d6567797065726365732d723335362e747874`). The restore placed them under
|
||
`/mnt/felhom-drives/hdd_1/userdata/media/books/` — the app's own drive.
|
||
`/mnt/sys_drive/felhom-data/userdata/media` **does not exist**, so there was no silent misplacement
|
||
onto the system disk.
|
||
|
||
Message, verbatim (161 bytes):
|
||
|
||
> A(z) calibre-web: 3 fájl és 1 adatkötet visszaállítva (mentés: 2026-08-22 13:20) — az alkalmazás
|
||
> újraindult. Ennek az alkalmazásnak nincs adatbázisa.
|
||
|
||
**No behaviour change for the 13-class was observed.** That is an absence claim, so it does not stand
|
||
on the live walk alone: the unit-test red-proof for it plants the system-data fallback into the drive
|
||
path and three tests convict it (`TestR356_ScenarioB_*`, `TestR356_ScenarioE_PlaceDriveApp*`).
|