When async work outlives its creator, late completions/callbacks will corrupt the current state (wrong session, double-send, lost attachments, teardown overwritten). Standardize concurrency ownership and cleanup:
1) Guard every awaited continuation with an ownership token
2) Claim before await for single-consumer promises
3) Avoid stacking side effects on retries
4) Serialize ordering-sensitive writes per key
5) Clean up resources immediately on settle (including fallbacks)
Example pattern (generation guard + claim-before-await)
let generation = 0;
const current = () => generation;
function rebind() {
generation += 1;
const g = current();
(async () => {
const reply = await getReply();
if (g !== current()) return; // ownership check
applyReplyToLiveState(reply);
})();
return () => {
generation += 1; // invalidates pending continuations
};
}
// Single-consumer claim before await
let pendingResolve: ((value: string) => void) | undefined;
async function resolveOnce() {
const resolve = pendingResolve;
if (!resolve) return;
pendingResolve = undefined; // claim
await deliverAttachments(); // safe: no second submission can resolve the same pending ask
resolve("ok");
}
Apply this consistently across session rebuilds, UI binds, request/response handlers, and subprocess orchestration: define ownership, validate after awaits, prevent duplicate side effects, and clean up on settle.