Problem
The OpenCode backend can miss cancellation when the signal aborts while createOpenCodeProcess(...) is still pending.
The backend awaits the spawner before installing its abort listener. It does not check signal.aborted after the await. A cancellation in that window leaves the child alive until the iterator closes.
Reproduction
Tested against main at f0971fd with a delayed spawner:
- abort signal after 5 ms
- spawner resolves after 30 ms
- terminate calls before the backend returns: 0
- terminate calls only after the iterator is closed: 1
Braid's packed CLI Bridge cancellation test enters this window with an early cancel. The stream emits a backend error and failed final event, while executor teardown can take more than 20 seconds to acknowledge.
Expected
Bind cancellation once through a shared helper:
- If
signal.aborted is already true, terminate immediately.
- Otherwise install the one-shot abort listener.
- Remove the listener during cleanup.
Add a deterministic delayed-spawner test that aborts before process creation resolves and proves termination occurs immediately after spawn.
Problem
The OpenCode backend can miss cancellation when the signal aborts while
createOpenCodeProcess(...)is still pending.The backend awaits the spawner before installing its abort listener. It does not check
signal.abortedafter the await. A cancellation in that window leaves the child alive until the iterator closes.Reproduction
Tested against main at
f0971fdwith a delayed spawner:Braid's packed CLI Bridge cancellation test enters this window with an early cancel. The stream emits a backend error and failed final event, while executor teardown can take more than 20 seconds to acknowledge.
Expected
Bind cancellation once through a shared helper:
signal.abortedis already true, terminate immediately.Add a deterministic delayed-spawner test that aborts before process creation resolves and proves termination occurs immediately after spawn.