#!/usr/bin/env python3 """keptprobe.py — R-1271 live, on a throwaway drive-folder app this run installs (never a household's unit). The measured case (catalog sweep 2026-10-24): a copy dated in the future beat the family's own copy. Here the future-dated copy is FORGED on 9202 in a scratch place every box looks at — a second-drive copy of the app's own unit under the system drive's backups/secondary//recovery-unit, its data time set to 2026-10-28T06:39:39Z (the rehearsal box's clock), the only hand-made change. Then the household's order: install, seed, „Mentés most", remove keeping data, install again → the question (expect: the OWN copy named, no future flag); the own unit moved aside for a moment → the question again (expect: the forged copy offered, marked future, with the sentence, not recommended); the own unit back → „A megőrzött adataimat használom" → the item back. Then remove with data (the forged copy goes with the app's second-drive copies). usage: SC=… SWEEP_EV=… TARGET=9202 DRIVE_ROOT=… python3 keptprobe.py """ import json, os, sys, time TOOLS = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../catalog-sweep-2026-10-24/tools") sys.path.insert(0, TOOLS) import sweep as sw # noqa: E402 w, fxm = sw.w, sw.fxm FUTURE = "2026-10-28T06:39:39Z" def ask(app, sub): os.environ.pop("KEPT", None) c, d = w.ctl("POST", f"/api/stacks/{app}/deploy", {"values": dict(w.deploy_values(app, sub, dict(w.GENERATED.get(app) or {})))}) data = (d.get("data") or {}) if isinstance(d, dict) else {} return c, {k: data.get(k) for k in ("code", "use_offered", "use_desc", "use_future", "use_warn", "use_off")} def main(app): d = os.path.join(sw.EV, "_keptprobe", app) os.makedirs(d, exist_ok=True) log = open(os.path.join(d, "walk.log"), "a") def say(*a): line = time.strftime("%H:%M:%SZ", time.gmtime()) + " " + " ".join(str(x) for x in a) print(line, flush=True) log.write(sw.scrub(line) + "\n") log.flush() w.say = say fx = fxm.FIXTURES[app] sub = getattr(fx, "sub", app) rec = {"app": app} forged = f"/mnt/sys_drive/felhom-data/backups/secondary/{app}/recovery-unit" t_start = int(time.time()) unit = "" w.login() try: rec["install"] = w.deploy(app, sub) and w.wait_app(sub, "/", tries=120, delay=5) tok = fx.seed(w, sub, say) rec["seed"] = bool(tok) sw.backup_now(rec, say) unit = sw.g(f"for p in /mnt/felhom-drives/*/backups/primary/{app} /mnt/felhom-drives/*/felhom-data/backups/primary/{app}; do [ -f $p/manifest.json ] && echo $p; done | head -1").strip() rec["own_unit"] = unit if not unit: say(" no unit of the app on its drive — stop") return sw.g(f"rm -rf /mnt/sys_drive/felhom-data/backups/secondary/{app}; mkdir -p /mnt/sys_drive/felhom-data/backups/secondary/{app} && cp -a {unit} {forged} && " f"sed -i -E 's/\"at\": \"[^\"]+\"/\"at\": \"{FUTURE}\"/' {forged}/manifest.json") rec["forged_at"] = sw.g(f"grep -o '\"at\": \"[^\"]*\"' {forged}/manifest.json | head -2").strip() say(f" forged a future-dated second-drive copy: {rec['forged_at']} (own unit: {unit})") sw.remove(app, keep=True, say=say) rec["q1_code"], rec["q1"] = ask(app, sub) say(f" [question, own copy + future copy] {rec['q1_code']} {json.dumps(rec['q1'], ensure_ascii=False)[:400]}") sw.g(f"mv {unit} {unit}.r1271-away") rec["q2_code"], rec["q2"] = ask(app, sub) say(f" [question, the future copy alone] {rec['q2_code']} {json.dumps(rec['q2'], ensure_ascii=False)[:500]}") sw.g(f"mv {unit}.r1271-away {unit}") os.environ["KEPT"] = "use" w.DEPLOYED_THIS_RUN.discard(app) rec["use_ok"] = w.deploy(app, sub, dict(w.GENERATED.get(app) or {})) os.environ.pop("KEPT", None) t0, last = time.time(), None while time.time() - t0 < 1200: time.sleep(5) c, st = w.ctl("GET", "/api/backup/restore-status") last = (st.get("data") or {}) if isinstance(st, dict) else {} if not last.get("running") and time.time() - t0 > 10: break rec["load_status"] = json.dumps(last, ensure_ascii=False)[:600] say(" load: " + rec["load_status"][:300]) w.wait_app(sub, "/", want=("200", "301", "302", "303", "307", "308", "401", "403"), tries=90, delay=5) rec["item_after_load"] = bool(tok) and bool(fx.verify(w, sub, tok, say)) say(" item after use-my-kept-data: %s" % rec["item_after_load"]) finally: os.environ.pop("KEPT", None) if unit: sw.g(f"[ -d {unit}.r1271-away ] && [ ! -e {unit} ] && mv {unit}.r1271-away {unit}") rec["controller_lines"] = sw.scrub(sw.g( f"docker logs --since {t_start} felhom-controller 2>&1 | grep -E '{app}' | grep -iE 'kept|USE MY|asking|future|restor' | cut -c1-300")) if w.stack(app).get("deployed"): sw.remove(app, keep=False, say=say) rec["after_remove"] = sw.leftovers(app, sub) rec["forged_left"] = sw.g(f"ls -d /mnt/sys_drive/felhom-data/backups/secondary/{app} 2>&1").strip() json.dump(rec, open(os.path.join(d, "record.json"), "w"), ensure_ascii=False, indent=1) if __name__ == "__main__": main(sys.argv[1])