Skip to content

fix(client): reveal earlier agent turns in one load - #24417

Open
juliusmarminge wants to merge 5 commits into
mainfrom
fix/issue-21821
Open

juliusmarminge wants to merge 5 commits into
mainfrom
fix/issue-21821

Conversation

@juliusmarminge

Copy link
Copy Markdown
Member

Problem

When an older completed run was started by an agent and spanned several history pages, clicking “Load earlier turns” loaded only one slice into its collapsed activity group. Repeated clicks changed the “Worked for…” duration without revealing the run's opening message. Reproduced in the web dev app with a completed 532-row MCP-started run followed by ten human turns.

Change

The shared client history loader continues through activity-only pages until it reaches a user-message turn start, a visible notification, or the end of history. Each server request keeps its existing page budget. Loading and the active cursor stay consistent across later-page failures, retry, cancellation, and replacement snapshots. Targeted find navigation keeps its existing two-phase loading.

Scope and approval

Fixes #21821

GitCafe: #21821

Triaged bug via the automated issue flow; accepted by the maintainer on the linked issue. The change is limited to the shared client loader and focused regression tests.

Verification

  • Red test on main reproduced the missing opening turn after a single load-earlier request.
  • History sync tests: 39 passed, including multi-page loading, follow-up failure/retry, and stopping at a visible notification.
  • After merging main: 68 tests passed across history sync, atoms, controller, merge and server history paging.
  • Client-runtime typecheck passed. Targeted lint had no new findings; two pre-existing test warnings remain.
  • Integrated web dev app: one click reveals the agent opener. Literal two-run control already loads fully on main and remains unchanged.

Evidence report and scripts · Fixture matrix · Manifest and request traces.

Chrome 154/Linux integrated web, incognito, DPR 2, font 16px/100%, frozen clock, reduced motion. Viewports 1440×900 and 390×844 CSS; wide stills scaled full-frame to 1280×800, narrow stills 780×1688. Same synthetic data, theme and shared-content alignment; pointer parked away from controls. Each exact delivered still pair is pixel-identical at least 600ms apart. Diff0 retains all nonzero differences amplified 8×; DiffT marks maximum RGB channel difference >16/255. No masks or crops.

Visible changes are the opener replacing the earlier-history control, Worked duration/time, and navigator marks. Shared later content is aligned by scrolling head 16px. Narrow composer subtraction is zero; wide common-text raster edges include 51/light or 34/dark bottom-region pixels at at most 2/255. No renderer code changed. Full openers are unobscured in supplemental expanded stills and recordings.

1440light

Before — two-click recording · After — one-click recording

Before fef851b After 67c9f4b Diff0 ×8 DiffT >16
Before 1440light two clicks, opener absent After 1440light one click, opener loaded Unmasked Diff0 1440light Unmasked DiffT 1440light

Exact temporal stability:0 changed pixels in each base/head pair. Across revisions:15579 nonzero;3462 above16, of1024000. Bottom13%:51 nonzero pixels. Before second still · After second still · Unobscured full opener · Before newer turns · After newer turns · Expanded Worked.

After 1440light full opener below sticky fade

1440dark

Before — two-click recording · After — one-click recording

Before fef851b After 67c9f4b Diff0 ×8 DiffT >16
Before 1440dark two clicks, opener absent After 1440dark one click, opener loaded Unmasked Diff0 1440dark Unmasked DiffT 1440dark

Exact temporal stability:0 changed pixels in each base/head pair. Across revisions:15237 nonzero;3449 above16, of1024000. Bottom13%:34 nonzero pixels. Before second still · After second still · Unobscured full opener · Before newer turns · After newer turns · Expanded Worked.

After 1440dark full opener below sticky fade

390light

Before — two-click recording · After — one-click recording

Before fef851b After 67c9f4b Diff0 ×8 DiffT >16
Before 390light two clicks, opener absent After 390light one click, opener loaded Unmasked Diff0 390light Unmasked DiffT 390light

Exact temporal stability:0 changed pixels in each base/head pair. Across revisions:42081 nonzero;5803 above16, of1316640. Bottom13%:0 nonzero pixels. Before second still · After second still · Unobscured full opener · Before newer turns · After newer turns · Expanded Worked.

