#!/usr/bin/env python3 """R-640 live on 9202 (v0.267.0): a CUT-OFF database copy in docmost's local unit must be refused by the household's own restore button, BEFORE anything is touched. The copy is cut to half its size (the exact shape measured on 2026-09-23 morning: a copy that ends inside a COPY block, no completion marker). Positive observables: the restore's own answer carries the „csonka" sentence; docmost's containers keep their start times (nothing was stopped); seed A still reads back. Negative control: the whole copy is put back byte for byte and the same button then restores (so the refusal is about the cut, not about the button).""" import json, sys, time sys.path.insert(0, ".") import walk as w from chaos import load, sub_of, SIX w.login() s = load() out = {} find = w.guest("ls -la /mnt/sys_drive/felhom-data/backups/primary/docmost/db-dumps/ 2>&1; " "find / -xdev -path '*backups/primary/docmost*' -name 'docmost-postgres.sql' 2>/dev/null | head -3") w.say("the unit's dump:\n" + find) paths = [l for l in find.splitlines() if l.endswith("docmost-postgres.sql") and l.startswith("/")] or \ ["/mnt/sys_drive/felhom-data/backups/primary/docmost/db-dumps/docmost-postgres.sql"] if not paths: sys.exit("no docmost dump found in a local unit") dump = paths[0] out["dump"] = dump starts0 = w.guest("docker ps --filter label=com.docker.compose.project=docmost --format '{{.Names}} {{.RunningFor}}'; " "for c in docmost docmost-postgres; do docker inspect -f '{{.Name}} {{.State.StartedAt}}' $c; done") w.say("before:\n" + starts0) cut = w.guest(f"""set -e cp -p {dump} /root/r640-whole.sql n=$(stat -c %s {dump}); head -c $((n/2)) /root/r640-whole.sql > {dump} echo "whole=$n cut=$(stat -c %s {dump})"; tail -c 200 {dump} | tail -2; echo; grep -c 'dump complete' {dump} || true""") w.say("cut:\n" + cut) out["cut"] = cut res = w.restore("docmost") code, st = w.ctl("GET", "/api/backup/restore-status") w.say(f"restore-status after the refused restore: {json.dumps(st, ensure_ascii=False)[:600]}") out["refused_restore"] = {"result": {k: res.get(k) for k in ("http", "location", "seconds", "state_after", "hold_after")}, "status": st} for lang in ("hu", "en"): h = w.page(f"/backups?lang={lang}") import re, html m = re.findall(r"[^<>]{0,160}(?:csonka|cut off)[^<>]{0,200}", html.unescape(h)) out[f"page_{lang}"] = m[:2] w.say(f" /backups ({lang}) carries the sentence: {m[:1]}") starts1 = w.guest("for c in docmost docmost-postgres; do docker inspect -f '{{.Name}} {{.State.StartedAt}}' $c; done") w.say("after:\n" + starts1) out["untouched"] = [l for l in starts0.splitlines() if "StartedAt" not in l and l.startswith("/")] == \ [l for l in starts1.splitlines() if l.startswith("/")] out["readback_A"] = SIX["docmost"]["fx"].verify(w, sub_of("docmost"), s["apps"]["docmost"]["A"], w.say) w.say(f"container start times unchanged: {out['untouched']}; seed A: {out['readback_A']}") # negative control: the whole copy back, the same button restores w.guest(f"cp -p /root/r640-whole.sql {dump}; rm -f /root/r640-whole.sql; grep -c 'dump complete' {dump}") res2 = w.restore("docmost") code, st2 = w.ctl("GET", "/api/backup/restore-status") out["control_restore"] = {"result": {k: res2.get(k) for k in ("http", "seconds", "state_after", "hold_after")}, "status": st2} out["control_readback_A"] = SIX["docmost"]["fx"].verify(w, sub_of("docmost"), s["apps"]["docmost"]["A"], w.say) w.say(f"control (whole copy): status {json.dumps(st2, ensure_ascii=False)[:300]}; seed A {out['control_readback_A']}") json.dump(out, open("E1-r640-live.json", "w"), indent=2, ensure_ascii=False) open("E1-r640-live.log", "w").write("\n".join(w.LOG) + "\n")