Skip to content

Commit 6e1f9a0

Browse files
committed
Explain why finalizeOnCrash clears the active-run handle early
The prior comment only noted that finalizeRunState's own clear becomes a no-op repeat, which reads as an argument for deleting the early call rather than keeping it. It is not redundant: index.ts installs its own crash listeners that read the handle directly and would otherwise race a competing write during the awaits here.
1 parent 7675e1a commit 6e1f9a0

1 file changed

Lines changed: 12 additions & 6 deletions

File tree

src/tui/runner.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,18 @@ export async function runTUI(initialConfig: Config): Promise<number> {
553553
const finalizeOnCrash = async (err: unknown): Promise<void> => {
554554
if (finalized) return;
555555
finalized = true;
556-
// Clear the active-run handle up front, before the awaits below, so a
557-
// second crash mid-flush can't see this run as still live and race the
558-
// finalize write issued here. finalizeRunState (state.ts) would otherwise
559-
// do this itself, but only after saveState resolves — too late for that
560-
// guard, so it's done here and finalizeRunState's own clear becomes a
561-
// no-op repeat of the same fact rather than a second independent write.
556+
// Clear the active-run handle up front, before the awaits below. This
557+
// handler isn't the only reader of the handle: index.ts installs its own
558+
// uncaughtException/unhandledRejection listeners that call getActiveRun()
559+
// directly and, if it's still set, write a competing "crashed" record via
560+
// saveCrashState. An escaped throw during flushPartialOnCrash or the
561+
// finalizeRunState await below would otherwise reach that listener while
562+
// the handle still reads as live, racing its write against the "failed"
563+
// write in progress here. finalizeRunState (state.ts) also clears the
564+
// handle, but only after its own saveState resolves — too late to close
565+
// that window, so the clear is duplicated here. finalizeRunState is left
566+
// unchanged: its other callers (normal completion, session rotation) rely
567+
// on it being the one that clears the handle.
562568
clearActiveRun();
563569
clearActiveDisposeHost();
564570
await flushPartialOnCrash().catch((flushErr: unknown) => {

0 commit comments

Comments
 (0)