Handle each pi stdout line in its own event-loop turn - #2355
Merged
SawyerHood merged 1 commit intoAug 24, 2026
Conversation
The parity self-test `pi/compaction reproduces its recording` failed on main (#2346, #2349): `turn/input/accepted` for the steer moved after the `item.close` of the `sleep 2` command, so the row spans shifted. One pipe read can carry pi's `prompt` response and the events pi wrote after it. The bridge handled a chunk in one synchronous loop: the next event's delivery ran one microtask hop after its line, but the steer's ack runs after several `await` hops past the response. So the ack went out after the event, and the bridge's order depended on pipe chunking. A loaded CI runner can stall the bridge past the replay child's 50 ms post-response gap, which merges the two lines into one read. `PiRpcChild` now queues stdout lines and handles one line per event-loop turn. The request continuation finishes before the next line, the order a line-at-a-time read gives. Verification: a new fake-pi knob (FAKE_PI_BATCH_STEER_REPLY=1) writes the steer response and the resumed run's first event in one write; the new round2 test fails before this change and passes after it. The parity cell passes 3/3 with a replay child patched to coalesce post-response writes (it failed 3/3 before). Full pi plugin and parity suites pass. Co-Authored-By: Claude <noreply@anthropic.com>
SawyerHood
deleted the
bb/investigate-failing-main-tests-thr_3t6w72mwrv
branch
August 24, 2026 22:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
The parity self-test
pi/compaction reproduces its recordingfails onmain(CI for #2346 and #2349, jobTests (packages, ubuntu-latest, Node 22.x)). The recording contains a steer. After the steer, pi writes thepromptresponse and then thetool_execution_endforsleep 2. One pipe read can carry both lines. The pi bridge handled a chunk in one synchronous loop: the event's delivery (deliverInOrder) runs one microtask hop after its line, but the steer'sinput.acceptedruns severalawaithops after the response. Soitem.closewent out beforeinput.accepted, and the bridge's output order depended on pipe chunking. The parity replay child keeps a 50 ms gap after a response, but a starved CI runner can stall the bridge past that gap. The diff in CI shows this exactly:turn/input/acceptedmoved, and thesleep 2row spans seq 9–11 instead of 9–12.The other red test on
main(bridge.lifecycle.test.ts > a failed construction leaves no child, #2346 only) is the pi lifecycle budget flake that #2353 addresses.What changed
plugins/provider-pi/src/bridge/rpc-child.ts:PiRpcChildqueues stdout lines and handles one line per event-loop turn (setImmediate). A request's continuation finishes before the next line, which is the order a line-at-a-time read gives.plugins/provider-pi/src/bridge/fake-pi-rpc.mjs: new knobFAKE_PI_BATCH_STEER_REPLY=1writes a steer'spromptresponse and the resumed run's first event in one stdout write.plugins/provider-pi/src/bridge/bridge.round2.test.ts: regression test that pins the ack before the same-chunk event.No wire change.
HOST_DAEMON_PROTOCOL_VERSIONstays the same: only the bridge's ordering became deterministic.How you verified
pi/compactioncell 3/3 before the change and passed 3/3 after it. The patch was a local experiment and is not part of this PR.pnpm exec turbo run test typecheck --filter=./plugins/provider-pi --filter=@bb/provider-parity --force: pi plugin 105/105, parity 56/56, typecheck clean.pi(0.84.3) slice of@bb/agent-runtime#test:integration(integration.provider-basic.test.ts -t "pi provider"): 8/8, including "steers an active turn".Fixes the
pi/compactionparity failure onmain(no issue filed).