Skip to content

fix(tui): order live transcript by message created time so wrapped ids stay visible - #13247

Merged
johnnyeric merged 2 commits into
mainfrom
johnnyeric/tui-message-time-order
Aug 20, 2026
Merged

fix(tui): order live transcript by message created time so wrapped ids stay visible#13247
johnnyeric merged 2 commits into
mainfrom
johnnyeric/tui-message-time-order

Conversation

@johnnyeric

@johnnyeric johnnyeric commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What

The TUI live transcript hides new turns in long-running sessions whose message IDs crossed the 48-bit timestamp wrap on 2026-08-14. Persistence is fine — quitting and reopening shows the missing work — only the live store drops it.

For context I resumed a session from 2 weeks before and it got stuck without streaming anything and the only visible movement was the spinner. With the fix, the same session resumed correctly.

Screenshots

Before

Old session resumed: Session stuck after I sent "Continue"

Screenshot 2026-08-20 at 12 33 49

After

Old session resumed: Session streaming after I sent "Continue"

Screenshot 2026-08-20 at 12 33 19

Why

packages/opencode/src/id/id.ts encodes Date.now() * 0x1000 + counter in 48 bits, wrapping roughly every 795 days. Wrap 25 ended 2026-08-14 13:19:55; new IDs restarted at msg_000…/msg_019…. The TUI sync store (packages/tui/src/context/sync.tsx) inserted messages by binary search on id and evicted list[0] as "oldest" when the 100-message window overflowed. After the wrap, a new msg_019f… sorts before an old msg_ff0c…, so every new turn inserted at index 0 and was immediately evicted. Hydration over HTTP orders by time_created, which is why reopening looked correct (observed in ses_023cb4401ffe2R9oTrbp7nj9Hz, 606 messages spanning the wrap).

This also closes a second latent bug: after hydration the list was time-ordered but binary-searched as if id-ordered, so a lookup could miss an element that was present — message.updated could insert a duplicate entry and message.removed could fail to remove one. The linear id lookup eliminates both.

How

Ordering logic lives in a new kilo-owned helper, packages/tui/src/kilocode/message-order.ts, ordering by time.created with id as tiebreaker (matching the server's canonical (time_created, id) order):

  • older(a, b) — comparator by created time, then id
  • slot(list, item) — insert/update index by created time
  • at(list, id) — linear id lookup (the list is no longer id-sorted)
  • recent(list, cap = 100) — newest-by-created window

sync.tsx changes are limited to five marked call-site swaps: message.updated / message.updated.1 insert via slot, message.removed / message.removed.1 look up via at, and the hydrate window uses recent instead of slice(-100).

Tests live in packages/tui/test/kilocode/: unit coverage for the helper plus sync-store tests asserting a later msg_019f… emitted after an older msg_ff0c… stays at the tail (on both the plain and versioned sync channels) and that eviction at the 100-message cap drops the oldest message, not the newest.

Known remaining limitation, out of scope here: a few upstream-owned render-layer sites in packages/tui/src/routes/session/index.tsx still compare message ids lexicographically as a proxy for chronology (queued styling, revert boundaries for undo/redo/copy). Those are pre-existing and unaffected by this change.

@johnnyeric
johnnyeric marked this pull request as ready for review August 20, 2026 10:36
@kilo-code-bot

kilo-code-bot Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (5 files)
  • .changeset/tui-message-time-order.md
  • packages/tui/src/context/sync.tsx
  • packages/tui/src/kilocode/message-order.ts
  • packages/tui/test/kilocode/message-order-sync.test.tsx
  • packages/tui/test/kilocode/message-order.test.ts

Reviewed by grok-4.6 · Input: 242.3K · Output: 30.8K · Cached: 322.4K

Review guidance: REVIEW.md from base branch main

@johnnyeric
johnnyeric merged commit 0d5d334 into main Aug 20, 2026
31 checks passed
@johnnyeric
johnnyeric deleted the johnnyeric/tui-message-time-order branch August 20, 2026 12:05
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.

2 participants