Part of #641.
Problem
DeploymentRecorder.finish() (components/deploymentRecorder.ts) emits an internal sentinel, _recorder_finished, on the deploy's progress emitter. It does this so that get_deployment's live tail can stop waiting. The sentinel goes out before the recorder sets finished and unsubscribes, so it also leaks into places it doesn't belong:
- The record. The recorder's own subscriber (
appendEvent) appends the sentinel to event_log, and the terminal write stores it. Every finished deployment's history therefore ends with an _recorder_finished entry, and Studio's deployment detail shows that entry in its activity list.
- A streamed
deploy_component. The SSE writer (server/serverHelpers/progressEmitter.ts) forwards every emitter event, so clients receive an _recorder_finished event before done.
- The live tail.
get_deployment's live tail (components/deploymentOperations.ts) calls sse.emit before it checks whether the event is terminal, so the tail forwards the sentinel too.
I found this by reading the code and haven't reproduced it.
Proposal
Signal the end of a deployment to the live tail some other way, such as a promise the recorder settles, or a finished status the tail already reads. Failing that, emit the sentinel after the recorder unsubscribes, and have both SSE writers drop event names that start with _.
Done when
A finished deployment's event_log contains no _recorder_finished entry. Neither a streamed deploy_component nor a get_deployment tail sends one, and the tail still ends when the deploy does.
Part of #641.
Problem
DeploymentRecorder.finish()(components/deploymentRecorder.ts) emits an internal sentinel,_recorder_finished, on the deploy's progress emitter. It does this so thatget_deployment's live tail can stop waiting. The sentinel goes out before the recorder setsfinishedand unsubscribes, so it also leaks into places it doesn't belong:appendEvent) appends the sentinel toevent_log, and the terminal write stores it. Every finished deployment's history therefore ends with an_recorder_finishedentry, and Studio's deployment detail shows that entry in its activity list.deploy_component. The SSE writer (server/serverHelpers/progressEmitter.ts) forwards every emitter event, so clients receive an_recorder_finishedevent beforedone.get_deployment's live tail (components/deploymentOperations.ts) callssse.emitbefore it checks whether the event is terminal, so the tail forwards the sentinel too.I found this by reading the code and haven't reproduced it.
Proposal
Signal the end of a deployment to the live tail some other way, such as a promise the recorder settles, or a
finishedstatus the tail already reads. Failing that, emit the sentinel after the recorder unsubscribes, and have both SSE writers drop event names that start with_.Done when
A finished deployment's
event_logcontains no_recorder_finishedentry. Neither a streameddeploy_componentnor aget_deploymenttail sends one, and the tail still ends when the deploy does.