From 7f8fdd8e868fb5fad71eacdf0c4fd0a97fe9c6ee Mon Sep 17 00:00:00 2001 From: t Date: Mon, 17 Aug 2026 23:27:46 -0600 Subject: jobs: only settle may close; e2e proof harness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close_all no longer joins pump threads from the owner thread: job:close() joins the pump, and a pump parked in an owner-posted tool batch needs the owner back in the loop, so a synchronous close at turn_end could deadlock. close_all now cancels everything, closes only already-settled jobs, and defers the rest to their own settle; jobs.active() ignores closing children so the next turn can resume the id. e2e/ reconstructs the end-to-end proof against the real binary in print mode: a scripted fixture protocol plays primary and children, and the suite asserts the product surface from process output and JSONL bytes on disk — parallel batch with unknown-agent error, lane identity, tool inheritance minus subagents.*, resume with manifest re-identification, workflow diamond, sandbox fan-out with an ephemeral structured worker, catalog round-trip, child-store isolation from the session picker. mise run e2e; check stays independent. --- spec/test_jobs.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'spec/test_jobs.lua') diff --git a/spec/test_jobs.lua b/spec/test_jobs.lua index e6ce097..ce0525c 100644 --- a/spec/test_jobs.lua +++ b/spec/test_jobs.lua @@ -233,6 +233,26 @@ return { end) end }, + -- close() joins the pump, and a pump parked in a tool batch needs the owner + -- thread — the thread close_all itself runs on. So an unsettled job is never + -- closed here; it is cancelled, and the drain that sees it settle closes it. + { "close_all leaves an unsettled job to close on its own settle", function() + with_jobs(function() + local start, _, made = starter() + local handle = assert(start("alpha", { settle = 99 })) + + jobs.close_all() + assert(made.alpha._cancel_requested, "close_all asks a running child to stop") + assert(not made.alpha._closed, "close_all must not join a pump that is still up") + assert(handle:result() == nil, "close_all does not settle the child itself") + + local results = jobs.await({ handle }, "all") + assert(results[1].status == "cancelled", tostring(results[1].status)) + assert(made.alpha._closed, "the job closes as soon as it settles") + assert(handle:result().status == "cancelled", "the result is cached before the close") + end) + end }, + { "a build failure is a nil return, never an exception", function() with_jobs(function() local start = starter() -- cgit v1.3