Repository navigation
Conversation
Tool cycles write turns only and defer metadata to the next terminal commit. An approved or rejected call drops its pending operation from memory, but a teardown before that terminal left it in metadata.json; a reactor rebuilt from the store re-armed the answered call's gate and, at the original deadline, appended a second tool_result for the same call id, which the prompt tripwire rejects. The turns-only write now also writes metadata when a resolved approval changed the pending operations, so the removal lands with the turn that answers the call. Writing metadata in tryCorrelate instead would drop the op before the re-dispatched result is on disk, leaving a dangling tool_use with no gate to answer it. Cycles that leave pending operations untouched still skip the metadata write.
The pending-operation removal reaches metadata in a second await after the result turn, so a crash between the two leaves a stale op for a call history already answers. A reactor rebuilt from that store re-armed its gate and, at the original deadline, appended a second tool_result for the same call id, which the prompt tripwire rejects. Startup now drops and persists the removal of any loaded op whose parked call already has a result, and the approval timeout injects no synthetic result for such a call.
TheGreatAxios
left a comment
There was a problem hiding this comment.
Review · Request changes
A single approved or rejected call persists its pending-operation removal with the result turn. A second approval that resolves during that metadata write is left on disk.
Findings
vendor/intx-inference/src/reactor.ts:1392—writeMetadatasnapshotsgetPendingOperations()before the await, then setspendingOperationsChanged = falseat:1397. The flag is raised when an approval, rejection, or timeout drops an op (:789,:814,:1463). If another parked call is approved during that write, its removal is cleared off the flag after a payload that still contains it.writeCycleTurnsthen writes the secondtool_resultand skips metadata. Tear down before the next terminal commit and a rebuild re-arms that call. Two ask calls showed both results on disk whilecall-bwas still inpendingOperations. Clear the flag only when the live set still matches the bytes just written. Cover that next to the tests atreactor.test.ts:5470and:5529.
Notes
- One approval or rejection still removes the op with the answering turn (
reactor.ts:1231,:1667). Tool cycles that do not touch pending ops still skip metadata (reactor.test.ts:2522). - This diff edits
vendor/intx-inference, which triage forbids. That is separate from the race above.
|
Superseded by CL-10781, which stores a pending approval in turns.jsonl next to the call it parks, so the call's result closes it. That needs no change under |
Crash recovery could reload a pending operation for a call the turns already answer, re-arming its gate and injecting a second tool result at the deadline. load() now drops any pending operation whose suspended call id already has a tool result, warning per drop; marker operations without a suspended call pass through. The removal converges to disk on the next metadata write.
…out-result-for-a-parked-call-that-already fix(reactor): never re-answer a parked call that already has a result
|
Superseded by #1495, which has merged. A parked approval lives in turns.jsonl beside its call, so this metadata-removal patch is not needed. |
Summary
metadata.jsontogether with the turn that answers it, so a reactor rebuilt from the session store never re-arms the answered call's gate.ask, rebuilds the agent from the same store, and advances past the original gate deadline.In the interactive TUI without yolo, a reload right after an approval rebuilt the agent while
metadata.jsonstill listed the pending operation. One hour later the stale gate injectedapproval timed outfor a call that already had a result, and the session died withMalformed tool sequence: duplicate tool_result.Verification
bun run typecheck,bun run build, andbun run testpass (9203 tests)Fixes CL-10764
Fixes CL-10767
Part of CL-10763