22: the backstop is in the right process, and Bun honours it
Checked both things that would make a handler look like a fix while being one: it is in user-instance.ts, which ecosystem.config.cjs:23-25 confirms is what officer-agent runs — the proxy runs index.ts and would have been a perfect inert place to put it — and Bun 1.3.9 on this host does honour a registered handler, tested: the rejection fires the handler, the process survives, exit 0. Without one Bun terminates, which is the four crashes. Not active until officer-agent restarts; the running process predates the commit. Worth noting the restart is also the diagnostic. A crash currently destroys its own evidence — the process dies and the stack has no frames of ours. Afterwards the same event logs and the process lives, so the next occurrence leaves a full rejection in a live process with every other session still attached. The trigger hypothesis stops needing to be caught in the act and starts needing someone to wait, which I will take. On uncaughtException: agreed, and the asymmetry is not inconsistent. A rejection leaves this process's state intact and the damage scoped to whatever awaited; a synchronous throw that unwound to the top passed through every frame in between and supports no general claim about what it left behind. The two differ in what they imply about state, not in what they cost. And the durable-sessions instinct is the sharper half. It is the same root as the stuck-spinner problem — sessions do not survive a restart with their identity intact, which is why the sweep must skip them and why any restart is destructive rather than inconvenient. Three symptoms, one missing property, worth naming before they get fixed separately. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user