# CAMPAIGN-6B — UNATTENDED close-out of the C6 remainder (.fab upload circle · browser planes · backup tiers · regression) **Class:** Unattended "no mercy" continuation of CAMPAIGN-6. Findings only — NO code fixes, NO spec-writing however obvious. Output: `felhom.eu/documentation/audits/CAMPAIGN-6B-.md` (C3/4/5/6A structure). Continue the ledger + evidence at `180:~/campaign6/`. Record a new launch seed. No fixed time budget — the run ends when the checklist is complete. ## THE OPERATING MODE — read this first (it is the whole point) **This run is UNATTENDED. Viktor is NOT at the keyboard. Do NOT BLOCK-and-wait.** - **All reboots — guest AND host, both boxes — are PRE-AUTHORIZED. Drive them yourself** (`pct reboot 9201`, host `systemctl reboot`). This is a dev/test environment; there is no evidence-banking delay and no per-reboot approval. The CAMPAIGN-6A supervised run already proved the reboot plane is safe; 6B does not re-ask. - **`exportfs` toggles on the campaign share are pre-authorized** (same safety line: campaign `felhom-campaign6` export ONLY; never non-felhom exports; never stop DooPlex services). - **`teszt_enroll` drive destructive ops are pre-authorized.** Demo's ~20 existing apps: start/stop/ backup only — never delete/wipe/redeploy-over. Campaign apps + drill: free chaos. Escrow ceremonies: drill only; every R scratch + uncommitted. - **DEFERRAL IS STILL BANNED, but so is BLOCKING.** Do not stop to ask permission. **HALT ONLY IF a genuine, unrecoverable decision is required** (e.g. a truly ambiguous destructive choice with no safe default, or missing credentials) — and even then, prefer the safe default and ledger it. Running low on context is NOT a halt reason: instead, wrap what is done into the doc, write a `CAMPAIGN-6C` continuation prompt, and stop cleanly (the 6A pattern). Every checklist item ends as PASS / FAIL / FINDING / (operator-authorized) split-to-6C — never blank, never "deferred". - If a reboot/host action does not come back, use the CAMPAIGN-6A morning-recovery steps and ledger it as a FAIL with the diagnostic, then continue (continue-on-failure). ## Pre-existing state (left ready by CAMPAIGN-6A — verify at P0, don't trust this) - controller **0.129.0** both guests · agent **0.88.0** both hosts · hub **0.54.0**. caps 63/63 both. - **campaign6 NFS share still enrolled** on demo (`192.168.0.180:/mnt/5_hdd/felhom-campaign6` → `/mnt/felhom-drives/campaign6`, idle); **sonarr deployed on it (stopped)**; DooPlex export active. - Credentials **unchanged from CAMPAIGN-4/5/6A**: controller AND hub dashboard = the campaign credential. **Never commit it; ledger says "campaign credential"; rotate only at the very end.** - P7 samplers (`c5demo`/`c5drill`, `c4-sampler.sh`) still running on both PVE hosts — reuse them. - Access: `SSH=/c/Windows/System32/OpenSSH/ssh.exe`. 180=DooPlex (passwordless sudo), felhom-pve=demo host, root@192.168.0.152=drill host. Controllers driven via `docker exec curl 127.0.0.1:8080` (real login→CSRF) or claude-in-chrome for the browser planes. ## Findings already banked in 6A (do NOT re-hunt; watch for related regressions) - **C6-1 (LOW-MED):** `skip-active` is a no-op on `pct reboot` — the guest-hook heal re-arm carries every active-share reboot; the "fresh namespaces inherit real mounts" log is misleading. - **C6-2 (MED):** a NAS outage spanning a guest reboot can strand the share `failed` until an agent restart (or periodic sweep — timing unmeasured; **6B: measure the periodic-sweep interval** if a cheap opportunity arises). - **C6-3 (LOW, setup):** the agent/wizard don't pre-create an app's userdata tree on a fresh `all_squash` NFS export → docker chown fails → container stuck `Created` until pre-created. - **F-A / F-B / F-C are already confirmed-fixed-live** (CAMPAIGN-5, same 0.129.0 fleet). 6B may spot-re-confirm opportunistically but need not re-prove them. ## P0 (fast) — verify the pre-existing state, record a seed, then GO Versions both; caps 63/63; campaign6 enrolled+health; sonarr present; escrow states; samplers alive. Push to `180:~/campaign6/evidence/P0-6B/`. ## PHASE 2 — the `.fab` full circle, UPLOAD half (demo; twice-deferred flagship) Fresh **campaign** app + **~4 GiB** `/dev/urandom` (varied sizes incl one >1 GiB); sha256 manifest. Export → `.fab` (progress honesty + atomicity). Download twice — browser/LAN AND `curl` with the session cookie **through the real Cloudflare edge** (`--resolve :443:` — Pi-hole split-horizon bypasses the edge otherwise); both hashes == the docker-cp reference. Re-prove the edge cap: single >100 MB POST → **413 from Cloudflare**. Delete the campaign app + data. Upload back — browser/LAN AND `curl --resolve` through the edge in 64 MiB chunks. Import/restore; **byte-compare every file vs the manifest → zero mismatches = PASS.** Edge volley (live over the unit tests): cancel mid-upload → abort + `.part` gone; controller restart mid-upload → startup GC count logged; offset replay → 409+resync; oversize-vs-free → Hungarian refusal (both numbers) **AND F-A real multi-GB size**; collision → " (1)" then " (2)"; second concurrent init → 409; wrong extension refused; idle 15-min abort (park one, return). (Note the storage-bearing box + a proper export are required — see C6-3; pre-create the userdata tree.) ## PHASE 3 — browser planes (claude-in-chrome; twice-deferred) Session must be started AFTER the chrome bridge connected. Campaign credential for login. - **3A escrow wizard, full browser pass (drill):** preflight all-green + Hungarian details (no raw English leak), warnings, re-auth, run, reveal, **typed-back with the two highlighted words** (read from screen), manual hide/show toggle, finish → auto-confirm flips + hub row hash matches (server-side check via 180). Then re-claim → 410 UI; unclaimed → TTL → `unclaimed_void` screen; **F-C live** (`phase:none` claim → clean 4xx UI, not 502); out-of-band CLI ceremony w/o staged secret → stale card fires → wizard clears it. - **3B DOM / native-alert / session sweep (both boxes):** grep served DOM for `alert(`/`confirm(` (must be zero); session expiry mid-wizard and mid-upload → JSON 401 on `/api/`, redirect on pages; CSRF stale-token on storage-wizard/escrow/upload POSTs → 403 JSON; zero-toggle honesty + inline two-step confirms; **F-B live** quick re-check. - **3C hub 8-tab customer-detail ring (hub credential = campaign credential):** hash-nav across all 8 tabs; auto-refresh scoped to live tabs; **dirty-form suppression** (start editing → refresh holds); events tab under volume; no stale-host deletion against real hosts (synthetic row only). ## PHASE 4-rest — backup tiers depth + NAS integrity - **F7 mid-backup NAS cut:** `POST /api/backup/run` on a NAS app; `exportfs -u` at T+~6s; the last-good volume dump must survive (tmp+rename) — no 0-byte artifact; `success:false` is the only signal. (Give the app enough data that the dump takes >6 s.) - Four backup sub-pages truth vs live; offsite card three honest states; Tier-3 "Távoli mentés most" additive + quota bar; **restic stale-lock self-heal** (kill controller mid-offsite-run → next run self-heals the lock); tier-1 replace-semantics; offsite restore-to-verify to a scratch target (campaign app) — byte-identical; volume-only app gets its tier-2 secondary (F6 fix); per-app toggles round-trip; snapshot coherence across pages. (F8 already CONFIRMED in 6A — cite it.) ## PHASE 5 — regression spot-checks (fast) - Agent-restart re-arm still logs per-share verdicts (6A re-showed it via 1E `netmigrate` — one quick re-confirm). **F1/F2 residue** after the campaign share's final removal — zero mounts/units/ dirs, host+guest. **F4** `mapped_uid:101000` → friendly Hungarian 400 (not `agent_error`). Dead-app alert + email on a killed campaign container (cooldown math vs the run's emails). ## Wrap — completeness gate (same as 6A) Checklist table of EVERY 6B item = PASS / FAIL / FINDING / (operator-authorized) split-to-6C. Verdict; ranked findings + repros; timings; deviations; box state (both boxes; "campaign credential active — Viktor rotates"; drill fresh-R note); morning recovery; evidence index. Commit the doc + overwrite `felhom.eu/REPORT.md`. **No credential, no R, no blob committed.** ## Final cleanup (unattended — do it, no BLOCK; show before/after in the ledger) Remove campaign6 share + campaign apps (product flow); `sudo exportfs -u 192.168.0.162:/mnt/5_hdd/felhom-campaign6 && sudo rm -rf /mnt/5_hdd/felhom-campaign6` on 180 (confirm `exportfs -v` back to the P0 baseline, felhom-data intact); remove scratch `.fab` + injected data; stop the samplers (`pkill -f c4-sampler.sh` both PVE hosts, `pkill -f hub-sampler.sh` on 180). Leave the campaign credential in place and note in the doc that **Viktor rotates it** — that is the one human step that remains after 6B.