3e58c184f6
gates / gates (push) Successful in 27s
DRILL-night-2026-09-23.md: Parts A-E. 09 §3 decisions 21 (operator word), 22 and 23 (CC unattended, operator may reverse); §6.4 parts 4 and 6 (catalog half) shipped; §6.1a residuals R-658/R-659. Register 330 -> 336: R-651..R-660 opened (R-658 and R-659 P1), R-650/R-640/R-499/R-626 closed. Capability map, nightly rotation (opengist), STATUS (one question: the floor), CONTEXT, REPORT. The floor stays 0.266.0. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
63 lines
3.7 KiB
Python
63 lines
3.7 KiB
Python
#!/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")
|