fix(pi): fork completed turns while the next turn is running#23052

merged3
main
fix/issue-23050
opened1d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

Forking a completed Pi turn while the next turn is still running fails with “Pi turn 2 has no captured session-tree entry and none was found in the session tree.” The running turn has a synthetic weak reference and no completion timestamp, although Pi has already persisted its prompt.

Change

Allow the existing session-tree recovery window to remain open at its upper end for a running boundary turn. Keep the retained turn’s lower bound, ancestry validation, and earliest-user-entry selection, so the fork cuts before the running turn’s prompt rather than a later steer. Completed boundary turns keep their finite upper bound.

Add one adapter regression for the running weak-reference boundary. This is a server-only Pi adapter change; no client, wire contract, or other provider changes.

Scope and approval

Fixes #23050

Triaged bug via the automated issue flow. Focused repair of the existing fork behavior, following #20521; no authentication, credential, permission, approval, mode, sandbox, or MCP changes.

Verification

  • Test-first: the running-boundary regression fails on main with the exact reported protocol error; the existing three native-fork tests pass. Independent proof audit reruns red and green.
  • ./node_modules/.bin/vp test run packages/provider-pi/src/server/adapter.test.ts: 84/84 pass on the final head, including the existing completed-uncaptured-boundary cases.
  • Scoped Pi typecheck, changed-file lint, formatting, whitespace checks, and knip --workspace packages/provider-pi --no-config-hints pass. Lint reports one existing unused layer warning outside this change.
  • Temporary fake-Pi runtime driver: before fails with the exact protocol error; after returns /fake/forked.jsonl and sends native fork at u2, excluding turn 2 and its later steer. Evidence is from the adapter’s fake Pi protocol harness, not native session persistence.
  • Codex GPT-6.1 Sol and Claude Opus 5.5 independent reviews: MERGE, no confirmed bugs. Removed their nonblocking fixture-only ancestry assertion.
  • UI evidence matrix is empty. No visual changes; no screenshots or recordings required.

23050-runtime-proof.txt 23050-proof-matrix.txt

Pi 1.3.0 installed without model credentials. Attempted the isolated worktree web flow, but repeated dev watcher restarts on source/test-cache changes and reconnect failures prevented completing the live two-turn sequence. Live Pi, authenticated model behavior, Windows, Electron desktop, and mobile remain unverified. No live T3 state was written. Main was fetched and merged locally; it was already up to date.

Implementation and regression test: Claude Opus 5.5. Triage, integrated verification, proof audit, and review: Codex GPT-6.1 Sol and Claude Opus 5.5 through T3 Code (Codex and Claude Agent harnesses).

Checks

All checks passed

Added 3 commits

  • fix(provider-pi): fork before a running turn whose start entry was not captured yet111dadc
  • test(pi): keep running fork regression focused on native cut1372a7a
  • test(provider-pi): reproduce #23050 fork before a running uncaptured turnc208208
Synced from GitHub

Approvability

Verdict: Approved at 1372a7a

Macroscope's review found this PR approvable — This is a narrowly scoped Pi adapter bug fix that keeps completed-turn behavior unchanged while allowing forks to recover a prompt from a currently running boundary turn. The accompanying regression test covers the previously failing case, with no schema, defaults, infrastructure, or static-analysis override changes.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiB✅
ClaudeLive turn messages220 (0.0%)8✅

Baseline: d27c606 · PR result: 1372a7a · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 06674b94-6ba1-4034-bb54-17fe610201db
📥 Commits

Reviewing files that changed from the base of the PR and between d27c6067a9162150f654e38f455a7a936ef79178 and 1372a7af05a99986ff154c41ec3d6c83b21f51c3.

📒 Files selected for processing: 2
  • packages/provider-pi/src/server/adapter.test.ts
  • packages/provider-pi/src/server/adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

📝 Walkthrough

The uncaptured fork-entry search now supports a boundary turn that has started but is still running. A regression test verifies that forking succeeds and includes the running turn’s root entry, but not its steer entry.

Changes: Running-turn fork boundary

Layer / File(s)Summary
Handle running fork boundaries
packages/provider-pi/src/server/adapter.ts, packages/provider-pi/src/server/adapter.test.ts
piUncapturedForkEntry uses an open-ended search window when completedAt is absent, while still requiring startedAt. The regression test checks the fork identity and confirms that only the running turn’s root entry is included.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related issues

  • Issue 23050 reports the Pi fork failure when the next turn is still running. This change addresses that case by extending the uncaptured search window and adding a regression test.

Suggested reviewers: henrychu04

Merge Risk: ⚪ Minimal · up to 1372a

The running-turn fork change appears mergeable after normal checks; the available evidence establishes no remaining issue.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main fix: Pi can fork a completed turn while the next turn is running.
Description checkPassedThe description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the failure, implementation, regression test, verification results, and unverified env…
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the failure, implementation, regression test, verification results, and unverified environments.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.