After 390light full opener below sticky fade

390dark

Before — two-click recording · After — one-click recording

Before fef851b After 67c9f4b Diff0 ×8 DiffT >16
Before 390dark two clicks, opener absent After 390dark one click, opener loaded Unmasked Diff0 390dark Unmasked DiffT 390dark

Exact temporal stability:0 changed pixels in each base/head pair. Across revisions:42043 nonzero;5465 above16, of1316640. Bottom13%:0 nonzero pixels. Before second still · After second still · Unobscured full opener · Before newer turns · After newer turns · Expanded Worked.

After 390dark full opener below sticky fade

Evidence was captured and audited at 67c9f4b5d8. The final head merges main; both changed files are identical to that audited head. Scoped tests were rerun after the merge.

Unverified coverage

Actual Electron, native iOS/Android, remote/relay/tunnel connections and the reporter's large-checkpoint fixture were not exercised. Responsive web captures do not certify native clients. Runtime fixtures for queued/steer boundaries, notification boundaries, opener-with-older-history, no-opener exhaustion, protocol edge flags, first-page disconnect, replacement during a later page and cancellation/remount were not captured. Notification stop and later-page failure/retry have focused unit coverage. Normal find navigation and forced later-page failure/retry have supplemental recordings in the full report; delayed targeted find/retry remains unverified.

Final proof audit: sufficient. Independent 390/light rebuild matched the delivered head capture exactly (zero changed pixels).

Models: Claude Opus 5.5 via Claude Agent (tests and implementation); GPT-6.1-Sol via Codex and Claude Opus 5.5 via Claude Agent (review); GPT-6.1-Sol via Codex (triage and evidence).

juliusmarminge and others added 4 commits October 24, 2026 11:12
…n agent run

One load-earlier request fetches a single history page, so a long agent
run takes several clicks before its opening turn appears.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g agent run

One Load earlier click fetched a single history page, so a run with more
rows than a page left its opening message absent for several clicks. A
plain load-earlier now keeps paging until a page holds a turn start or
history runs out. Find navigation keeps its single two-phase page.

Closes #21821

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The timeline shows every notification as a response boundary, so a page
containing one already reveals visible history, whether it opened its run
or arrived mid-run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 24, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 849d5da

Macroscope's review found this PR approvable — Earlier-history loading now recognizes agent-started turns and notifications while skipping steer-only boundaries. The change remains confined to existing history retrieval, with cursor, cancellation and failure safeguards unchanged.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

Earlier-history paging now stops when a page contains a turn-start item. Notifications and user messages other than steer or promoted_queued_to_steer count as turn starts. Tests cover these boundaries.

Changes: Thread history paging

Layer / File(s) Summary
Turn-start boundaries in history paging
packages/client-runtime/src/state/threads.ts, packages/client-runtime/src/state/threads-sync.test.ts
startsTurn recognizes notifications and user messages whose intent is neither steer nor promoted_queued_to_steer. Paging continues only when a page contains no turn-start item. Tests cover stopping after an agent-started turn or notification, and continuing across a steer.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related PRs

  • pingdotgg/t3code#26435: Both changes affect older-history page contents. This PR retains pending question and approval cards in bounded projections and restores missing cards during history merges.

Suggested reviewers: yash-singh1, maria-rcks

Merge Risk: Minimal · up to 849d5

The history-loading change is mergeable. In a narrow case involving a hidden notification from a superseded attempt, one click may not reveal an earlier visible turn.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title clearly and concisely describes the main fix: revealing earlier agent turns in one load. It uses a conventional commit format and is specific to the changeset.
Description check Passed The description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the reproduction, implementation, linked issue, approval basis, test results, evidence, an…
Linked Issues check Passed Issue #21821 requires one load-earlier action to continue through activity-only pages and reveal an earlier turn. In packages/client-runtime/src/state/threads.ts, startsTurn identifies notificatio…
Out of Scope Changes check Passed The pull request changes only the shared client history loader and its focused synchronization tests. The loader change directly implements issue #21821 paging boundaries. The tests validate the new s…
Full details: Description check

Explanation

