Skip to content

fix(peer): bound the relay history observer read and surface first-page stalls - #3587

Draft
Raing5Days wants to merge 1 commit into
GCWing:mainfrom
Raing5Days:fix/peer-surface-blocking-interaction
Draft

Raing5Days wants to merge 1 commit into
GCWing:mainfrom
Raing5Days:fix/peer-surface-blocking-interaction

Conversation

@Raing5Days

Copy link
Copy Markdown
Contributor

Summary

Fixes a controller-side deadlock that leaves a peer Surface stuck on a loading placeholder, with no answerable AskUserQuestion card.

Root cause: load_relay_session_selection acquired the per-session mutation lease through an unbounded acquire_session_mutation. That lease is owned by the Session's own Turn for the Turn's whole life. When that Turn is blocked on an unanswered AskUserQuestion, a controller's first read_stream waits on the same lease, so the stream never becomes ready, the transcript and the question card never arrive, and the answer that would release the Turn can never be sent.

  • coordinator.rs: the relay history observer read now waits a bounded window for the lease and otherwise projects the persisted records. It still refuses to project while an unfinished undo transition needs the lease, rather than returning rows that transition is about to replace.
  • RelaySessionHistory.ts: opening no longer waits forever for relay://session-ready. After a timeout it reads the runtime interaction mailbox directly, publishes a ready-but-empty page and leaves hydration; the live subscription stays open, so a late page still applies.
  • RelaySessionHistory.test.ts: regression test for the overdue-first-page path.

Validation

  • pnpm --dir src/web-ui run test:run src/flow_chat/services/RelaySessionHistory.test.ts — passed (7 tests)
  • pnpm --dir src/web-ui run test:run src/flow_chat/store/FlowChatStore.test.ts src/flow_chat/services/RelaySessionHistory.test.ts src/flow_chat/services/flow-chat-manager/PeerSessionRefreshModule.test.ts — passed (277 tests)
  • pnpm --dir src/web-ui run type-check — passed
  • cargo check -p openbitfun-core --lib — passed, with two pre-existing dead_code warnings in service/config/service.rs and util/errors.rs unrelated to this change
  • pnpm run fmt:rs — applied

Not verified: an end-to-end two-device Peer session over an SSH workspace. The deadlock analysis is static, and the 1.5s lease wait is a judgement call that only the local reproduction can confirm.

Risks

  • Peer surfaces only: the bounded wait narrows the consistency window for observer reads. While the lease is held, a controller can now see persisted records slightly before the Turn settles. That is the same projection the mailbox/snapshot path already reconciles.
  • When a Session has an unfinished revert that needs the lease, the read now fails with an explicit OutcomeUnknown instead of hanging. Controllers surface that as a failed history load rather than a spinner that never resolves.
  • No persisted shape changes; no protocol or capability changes.

Generated with OpenBitFun

Relay history reads acquired the per-session mutation lease without a bound. The lease owner is the Session's own Turn, which holds it for the Turn's whole life, so a Turn blocked on an unanswered AskUserQuestion also blocked the read that lets a controller answer it. Wait briefly for the consistent window and fall back to persisted records instead.

A stalled relay stream likewise left a controller Surface hydrating forever. The first page now has a timeout that reads the runtime interaction mailbox directly and leaves hydration; the subscription stays open, so a late page still applies.
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.

1 participant