Skip to content

fix(tui): preserve prompts during session hydration#36433

Open
kitlangton wants to merge 1 commit into
v2from
fix-initial-message
Open

fix(tui): preserve prompts during session hydration#36433
kitlangton wants to merge 1 commit into
v2from
fix-initial-message

Conversation

@kitlangton

@kitlangton kitlangton commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

What

Prevent the V2 TUI from dropping the first user prompt when a new Session opens while that prompt is promoted from pending work into projected history. The submitted prompt remains visible through initial hydration and reconnect hydration.

Closes #35988.

Before / After

Before

The Session row owner requested pending work and projected messages independently. Promotion could occur between those snapshots:

  1. Projected-history read observed the Session before promotion.
  2. The server atomically promoted the input, removing it from pending and adding it to projected history.
  3. Pending-work read observed the Session after promotion.
  4. Both responses omitted the input, and hydration replaced the live user row with an assistant-first transcript.

A gated OpenCode Drive reproduction now confirms that exact visible failure against the pre-fix parent: the real TUI shows the simulated assistant response and timing metadata, but no preceding user prompt.

After

One message-hydration operation owns the sequence: reconcile pending work first, then load projected history. Pending work is the only source of pending-input identity, and admissions/promotions received during either request are replayed over the snapshot. Projected hydration retains both the reconciled pending rows and live inputs received while history loads.

The identical gated Drive scenario passes against this branch and retains both transcript rows.

How

  • packages/tui/src/context/data.tsx keeps one authoritative pending store; session.input is derived rather than separately synchronized.
  • A small per-Session operation journal applies admissions, promotions, and committed reverts that arrive while pending work loads.
  • session.message.sync owns pending-first ordering, so callers cannot accidentally reintroduce parallel snapshot reads.
  • Live admission and hydration use the same pending-to-message projection.
  • packages/tui/src/routes/session/rows.ts invokes the single message hydration operation and relies on existing reactive row reduction.
  • Race tests cover promotion between pending/history snapshots and admission plus promotion during the pending request.

Scope

  • No server, protocol, persistence, or generated-client changes.
  • No temporary client-only message IDs.
  • No change to prompt delivery semantics or pending/queued styling.
  • The timing gates used to obtain deterministic Drive evidence were local diagnostic instrumentation and are not included in this PR.

Testing

  • bun run test from packages/tui: 267 passed, 1 skipped.
  • bun typecheck from packages/tui: passed.
  • Pre-push workspace typecheck: 32 packages passed.
  • Focused race differential:
    • Pre-fix parent: Expected: "user", Received: undefined.
    • This branch: both hydration race tests pass.
  • OpenCode Drive black-box differential using a real V2 server, TUI, simulated model, valid pending/history snapshots, and controlled response timing:
    • Pre-fix parent: fails on attempt 1 with initial message disappeared; final frame is assistant-first.
    • This branch: passes the identical scenario.

The Drive trace forced this valid production ordering:

  1. Input admitted.
  2. Projected history snapshots empty.
  3. Input promoted atomically from pending into history.
  4. The stale history response installs before assistant output.
  5. Assistant events append normally.

Flow

sequenceDiagram
    participant Events as Session events
    participant TUI as TUI data store
    participant Pending as Pending API
    participant Messages as Message API

    TUI->>Pending: Load pending work
    Events-->>TUI: Journal admissions/promotions/reverts
    Pending-->>TUI: Install snapshot with journal replayed
    TUI->>Messages: Load projected history
    Events-->>TUI: Retain live input rows
    Messages-->>TUI: Install projected + pending/live rows by durable ID
Loading

@kitlangton kitlangton changed the title fix(tui): preserve admitted messages during hydration fix(tui): hydrate pending session work Jul 11, 2026
@kitlangton kitlangton changed the title fix(tui): hydrate pending session work fix(tui): preserve pending session work Jul 11, 2026
@kitlangton
kitlangton force-pushed the fix-initial-message branch 2 times, most recently from d44a729 to 0b1662f Compare July 11, 2026 18:45
@kitlangton
kitlangton force-pushed the fix-initial-message branch from 37c017d to c78a0ba Compare July 15, 2026 19:06
@kitlangton kitlangton changed the title fix(tui): preserve pending session work fix(tui): preserve prompts during session hydration Jul 15, 2026
@kitlangton
kitlangton force-pushed the fix-initial-message branch from c78a0ba to 17753e6 Compare July 15, 2026 19:20
@kitlangton
kitlangton force-pushed the fix-initial-message branch from 17753e6 to 00ad2be Compare July 18, 2026 00:51
kitlangton added a commit that referenced this pull request Jul 18, 2026
Port of #36433 onto the quark timeline branch: pending operations journal, pending-derived inputs, and hydration that reappends admitted-but-unprojected prompts. Composed with part-collection reseeding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant