Skip to content

Commit 2ebfe7f

Browse files
committed
docs(gui): record why the pause path is not cross-gated with the pin writes
Pausing the pinned account releases the pin too, so the obvious reading of the switch/order cross-gate is that pause was missed. It was not: that edge is conditional on the pin still naming the paused account, so it is a no-op whenever a concurrent write has already moved the pin elsewhere, and the client agrees with the server whichever response lands last. The gated pair state a pin outright, which is what makes response order decide the outcome. Comment only -- worth having at the line, because the safe-looking fix (share pauseMutationRef) would make a pause and an order change on two unrelated accounts reject each other, and because copying the unconditional pattern here would introduce the very race the gate exists to prevent.
1 parent aa9a338 commit 2ebfe7f

1 file changed

Lines changed: 11 additions & 0 deletions

File tree

gui/src/hooks/useCodexAccountPool.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,14 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou
301301
pendingActiveIdRef.current = { id: nextActiveId };
302302
setActiveId(nextActiveId);
303303
}
304+
// Deliberately NOT cross-gated against the switch and order writes, even though
305+
// pausing the pinned account also releases the pin. This edge is conditional on
306+
// the pin still naming `id`, which makes it order-robust: whichever response
307+
// lands last, the client agrees with the server. An unconditional edge is what
308+
// forced the gate between those two -- each states a pin outright, so the later
309+
// response wins regardless of which write the server applied last. Sharing a
310+
// mutation ref here would instead make a pause and an order change on two
311+
// unrelated accounts reject each other for no reason.
304312
if (paused) setActivePinnedId(current => current === id ? null : current);
305313
void load();
306314
return { ok: true } as const;
@@ -375,6 +383,9 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou
375383
pendingActiveIdRef.current = { id: nextActiveId };
376384
setActiveId(nextActiveId);
377385
}
386+
// Conditional for the same reason as the single-account pause above: clearing
387+
// outright would race the switch and order writes, which is why those two are
388+
// gated against each other and these two do not need to be.
378389
setActivePinnedId(current => current !== null && pausedIds.has(current) ? null : current);
379390
void load();
380391
return { ok: true, pausedCount: result.pausedCount ?? pausedIds.size } as const;

0 commit comments

Comments
 (0)