Skip to content

fix(pi): a fresh pane's first prompt waits for its bridge (#1315) - #1316

Merged
Juliusolsson05 merged 4 commits into
mainfrom
fix/pi-bootstrap-waits-for-bridge
Sep 25, 2026
Merged

Juliusolsson05 merged 4 commits into
mainfrom
fix/pi-bootstrap-waits-for-bridge

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Fixes #1315.

Plan: docs/plans/2026-09-25-pi-bootstrap-waits-for-bridge.md (first commit).

Why

Pi orchestration_create_agent calls lost their bootstrap prompt with prompt_delivery_failed … the Pi bridge is not connected, and a later retry worked. The issue counted 5 of 5 on 2026-09-25. Review C found 27 such incidents in that day's journals: 26 bootstraps and 1 send_prompt. Each failed 9–40 ms after start, and the bridge became ready a median 498 ms later (max 15.4 s).

The cause: PiSession.deliverPromptText asked the package to submit while the bridge extension was still connecting, and the package answers no-live-channel at once. Codex already waits for readiness before its first write; Pi did not.

What merges

  • PiSession keeps a flag, "bridge startup settled", that resets on each start. The package's own verdicts set it:
    • the first connected;
    • bridge-unreachable, after the package's connect deadline (30 s by default);
    • bridge-listen-failed.
      Exit and stop set it too.
  • deliverPromptText waits for that flag before the first connect only. It reads the pane's state again after the wait, because the pane may have stopped meanwhile. A 35 s cap is a backstop in case the package never settles.
  • A bridge that drops mid-session still fails fast. A bridge that never connects still fails not-ready, with the existing banner.
  • Nothing is pasted into the TUI (bug(opencode): prompts sent to a just-started OpenCode Terminal pane are silently lost #877).

Tests

piSession.system.test.ts, 28 tests, all driven by the recorded bridge replay:

  • A prompt sent before the bridge connects waits, then submits that prompt. The test checks the exact submitPrompt argument. It is red on main.
  • Once the bridge has connected and dropped, delivery fails fast (under 1 s) as not-ready.
  • A waiting delivery settles at once when pi exits, the pane stops, or the bridge cannot listen (3 cases).
  • With nothing settling, delivery gives up at the cap: nothing is submitted at 34 s, and the delivery settles by 36 s (fake timers).
  • The existing no-bridge test still refuses not-ready after the deadline.

npx tsc -b is clean.

Residual

  • When the cap fires, it does not mark startup settled. A retry after a cap timeout waits the full cap again. This happens only if the package emits none of its verdicts, which the recorded incidents never showed.
  • The cap is fixed at 35 s. It does not follow a custom bridgeConnectDeadlineMs.
  • The orchestration tool call is silent while it waits: about 0.5 s typically, 15 s at worst on record.
  • Nobody tested this against live Pi.

🤖 Generated with Claude Code

Juliusolsson05 and others added 4 commits September 25, 2026 09:28
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Orchestration delivers a Pi child's bootstrap prompt right after spawn,
while the bridge is still connecting, and it failed with "the Pi bridge is
not connected" every time. Delivery now waits until the package settles
the bridge startup (connected, unreachable after its deadline, listen
failure, exit or stop); a mid-session disconnect still fails fast.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a drop, and every settle path pinned

The first test proved only that some request reached the rig. Now it asserts
the prompt submitted; a delivery after a later disconnect fails at once; and
exit, stop, a listen failure and the 35 s cap each settle a waiting
delivery. Every mutation review B listed now fails a test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Juliusolsson05 added a commit that referenced this pull request Sep 25, 2026
…dicts, #1316

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Final disposition (pre-merge), head fb4e6dc. Three independent reviewers:

  • A (correctness): one round. A said MERGE-READY in round 1 and was told no further round was needed unless it found a problem. There is no round-2 report from A.
  • B (tests): two rounds.
  • C (evidence and UX): one round.
Reviewer Round 1 Round 2
A (correctness) MERGE-READY — (not needed)
B (tests) FIX-BEFORE-MERGE MERGE-READY (at fb4e6dc)
C (evidence, UX) MERGE-READY —

Findings and dispositions:

Round 1, B (all fixed in 129424f; B's round 2 confirmed each mutant now fails one test, 28/28 green, subset stable over 12 runs)

  • Major: the bootstrap test accepted delivery of the wrong prompt, because the replay rig refuses every request the same way. Fixed. The test now asserts that submitPrompt receives the exact text.
  • Major: nothing protected fast failure after a later disconnect. Fixed by the new test "fails fast after the bridge has connected once and then dropped", which requires under 1 s and pi-terminal-not-ready.
  • Major: a pending delivery could wait until the cap after the PTY exited or the pane stopped. Fixed by "settles a waiting delivery when pi exits / the pane stops".
  • Minor: a listen failure and the 35 s cap had no test. Fixed by "…when the bridge cannot listen" and "gives up at the cap…". The cap test uses fake timers: nothing is submitted at 34 s, and the delivery settles by 36 s.

Round 1, A

  • Minor: the stop, exit and bridge-listen-failed wakeups were untested. Fixed in 129424f by the same tests.
  • Suspicion: the 35 s cap is fixed, independent of a custom bridgeConnectDeadlineMs. Not fixed. Production uses the package's 30 s default, so no user-facing failure has been shown.

Round 1, C

  • Minor: when the cap fires, it resolves the waiter but does not set bridgeStartupSettled. If the package never settles, a retry by the parent waits another 35 s. This only happens when the package emits none of connected, bridge-unreachable or bridge-listen-failed, which C's 27 recorded incidents never showed. Not fixed; the code at piSession.ts:312-322 is unchanged.
  • Also minor: the cap was unpinned (C's 35→90 s mutant survived). Now pinned by the fake-timer cap test from 129424f, which checks at 34 s and 36 s.
  • C's evidence: 27 journal incidents, all immediate not connected failures. The bridge became ready a median of 498 ms later (max 15.4 s). A bridge that never connected: 0 of 27.

Residuals:

  • The cap does not stick. A retry after a cap timeout waits the full cap again, which matters only if the package never settles.
  • The cap does not follow a custom bridge connect deadline.
  • The orchestration tool call is silent while it waits: about 0.5 s typically, 15 s at worst in the recorded data.
  • Nobody ran live Pi. All tests use recorded bridge fixtures.

Merges through batch PR #1318 once every member passes its gate.

🤖 Generated with Claude Code

@Juliusolsson05
Juliusolsson05 merged commit 2096373 into main Sep 25, 2026
1 of 2 checks passed
@Juliusolsson05
Juliusolsson05 deleted the fix/pi-bootstrap-waits-for-bridge branch September 25, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(pi): orchestration_create_agent's bootstrap prompt always fails for Pi — delivery does not wait for the bridge to connect

1 participant