The description includes complete Problem, Change, Scope and approval, and Verification sections. It explains the reproduction, implementation, linked issue, approval basis, test results, evidence, and unverified coverage.

Full details: Linked Issues check

Explanation

Issue #21821 requires one load-earlier action to continue through activity-only pages and reveal an earlier turn. In packages/client-runtime/src/state/threads.ts, startsTurn identifies notifications and user messages other than steer and promoted_queued_to_steer. The loader continues while no page item starts a turn and history remains. Focused tests cover an agent-started turn, a notification boundary, and continued paging through a steer.

Full details: Out of Scope Changes check

Explanation

The pull request changes only the shared client history loader and its focused synchronization tests. The loader change directly implements issue #21821 paging boundaries. The tests validate the new stopping and continuation behavior. No unrelated product area or behavior is shown in the reviewed diff.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

Note

This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.

Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between db7784f and 849d5da.

Files selected for processing: 2

  • packages/client-runtime/src/state/threads-sync.test.ts
  • packages/client-runtime/src/state/threads.ts

Limit details: You’ve used all 10 included reviews currently available.

@shivamhwp

Copy link
Copy Markdown
Collaborator

[gpt-6.1-sol][Codex] on behalf of shivam.

Handoff of #23760 findings from #23780 at 8fa5986, now that Julius owns the issue. These results concern heading virtualization, separate from this PR's history-loading change.

On Linux Chromium with a synthetic 464-message thread, main omitted the first loaded turn's heading from the DOM while scrolled to the end. Screen-reader heading navigation can only reach mounted headings. Folded automation prompts and agent messages also hid their headings.

The candidate fix kept the first and last loaded message rows mounted and moved folded-message headings outside the fold. A browser regression test with 120 messages failed on main and passed with the fix. In the integrated app, heading order was correct and scripted scrollIntoView jumps to both endpoints stayed there. Pinning alone left the last row at a stale position; it moved 1324px off screen after the jump. The web-only LegendList patch corrected that position.

Before capture, after at the end, jump to first, jump to last. Details and scroll measurements are in #23780.

vp run check:changed passed. Release Smoke failed on unused Expo patches, also reproduced on main. NVDA itself was not tested because no Windows machine was available. The fix covers loaded history only; fetching older turns remains a separate decision. Mobile was unchanged. The LegendList patch walks every loaded row's cached size on scroll to keep the last pinned row positioned, and that performance cost was not measured.

No new tests or pushes were started after the takeover notice.

Copy link
Copy Markdown
Member Author

Thank you for the thorough work on this. #26240 (d2429f733c) already makes a single load continue across activity-only pages. Please cut this down to the remaining boundary behavior: stopping at an agent-started turn or visible notification, which main currently skips while looking for a human message and can therefore over-fetch older history.

Main's load-earlier now pages until a human-authored message. Keep its
loop and apply this branch's stop rule: any turn-opening user message
(not steers) or a visible notification. Replace the branch's test with a
focused table next to main's paging test.

AI-assisted; verified with the tests and tools listed above.
@github-actions github-actions Bot added size:S 10-29 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Nov 11, 2026
@juliusmarminge

Copy link
Copy Markdown
Member Author

Evidence

Web app, Chromium, 1280×800, light theme, fresh synthetic databases on both commits. Create older human history, a completed long MCP-started replay run, and ten newer human turns. Reopen the bounded history and click Load earlier turns once.

Base fetches past the agent opener into older human history and exhausts history. Head reveals the agent opener and keeps older history behind Load earlier turns. Stills were stable across captures 500 ms apart; both recordings were visually inspected.

Before After
3a8c250cb0 849d5da997
Before: older human opener loaded and history exhausted After: agent opener revealed and earlier-history control retained
Single-click recording Single-click recording

Scenario file · Complete reproduction driver and recording setup

AI-assisted; verified with the tests and tools listed above.

Not shown:

  • Notification and steer boundary variants were not separately exercised; this proof covers the agent-authored opening-message boundary.
  • Desktop and mobile clients were not exercised; captures show the real web client.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Fix PR opened by an issue lead; enters the PR loop pr:gate-failed A land gate failed size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: "Load earlier turns" appears to do nothing while paging through a long agent-started run

2 participants