diff --git a/documentation/audits/r1292-qb-normal-slot-2026-10-26/tester-1-live-run1-instrument-failed.txt b/documentation/audits/r1292-qb-normal-slot-2026-10-26/tester-1-live-run1-instrument-failed.txt
new file mode 100644
index 00000000..3ec58a15
--- /dev/null
+++ b/documentation/audits/r1292-qb-normal-slot-2026-10-26/tester-1-live-run1-instrument-failed.txt
@@ -0,0 +1,17 @@
+rc=0
+ [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'QBT_ADMIN_PASSWORD']
+ [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+ [1] deployed, controller state=running, pinned={'qbittorrent': 'qbittorrentofficial/qbittorrent-nox:5.2.4-1'}
+1. qBittorrent installed: True
+ before: {'error': 'unreadable'}
+2. alternative speed ON, alternative limit 500 KiB/s (the household's): ok ok
+ now: {'error': 'unreadable'}
+ [3. first tick] rule lines: 2026/10/26 12:18:53 [INFO] [upwatch] qBittorrent upload limit set to 5892096 B/s (50 % of the tested line, 94.3 Mbit/s) | record: (none)
+ after the first tick: {'error': 'unreadable'}
+4. the household switches back to normal speed: ok {'error': 'unreadable'}
+ after the next tick: {'error': 'unreadable'} | record: | lines: (none at INFO)
+VERDICT: FAIL
+ [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'qbittorrent', 'volumes_removed': ['qbittorrent_qbittorrent_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-driv
+5. leftovers: {'containers': '', 'volumes': '', 'appyaml': '', 'appdata': '', 'kept': '', 'subdomain': '404'}
+
+[exited with code 0]
diff --git a/documentation/audits/r1292-qb-normal-slot-2026-10-26/tester-1-live.txt b/documentation/audits/r1292-qb-normal-slot-2026-10-26/tester-1-live.txt
new file mode 100644
index 00000000..6fcbad48
--- /dev/null
+++ b/documentation/audits/r1292-qb-normal-slot-2026-10-26/tester-1-live.txt
@@ -0,0 +1,14 @@
+ [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'QBT_ADMIN_PASSWORD']
+ [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
+ [1] deployed, controller state=running, pinned={'qbittorrent': 'qbittorrentofficial/qbittorrent-nox:5.2.4-1'}
+1. qBittorrent installed: True
+ before: {'up_limit': 0, 'alt_up_limit': 10240, 'mode_alt': False}
+2. alternative speed ON, alternative limit 500 KiB/s (the household's): ok ok
+ now: {'up_limit': 0, 'alt_up_limit': 512000, 'mode_alt': True}
+ [3. first tick] rule lines: 2026/10/26 12:53:06 [INFO] [upwatch] qBittorrent upload limit set to 5892096 B/s (50 % of the tested line, 94.3 Mbit/s) | record: {'box_set_bytes': 5892096, 'line_mbps': 94.28828951955792, 'set_at': '2026-10-26T12:53:06Z'}
+ after the first tick: {'up_limit': 5892096, 'alt_up_limit': 512000, 'mode_alt': True}
+4. the household switches back to normal speed: ok {'up_limit': 5892096, 'alt_up_limit': 512000, 'mode_alt': False}
+ after the next tick: {'up_limit': 5892096, 'alt_up_limit': 512000, 'mode_alt': False} | record: {'box_set_bytes': 5892096, 'line_mbps': 94.28828951955792, 'set_at': '2026-10-26T12:53:06Z'} | lines: (none at INFO)
+VERDICT: PASS
+ [7] stop 200, remove with data -> 200 {'ok': True, 'data': {'removed': 'qbittorrent', 'volumes_removed': ['qbittorrent_qbittorrent_config'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'userdata_kept': ['/mnt/felhom-drives/adatlem
+5. leftovers: {'containers': '', 'volumes': '', 'appyaml': '', 'appdata': '', 'kept': '', 'subdomain': '404'}
diff --git a/documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/ep0-install-v1.4.0.txt b/documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/ep0-install-v1.4.0.txt
new file mode 100644
index 00000000..0d92591c
--- /dev/null
+++ b/documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/ep0-install-v1.4.0.txt
@@ -0,0 +1,11 @@
+2026-10-26T13:09:21Z
+syntax-ok
+-rwxr-xr-x 1 root root 17964 Oct 26 13:09 /usr/local/bin/felhom-tenantsync
+-rwxr-xr-x 1 root root 8253 Jul 10 18:57 /usr/local/bin/felhom-tenantsync.bak-1.0.0
+-rwxr-xr-x 1 root root 10480 Jul 17 11:12 /usr/local/bin/felhom-tenantsync.bak-1.1.0
+-rwxr-xr-x 1 root root 12004 Jul 17 19:15 /usr/local/bin/felhom-tenantsync.bak-1.2.0
+-rwxr-xr-x 1 root root 15542 Oct 19 14:07 /usr/local/bin/felhom-tenantsync.v1.3.0
+751b3c26f3e4c872
+# felhom-tenantsync v1.4.0 — the offsi
+{"status":"ok","fp":"c6:07:28:3f"}
+{"status":"ok","unpruned_checked":true,"unpruned":[]}
diff --git a/documentation/audits/release-monday-2026-10-26/tools/r1292_live.py b/documentation/audits/release-monday-2026-10-26/tools/r1292_live.py
new file mode 100644
index 00000000..6675da36
--- /dev/null
+++ b/documentation/audits/release-monday-2026-10-26/tools/r1292_live.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python3
+"""r1292_live.py — R-1292 live on a box with a TESTED line (Tester 1; 9202 has none, so the rule never acts there):
+a THROWAWAY qBittorrent; the household's „alternative speed" switched ON with an alternative limit of 500 KiB/s; then
+the controller's 50 % rule (its 15-minute tick) must set the NORMAL limit (`up_limit`) and leave the alternative alone;
+then the household switches back to normal speed, and the next tick must NOT read that as „the household changed it".
+qBittorrent's own API from inside its container (the admin password rides an env var, never printed). Removed through
+the product at the end (data and backups).
+
+usage: SC=
SWEEP_EV= TARGET=tester-1 DRIVE_ROOT= python3 r1292_live.py"""
+import json, os, sys, time
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../catalog-sweep-2026-10-24/tools"))
+import sweep as sw # noqa: E402
+
+w = sw.w
+APP = "qbittorrent"
+
+
+def qb(path, data=None):
+ """One qBittorrent API call inside its container, through /root/qbtool.sh in the guest (the password via env QP)."""
+ pw = (w.GENERATED.get(APP) or {}).get("QBT_ADMIN_PASSWORD", "")
+ arg = " '" + data + "'" if data else ""
+ return sw.g(f"QP='{pw}' sh /root/qbtool.sh {path}{arg}").strip()
+
+
+def record():
+ """The 50 % rule's record (settings.json upwatch.qb_limit), parsed — never a grep on a JSON file."""
+ raw = sw.g("docker exec felhom-controller cat /opt/docker/felhom-controller/data/settings.json")
+ try:
+ return (json.loads(raw).get("upwatch") or {}).get("qb_limit")
+ except ValueError:
+ return "unreadable"
+
+
+def prefs():
+ try:
+ p = json.loads(qb("app/preferences"))
+ return {"up_limit": p.get("up_limit"), "alt_up_limit": p.get("alt_up_limit"), "mode_alt": qb("transfer/speedLimitsMode") == "1"}
+ except ValueError:
+ return {"error": "unreadable"}
+
+
+def rule_lines(since):
+ return sw.g(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'qBittorrent (upload )?limit' | cut -c1-200").strip()
+
+
+def wait_tick(since, say, label, cap=1100):
+ for _ in range(cap // 20):
+ time.sleep(20)
+ out = sw.g(f"docker logs --since {since} felhom-controller 2>&1 | grep -E 'upwatch' | grep -vE 'DEBUG' | tail -1")
+ # the 15-minute tick also logs the hold seeder; any upwatch line after `since` with a qBittorrent verdict counts
+ ln = rule_lines(since)
+ if ln:
+ break
+ st = record()
+ say(f" [{label}] rule lines: {rule_lines(since) or '(none at INFO)'} | record: {st or '(none)'}")
+ return st
+
+
+def main():
+ say = print
+ w.say = say
+ w.login()
+ t0 = int(time.time())
+ try:
+ ok = w.deploy(APP, "torrent") and w.wait_app("torrent", "/", tries=90, delay=5)
+ say("1. qBittorrent installed:", ok)
+ before = prefs()
+ say(" before:", before)
+ if "error" in before:
+ raise SystemExit("INSTRUMENT: qBittorrent's preferences are unreadable — no verdict (fix the probe first)")
+ say("2. alternative speed ON, alternative limit 500 KiB/s (the household's):",
+ qb("app/setPreferences", "json=" + json.dumps({"alt_up_limit": 512000})) or "ok",
+ qb("transfer/toggleSpeedLimitsMode", "x=1") or "ok")
+ say(" now:", prefs())
+ rec1 = wait_tick(t0, say, "3. first tick")
+ p1 = prefs()
+ say(" after the first tick:", p1)
+ say("4. the household switches back to normal speed:", qb("transfer/toggleSpeedLimitsMode", "x=1") or "ok", prefs())
+ t1 = int(time.time())
+ time.sleep(960) # one full 15-minute tick; a "kept" decision logs nothing, a "household" one logs at INFO
+ rec2 = record()
+ say(" after the next tick:", prefs(), "| record:", rec2, "| lines:", rule_lines(t1) or "(none at INFO)")
+ verdict = ("PASS" if p1.get("up_limit", 0) and abs(p1["up_limit"] - 94.3 * 0.5 * 1e6 / 8) < 2048 and p1.get("alt_up_limit") == 512000
+ and isinstance(rec2, dict) and not rec2.get("household") else "FAIL")
+ say("VERDICT:", verdict)
+ finally:
+ sw.remove(APP, keep=False, say=say)
+ say("5. leftovers:", sw.leftovers(APP, "torrent"))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/hub/CHANGELOG.md b/hub/CHANGELOG.md
index b4674d5b..fa6a4100 100644
--- a/hub/CHANGELOG.md
+++ b/hub/CHANGELOG.md
@@ -1,4 +1,4 @@
-## v0.172.0 (unreleased, 2026-10-26) — a fresh install's whole-guest off-site set-up never fails silently (R-1295)
+## v0.172.0 (2026-10-26) — a fresh install's whole-guest off-site set-up never fails silently (R-1295) — RELEASED 2026-10-26 13:08 UTC on the operator's yes (image sha256:7c8d129a…, from `232f42d2`, CI 2366; rc.1 ran the live proof)
- **Cause (measured, `documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/`):** PBS's proxy caches permissions for up to
5 s and an ACL-only change does not clear the cache; under concurrent requests ep0's self-check of a new token is
diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md
index aa2f4b83..845ba5f9 100644
--- a/scripts/CHANGELOG.md
+++ b/scripts/CHANGELOG.md
@@ -1,10 +1,10 @@
-## 2026-10-26 — felhom-tenantsync v1.4.0: the self-check waits out the PBS permission cache (R-1295) — committed, NOT installed on ep0
+## 2026-10-26 — felhom-tenantsync v1.4.0: the self-check waits out the PBS permission cache (R-1295) — INSTALLED on ep0 2026-10-26 13:09Z on the operator's yes (sha256 `751b3c26…` = the repository's; v1.3.0 kept as `.v1.3.0`; `fingerprint` and `usage` ok)
- **`felhom-tenantsync.sh` v1.4.0:** the new token is re-checked every 0.5 s for up to 15 s (a log line per try) before
the old regenerate-once-and-rollback; the transient admin token waits the same way before its first namespace list
(under load it met the same cache and a wrong `namespace create` died). Test `test_tenantsync_selfcheck.py` (19 checks;
v1.3.0 fails 11). Live on a throwaway PBS 4.2.5 under load, the hub's exact order, 30 pairs: v1.3.0 failed 11, v1.4.0
- failed 0 (`documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/`). **Installing it on ep0 is the operator's yes.**
+ failed 0 (`documentation/audits/r1295-pbsdr-selfcheck-2026-10-26/`, `ep0-install-v1.4.0.txt`).
## 2026-10-25 — installer 1.36.1: the preflight words a refusal again — PUBLISHED 2026-10-25 evening on the operator's yes (`installer-v1.36.1` → `79ee3e33`, served sha256 `e18cdd17…`; the three refusal sentences seen live)