Found during the integration review of PR #274 (issue #271).
The defect
packages/codev/src/agent-farm/commands/spawn.ts:211 calls ensureThreadBackendReady and nothing calls closeThreadBackend. cli.ts:339-379 has no process.exit on the success path. The open WebSocket keeps the event loop alive, so the command does its work and then does not exit.
This is the same defect PR #274 fixes for afx workspace add-architect, where it presented as a hang past two minutes with the architect already created and registered. Working, and hung, which from outside reads exactly like a command that failed.
The pattern under it
Four one-shot commands now reach a thread backend. Three hand-roll the same finally:
spawn.ts is the fourth and has none. A comment in the #274 fix says every one-shot command owes this, but nothing enforces it, so the next command to reach a thread will forget it too.
What would close this
closeThreadBackend on the afx spawn path.
- A
withThreadBackend(workspaceRoot, fn) helper that acquires and releases in one place, with the three existing hand-rolled finally blocks moved onto it, so forgetting is not expressible.
- A test that fails without the release. Assert at the call site, not on the module.
Source
.consult-runs/integration-271.md, integration review of PR #274.
Found during the integration review of PR #274 (issue #271).
The defect
packages/codev/src/agent-farm/commands/spawn.ts:211callsensureThreadBackendReadyand nothing callscloseThreadBackend.cli.ts:339-379has noprocess.exiton the success path. The open WebSocket keeps the event loop alive, so the command does its work and then does not exit.This is the same defect PR #274 fixes for
afx workspace add-architect, where it presented as a hang past two minutes with the architect already created and registered. Working, and hung, which from outside reads exactly like a command that failed.The pattern under it
Four one-shot commands now reach a thread backend. Three hand-roll the same
finally:interrupt.ts:89cleanup.ts:575workspace-add-architect.ts(PR [Air #271] The architect that arrived, hung, and could not be seen #274)spawn.tsis the fourth and has none. A comment in the #274 fix says every one-shot command owes this, but nothing enforces it, so the next command to reach a thread will forget it too.What would close this
closeThreadBackendon theafx spawnpath.withThreadBackend(workspaceRoot, fn)helper that acquires and releases in one place, with the three existing hand-rolledfinallyblocks moved onto it, so forgetting is not expressible.Source
.consult-runs/integration-271.md, integration review of PR #274.