"""Pin decision 61: each agent state from the host's session snapshot, the night state, radio receipts and claim beats.""" from __future__ import annotations import json import os import tempfile import unittest from pathlib import Path import hub_support # noqa: F401 import sessions as client from kvb_orchestrator.presence import SNAPSHOT_STALE, presence, read_snapshot NOW = 1_800_000_000.0 FRESH = int((NOW - 60) * 1000) OLD = int((NOW - 1800) * 1000) def record(sid: str, status: str, updated: int, name: str) -> dict: return {"status": status, "statusUpdatedAt": updated, "name": name, "running": sid != "gone"} def claim(session: str, name: str, beat: float | None) -> dict: return {"session": session, "agent": name, "beat": beat} class TestPresence(unittest.TestCase): def states(self, sessions: dict[str, dict], parts: dict[str, str], mode: str, claims: list[dict], news: list[dict]) -> dict[str, str]: return presence(sessions, parts, mode, claims, news, NOW) def test_each_state_by_day_and_by_night(self): sessions = {sid: record(sid, status, updated, name) for sid, status, updated, name in ( ("work", "busy", FRESH, "Worker"), ("idle", "idle", OLD, "Idler"), ("gone", "idle", FRESH, "Ghost"), ("stuck", "busy", OLD, "Stuck"), ("called", "idle", OLD, "Callee"), ("answered", "idle", OLD, "Answerer"), ("sleep", "idle", FRESH, "Sleeper"), ("park", "busy", FRESH, "Parker"), )} call = NOW - 700 news = [ {"ts": call, "from": "Operator", "to": ["Callee"], "class": "call"}, {"ts": call, "from": "Operator", "to": ["Answerer"], "class": "call"}, {"ts": call + 2, "from": "Answerer", "to": ["Operator"], "class": "receipt", "call": call}, {"ts": NOW - 60, "from": "Operator", "to": ["Idler"], "class": "call"}, ] claims = [claim("codex-on", "Codex", NOW - 60), claim("codex-off", "Codex old", NOW - 3600), claim("-", "Nobody", NOW), claim("op", "Operator", NOW)] day = self.states(sessions, {"sleep": "suspend", "park": "drain"}, "day", claims, news) self.assertEqual(day, { "work": "working", "idle": "alive", "gone": "dead", "stuck": "unreachable", "called": "unreachable", "answered": "alive", "sleep": "sleeping", "park": "suspending", "codex-on": "alive", "codex-off": "dead", }) night = self.states(sessions, {"idle": "day", "work": "suspend"}, "drain", [], []) self.assertEqual({sid: night[sid] for sid in ("work", "idle", "called", "sleep", "park")}, { "work": "suspending", "idle": "alive", "called": "sleeping", "sleep": "sleeping", "park": "suspending", }) def test_a_status_update_after_the_call_counts_as_reached(self): news = [{"ts": NOW - 900, "from": "Operator", "to": ["Alias"], "class": "call"}] claims = [claim("later", "Alias", NOW)] self.assertEqual(self.states({"later": record("later", "idle", FRESH, "Later")}, {}, "day", claims, news), {"later": "alive"}) self.assertEqual(self.states({"later": record("later", "idle", OLD, "Later")}, {}, "day", claims, news), {"later": "unreachable"}) def test_a_record_without_running_true_is_dead(self): for value in (False, None, "yes", 1): with self.subTest(value=value): entry = {**record("s", "busy", FRESH, "S"), "running": value} self.assertEqual(self.states({"s": entry}, {}, "day", [], []), {"s": "dead"}) class TestSnapshot(unittest.TestCase): def test_the_host_client_keeps_name_status_and_whether_the_process_runs(self): with tempfile.TemporaryDirectory() as tmp: base = Path(tmp) proc, folder = base / "proc", base / "sessions" (proc / "4242").mkdir(parents=True) folder.mkdir() (proc / "4242" / "stat").write_text("4242 (claude (main)) S " + " ".join(str(n) for n in range(1, 19)) + " 777 0 0\n", encoding="utf-8") live = {"sessionId": "s1", "pid": 4242, "procStart": "777", "status": "busy", "statusUpdatedAt": FRESH, "name": "One", "cwd": "/secret"} (folder / "1.json").write_text(json.dumps(live), encoding="utf-8") (folder / "2.json").write_text(json.dumps({**live, "sessionId": "s2", "procStart": "778"}), encoding="utf-8") (folder / "3.json").write_text(json.dumps({"status": "idle"}), encoding="utf-8") (folder / "4.json").write_text("{broken", encoding="utf-8") (folder / "5.json").write_text(json.dumps(["s5"]), encoding="utf-8") output = base / "agent-sessions.json" client.write(output, client.snapshot(folder, proc, NOW)) kept = {"status": "busy", "statusUpdatedAt": FRESH, "name": "One"} self.assertEqual(json.loads(output.read_text(encoding="utf-8")), { "written": NOW, "sessions": {"s1": {**kept, "running": True}, "s2": {**kept, "running": False}}, }) self.assertEqual(sorted(path.name for path in base.iterdir()), ["agent-sessions.json", "proc", "sessions"]) self.assertEqual(client.snapshot(folder / "missing", proc, NOW), {"written": NOW, "sessions": {}}) def test_the_host_client_skips_hostile_records_and_leaves_no_temp_file(self): with tempfile.TemporaryDirectory() as tmp: base = Path(tmp) proc, folder = base / "proc", base / "sessions" proc.mkdir() folder.mkdir() good = {"sessionId": "s1", "pid": 1, "procStart": "1", "status": "busy", "statusUpdatedAt": FRESH, "name": "One"} (base / "outside.json").write_text(json.dumps({**good, "sessionId": "s9"}), encoding="utf-8") (folder / "1.json").write_text(json.dumps({**good, "name": {"x": 1}, "status": "y" * 201, "statusUpdatedAt": True}), encoding="utf-8") (folder / "2.json").symlink_to(base / "outside.json") os.mkfifo(folder / "3.json") (folder / "4.json").write_text("[" * 30000 + "]" * 30000, encoding="utf-8") (folder / "5.json").write_text(json.dumps({**good, "sessionId": "s5", "name": "z" * client.RECORD_BYTES}), encoding="utf-8") self.assertEqual(client.snapshot(folder, proc, NOW), {"written": NOW, "sessions": {"s1": {"running": False}}}) output = base / "agent-sessions.json" with self.assertRaises(TypeError): client.write(output, {"written": object()}) self.assertEqual(sorted(path.name for path in base.iterdir()), ["outside.json", "proc", "sessions"]) def test_running_needs_an_int_pid_and_the_same_process_start(self): with tempfile.TemporaryDirectory() as tmp: proc = Path(tmp) (proc / "4242").mkdir() (proc / "4242" / "stat").write_text("4242 (claude (main)) S " + " ".join(str(n) for n in range(1, 19)) + " 777 0 0\n", encoding="utf-8") entry = {"pid": 4242, "procStart": "777"} self.assertTrue(client.running(entry, proc)) for bad in ({**entry, "procStart": "778"}, {**entry, "pid": 4243}, {**entry, "pid": True}, {**entry, "pid": "4242"}, {"pid": 4242}): with self.subTest(bad=bad): self.assertFalse(client.running(bad, proc)) def test_the_hub_reads_only_a_fresh_well_formed_snapshot(self): with tempfile.TemporaryDirectory() as tmp: path = Path(tmp) / "agent-sessions.json" self.assertEqual(read_snapshot(path, NOW), {}) entry = record("s1", "busy", FRESH, "One") for data, expected in ( ({"written": NOW - SNAPSHOT_STALE, "sessions": {"s1": entry, "s2": "x"}}, {"s1": entry}), ({"written": NOW - SNAPSHOT_STALE - 1, "sessions": {"s1": entry}}, {}), ({"written": True, "sessions": {"s1": entry}}, {}), ({"written": NOW + 1, "sessions": {"s1": entry}}, {}), ({"written": float("nan"), "sessions": {"s1": entry}}, {}), ({"written": NOW, "sessions": ["s1"]}, {}), (["s1"], {}), ): with self.subTest(data=data): path.write_text(json.dumps(data), encoding="utf-8") self.assertEqual(read_snapshot(path, NOW), expected) if __name__ == "__main__": unittest.main()