Skip to content

fix(chat): keep the working indicator on a thread opened mid-turn - #554

Merged
Tryanks merged 1 commit into
mainfrom
fix/running-indicator-on-open
Sep 30, 2026
Merged

Tryanks merged 1 commit into
mainfrom
fix/running-indicator-on-open

Conversation

@Tryanks

@Tryanks Tryanks commented Sep 30, 2026

Copy link
Copy Markdown
Owner

Behaviour

Opening a running thread (most often on a phone) sometimes showed no working indicator or timer at the bottom of the chat until the turn ended.

Cause

Two independent paths left the selected session's timeline replica not running while the host's status said the turn ran:

  1. Status settled after the fold. The snapshot fold calls mark_idle unless the status replica says turn_running. On selection that replica is the status cached from the last visit, and status and events are separate topics (reconnect resubscribes from a HashMap, so either can arrive first). A fold settled by a stale idle status stayed idle when the fresh running status arrived, since nothing re-evaluated it.
  2. Window cut inside the running turn. session_events_snapshot bounds the window by bytes from the tail, so a large running turn can be cut after the record that opened it. The client's fold of that window has no TurnStarted, so the turn neither runs nor has a start time, and if the tail already covers enough screens no earlier page is ever requested.

Fix

  • fold_held_records is the one place that folds held records and applies the status (previously duplicated in the snapshot and history-page handlers).
  • reconcile_replica_liveness: when the selected status's turn_running changes, the replica is idled in place, or refolded when it must come back to life (mark_idle discarded the live turn's state).
  • running_turn_opening_unheld: while the status runs and the replica holds only a partial, non-running turn, earlier history pages load until the turn's start arrives, so the timer counts from the real start.

Test

  • status_arriving_after_the_snapshot_settles_the_running_turn: a stale idle status, a snapshot with TurnStarted, then a running status; the last turn runs from the TurnStarted time, and an idle status afterwards stops it.
  • a_window_cut_inside_the_running_turn_loads_back_to_its_start: a snapshot window without the turn's start requests the earlier page; once it arrives the turn runs from its start.

Both fail with the fix disabled.

Checks run

  • cargo fmt --all --check
  • cargo clippy -p tcode-ui --all-targets --locked -- -D warnings
  • cargo nextest run -p tcode-ui --locked (322 passed)

Full workspace tests and the mobile/Web checks are left to CI. Not exercised on a real phone.

Opening a running thread sometimes showed no working indicator or timer
until the turn ended. Two causes:

- The snapshot fold marks the replica idle unless the status replica says
  the turn runs. Status and events are separate topics (and reconnect
  resubscribes in hash order), so the fold could be settled by the stale
  status cached from the last visit; the fresh running status never
  revived it. A change of the selected status's turn_running now idles the
  replica in place or refolds the held records.
- A snapshot window is byte-bounded from the tail, so a large running turn
  can be cut after the record that opened it, leaving a fold that neither
  runs nor times the turn. While the status runs and the replica holds only
  that partial turn, earlier pages load until the turn's start arrives.
@Tryanks
Tryanks merged commit a1c42d4 into main Sep 30, 2026
7 checks passed
@Tryanks
Tryanks deleted the fix/running-indicator-on-open branch September 30, 2026 10:55
yermakoffivan pushed a commit to yermakoffivan/tcode that referenced this pull request Sep 30, 2026
A client folds a byte-bounded window of a session's log and used to decide
liveness itself: mark_idle unless the status said the turn ran. That lost
the pending question and the working indicator whenever a stale cached
status settled the fold, and Tryanks#554 patched it with a refold on every
running flip plus back-to-back history pages until the running turn's
start arrived, downloading the whole running turn (often several MB).

The host already holds the complete fold and knows whether its provider
is live, so SessionStatus now carries the running turn (its index in the
whole log and start time), the pending approvals and the pending
question, gated on an in-flight turn. The client folds held records
purely and settles which held turn runs from the status, in place and
without discarding anything, whenever either topic changes. An unready
plan is hidden while its turn is not running instead of being discarded.

PROTOCOL_VERSION 7.
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