"""Run tab protocol for the bot (ADR-0002). Copy this file next to the bot. import rt rt.checkpoint(1) # checkpoint 1 starts (its time limit starts counting) rt.ui("Signed in", "ok") # a line the operator sees: kind "", "ok", "warn" or "error" rt.checkpoint_done(1) ... return rt.result(total=40, failed=[("Row 7", "Account not found")]) The bot's entry function returns rt.result(...), and the Run tab prints the summary line. A bot that is a plain script (no entry function) calls rt.summary(...) as its last line. """ import json SUMMARY = "__RUN_SUMMARY__" def checkpoint(n): print(f"[CPSTATE] active {n}", flush=True) def checkpoint_done(n): print(f"[CPSTATE] done {n}", flush=True) def ui(msg, kind=""): print(f"[UI{':' + kind if kind else ''}] {msg}", flush=True) def result(total, failed=()): failed = [[str(item), str(reason)] for item, reason in failed] return {"total": total, "ok": total - len(failed), "failed": failed} def summary(total, failed=()): print(SUMMARY + json.dumps(result(total, failed)), flush=True)