feat(service): the planning conversation's held read is woken by its mark over Neon Realtime

Draft
CH
7d ago
+93-19

Stacked on #3267 (luke/neon-realtime-planning-conversation), which stacks on #3266, #3232 and #3217. This is the second planning-conversation PR in the series moving Luke's reads onto Neon Realtime.

What changes

#3267 moved the hold for a desktop that follows the conversation's mark into the host. The service's own held read of /api/plans/{id}/messages?after= is still used by older desktops. That read still looked again every 250 ms.

brainPagePast now waits with #3266's lookedUntil and takes the conversation's mark statement from planConversationLiveStatements (added in #3267) as its live statement:

  • It looks again whenever the mark changes over Realtime, and every 5 s as a safety check. There is no BRAIN_POLL fallback.

The /messages route passes the mark. A read with hold=none is unchanged.

Tests

  • task-work.test.ts scripts a LiveWake. A held read on a running turn is answered as soon as the watch fires after the turn settles, even though TestClock never moves, and it watched exactly the mark's statement. On the old poll, that read would wait for the clock.
  • The existing held-read tests provide a scripted wake and drive the safety beat.
  • pnpm check:affected passes except apps/desktop/src/main/app-menu.test.ts, which fails in the sandbox because Electron can't install there.

Made with Luke


Summary by cubic

Wakes the planning conversation's held message reads on the conversation's mark over Neon Realtime instead of polling every 250 ms.

  • brainPagePast now waits via lookedUntil on the mark statement, so a held read looks again as soon as the mark changes, plus a 5 s safety check.
  • Where Realtime is unavailable it falls back to BRAIN_POLL exactly as before.
  • The /messages route passes the mark along; reads with hold=none are unchanged.
  • Adds a test that a held read hears a settling turn when the mark fires even though TestClock never moves.