Double-start guard: launching marker, probe-and-adopt, fresh-dir relaunch; skip unreachable terminals per tick

Before the launch call the planned run (run id, terminal, handle, bookkeeping) is saved as a launching
marker. If the launch call fails or agentd dies before recording the run, the next tick probes the run
directory (exit.txt / launch.pid / pid.txt): evidence -> adopt the run; nothing -> relaunch with the same
run id in <run_id>-r2 (-r3 ...); probe unreachable -> keep the marker, which holds the terminal slot.
Transports refuse to clean a run directory holding a pid file. A terminal whose relay fails is skipped
for the rest of the tick (heartbeat.down) while other terminals carry on.
This commit is contained in:
jj.wang
2026-10-21 11:54:40 +00:00
parent dbe305103c
commit 4f45d368ad
8 changed files with 357 additions and 50 deletions
+27
View File
@@ -120,3 +120,30 @@ class StoreTest(unittest.TestCase):
if __name__ == "__main__":
unittest.main()
class GuardTest(unittest.TestCase):
def test_local_clean_refuses_dir_with_pid_file(self):
from agentd.transports import TransportError
with tempfile.TemporaryDirectory() as tmp:
t = LocalTransport(Config(config_data()), "oregon")
(Path(tmp) / "prompt.md").write_text("x")
t.mkdir(tmp, clean=True)
self.assertEqual(t.probe(tmp, ("exit.txt", "pid.txt")), [])
(Path(tmp) / "pid.txt").write_text("1")
with self.assertRaises(TransportError):
t.mkdir(tmp, clean=True)
self.assertEqual(t.probe(tmp, ("exit.txt", "pid.txt")), ["pid.txt"])
def test_windows_probe_and_clean_guard(self):
from agentd.transports import TransportError
cfg = config.load(ROOT / "config" / "agentd.example.yaml")
t = WindowsWarpgateTransport(cfg, "win10")
scripts = []
t.ps = lambda s, timeout=150: (scripts.append(s), "PROBE=launch.pid,pid.txt\n")[1]
self.assertEqual(t.probe("C:\\r\\GW-1-1", ("exit.txt", "launch.pid", "pid.txt")), ["launch.pid", "pid.txt"])
self.assertIn("Join-Path $d $_", scripts[-1])
t.ps = lambda s, timeout=150: (scripts.append(s), "HASPID\n")[1]
with self.assertRaises(TransportError):
t.mkdir("C:\\r\\GW-1-1", clean=True)
self.assertIn("'pid.txt'", scripts[-1])