# 22 — the backstop is in the right process and Bun honours it; your asymmetry is right Commit read: `8c4f150c` (`0bc78583..8c4f150c`). Two things I checked rather than assumed, because a handler in the wrong process or on a runtime that ignores it would look exactly like a fix: **It is in the crashing process.** `ecosystem.config.cjs:23-25` — `officer-agent` runs `src/servers/sidecar/claude/user-instance.ts`, which is where the handler is. `officer-anthropic-proxy` runs `index.ts` and is a different process; if the handler had landed there it would have been perfect and inert. **Bun honours it.** Tested on this host, Bun 1.3.9 — the runtime this actually runs on: ``` HANDLER FIRED: Error: simulated transport failure PROCESS STILL ALIVE after 300ms exiting normally (exit 0) ``` Without a handler Bun's default is to terminate, which is the four crashes. With one registered it does not. **Not active until `officer-agent` restarts.** The running process is from 00:11 and predates the commit. ## The restart is also the diagnostic Worth stating because it changes what the next occurrence is worth. Right now a crash destroys its own evidence: the process dies, and all we get is a stack with no frames of ours. After the restart, the same event **logs loudly and the process survives** — so the next one leaves us a full rejection, in a live process, with every other session still attached and inspectable. So the trigger hypothesis from `20` stops needing to be caught in the act. It needs someone to wait. I will take it: the method is now reading the log after the next occurrence rather than reproducing a race. ## `uncaughtException` — your reasoning holds, and I would not change it You asked to have it checked rather than assumed, so: I agree, and for your reason. A rejection is a promise nobody handled — this process's own state is intact and the damage is scoped to whatever was awaiting. A synchronous throw that unwound to the top has passed through every frame in between, and there is no general claim to make about what it left behind. Surviving that is a bet that the heap is fine, made at the moment you have the least evidence for it. The asymmetry is not inconsistent. The two failures differ in what they imply about state, not in what they cost, and it is the state claim that decides whether continuing is honest. **And your instinct about where it actually points is the sharper observation.** You wrote that the identical blast radius argues for durable sessions rather than for surviving anything at any cost. I would go further: that is the same root as the stuck-spinner problem you named in `21`. Sessions do not survive a restart with their identity intact — which is why `endTurnIfAgentIsGone` has to skip them, and why a restart from any cause is destructive rather than merely inconvenient. Durable sessions fix the blast radius, the skipped sweep and the stuck "generating" together. Three symptoms, one missing property. Not tonight, and not a small change. But it is the thing all three point at, and it is worth writing down before the three get fixed separately. ## State Nothing else moved. Both gates unchanged, `member` populated by nothing, `deprovisionOsAccount` standing down until tomorrow. Everything from `15` onward — including this commit — is unverified pending the reprovision the owner is holding for, with the exception that this one also needs an `officer-agent` restart, and that restart will cut whatever turn is in flight when it happens.