feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: paginate thread loading with user-anchored turn windows - #5493

Merged
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading
Aug 7, 2026
Merged

feat: paginate thread loading with user-anchored turn windows#5493
t3dotgg merged 13 commits into
mainfrom
t3code/paginate-thread-loading

Conversation

@t3dotgg

@t3dotggt3dotgg commented Aug 6, 2026

Copy link
Copy Markdown
Member

Problem

Long threads are heavy to open, especially on mobile. The heaviest observed thread (161 turns, 23k activities) ships 8.4MB of JSON on every open, all of which must be parsed, held in client state, and persisted to the mobile cache. On many-turn threads, the most recent 10 turns are only 2-6% of the bytes.

Solution

Opt-in pagination of the thread detail snapshot, cut on user-anchored turn boundaries:

  • Server: GET /api/orchestration/threads/:id accepts turnLimit + beforeCursor. The window is everything from the Nth-last turn-with-a-user-pending-message onward, so subagent/fan-out turns ride along and the first page always contains the last N user prompts (verified against real data: fan-out bursts run 35+ consecutive subagent turns). Responses carry page: { beforeCursor, hasMore, snapshotSequence } with an opaque exclusive cursor returning disjoint older slices. A 150-raw-turn ceiling bounds pathological fan-out. The WS fallback snapshot honors the same opt-in via the subscription input.
  • Compatibility: pagination is strictly opt-in and capability-gated (threadSnapshotPagination in server config). Old client + new server and new client + old server both keep full-snapshot behavior.
  • Shared client state: initial loads request the last 10 user turns; loadOlderTurns fetches 20 more per call. Consistency rules: a fresh snapshot replaces all loaded history (no stale-revert resurrection), in-flight pages are discarded when a revert/snapshot/deletion rewrites history or when the page was read from a projection behind the loaded state, and merged pages never advance the live-event dedupe sequence. All covered by state-machine tests.
  • UI: a plain "Load earlier turns" header row on web and mobile; LegendList's maintainVisibleContentPosition anchors scroll on prepend.

No schema migration: the migration-029 indexes cover the bounded queries (verified with EXPLAIN QUERY PLAN against a 45k-activity fixture; worst-case bounded reads run in single-digit ms).

Measured on the heaviest real thread: initial fetch drops from 8.4MB to 1.0MB wire (~1/8th), and a full page-by-page walk reproduces the exact row set of an unwindowed fetch with zero overlap between pages.

Testing

  • 7 new server tests for window resolution, cursor semantics (foreign/malformed cursor degradation, disjointness/coverage walk), and the turnless-thread edge case
  • 7 new client state-machine tests for the race rules
  • Full server (1880) and client-runtime (615) suites green; typecheck and lint clean across the workspace
  • Live smoke against the seeded worktree db: windowed first page returns exactly the last 10 user messages with hasMore, older pages are disjoint, full walk covers all 815 messages

Implemented by Claude Fable 5 via Claude Code.

🤖 Generated with Claude Code


Note

Medium Risk
Touches core thread sync, projection queries, and cache semantics; mistakes could drop history, duplicate streaming text, or serve wrong pages, but behavior is opt-in, capability-gated, and heavily tested.

Overview
Adds opt-in, capability-gated thread detail pagination so long threads open with a small recent window instead of the full history.

Server exposes turnLimit and beforeCursor on HTTP thread snapshots and WS subscribe fallbacks. Windowing walks back user-anchored turns (subagent turns ride along), returns page metadata with an opaque keyset cursor, and uses a new projection_turns keyset index. Malformed or foreign cursors degrade to the first page.

Client-runtime loads the last 10 user turns initially and fetches 20 more per “load earlier” via requestOlderThreadTurns, with epoch/lock/watermark rules so reverts, fresh snapshots, and stale pages cannot corrupt merged history. Thread cache schema bumps to v3 so old clients cannot treat a partial window as complete.

Web and mobile show a Load earlier turns control in the thread feed when hasMore is set.

Reviewed by Cursor Bugbot for commit 95cd34a. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Paginate thread loading with user-anchored turn windows on client and server

  • Adds windowed thread snapshot loading to the server (ProjectionSnapshotQuery, HTTP and WS handlers), returning only the last 10 user-anchored turns initially and supporting cursor-based older-page fetches of 20 turns at a time.
  • Extends EnvironmentThreadState with pagination state (page, loadingOlder, hasMore, cursor) and adds requestOlderThreadTurns / threadHasOlderTurns helpers in the client-runtime state machine.
  • Introduces a semaphore (applyLock) and epoch/watermark guards in the thread state machine to prevent stale or interleaved older-page merges from corrupting live history.
  • Surfaces a "Load earlier turns" header control in both the web (MessagesTimeline) and mobile (ThreadFeed) UIs, wired to requestOlderThreadTurns and reflecting loading state.
  • Adds a new DB migration (037_ProjectionTurnsKeysetIndex.ts) creating a composite keyset index on projection_turns(thread_id, requested_at, turn_id) to support efficient paginated queries.
  • Bumps the thread snapshot cache schema version from 2 to 3; existing v1/v2 cached entries will fail to decode and trigger a full reload.
  • Risk: clients connected to servers that do not advertise threadSnapshotPagination in ServerConfig will have any windowed cache discarded and reload the full thread history.

Macroscope summarized 95cd34a.

@coderabbitai

coderabbitaiBot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ec277cf-6f61-408f-a3c7-14e9c2edeaaa

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Aug 6, 2026

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect service conventions review of the changed TypeScript. One finding: the new UI-to-state-machine channel in packages/client-runtime/src/state/threads.ts routes through mutable module-global state instead of the Effect environment. Server-side additions (threadDetailCursor.ts, windowed ProjectionSnapshotQuery queries, contract/schema additions) follow the import, error, and dependency-acquisition conventions; test harnesses pass service instances explicitly, which is an allowed test seam.

Posted via Macroscope — Effect Service Conventions

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts
@macroscopeapp

macroscopeappBot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces a substantial new pagination feature for thread loading with complex state management, new API parameters, and multi-platform UI changes. Additionally, there is an open bug report about the loading state getting stuck on disconnect. Human review is appropriate for this scope.

No code changes detected at 95cd34a. Prior analysis still applies.

You can customize Macroscope's approvability policy. Learn more.

Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts Outdated
@t3dotgg
t3dotggforce-pushed the t3code/paginate-thread-loading branch from d4c55c3 to 2c8a2e3CompareAugust 6, 2026 21:16
Comment threadpackages/client-runtime/src/state/threadSnapshotHttp.ts
Comment threadapps/server/src/orchestration/threadDetailCursor.ts Outdated
Comment threadpackages/client-runtime/src/state/threads.ts
@github-actionsgithub-actionsBot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Aug 7, 2026
const pendingOlderPage = yield* Ref.make<{
readonly snapshot: OrchestrationThreadDetailSnapshot;
readonly epoch: number;
} | null>(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parked page sticks loading offline

Medium Severity

The pendingOlderPage state, which holds a parked page and keeps loadingOlder true, isn't cleared when the connection disconnects or encounters a stream error. This leaves the UI stuck on "Loading earlier turns..." and prevents subsequent attempts to fetch older history.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit 9bc5966. Configure here.

t3dotggand others added 13 commits August 6, 2026 18:50
…n pages
Adds opt-in pagination to thread detail reads. A windowed request returns
everything from the Nth-last user-anchored turn onward (subagent/fan-out
turns ride along) plus page metadata with an opaque exclusive cursor for
disjoint older slices. Requests without a window keep the full-snapshot
behavior on both HTTP and the WS fallback, so pre-pagination clients are
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clients gate window requests on threadSnapshotPagination in the server
config, so new clients never send window fields to pre-pagination servers.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ge merges
Thread state gains page metadata and a loadOlderTurns flow implementing the
consistency rules: fresh snapshots replace all loaded history, in-flight
older pages are discarded when a revert/snapshot/deletion rewrites history
(epoch check) or when the page was read from a projection behind the loaded
state, and merged pages never advance the live-event dedupe sequence.
Windowed loads are gated on the server's threadSnapshotPagination
capability; servers without it keep full snapshots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both timelines gain a plain load-more row as the list header, driven by the
shared thread state's page metadata. LegendList's
maintainVisibleContentPosition anchors the scroll position on prepend.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext.Reference
Effect Service Conventions check flagged the module-global handler Map as
hiding the UI-action-to-state-machine dependency. The registry is now a
Context.Reference the machines resolve from the environment (overridable
in tests), with a shared default instance backing the sync
requestOlderThreadTurns entry point so app wiring is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…omic page merges
Addresses three review findings on the pagination PR:
- Stale cursors after revert (high): the server's revert projector rewrites
projection_turns row ids, invalidating the stored page cursor. On a
windowed thread, a revert now triggers a fresh windowed snapshot fetch
(sequence-checked so a lagging projection cannot resurrect reverted
turns), minting a valid cursor.
- Windowed cache vs pre-pagination server (medium): resuming a windowed
cache via afterSequence against a server without threadSnapshotPagination
would render only the window forever. The subscription now drops the
windowed cache and takes a full snapshot; loadOlderTurns is gated on the
capability so window params are never sent to old servers.
- Epoch TOCTOU (medium): staleness check and page merge now run under the
same semaphore as stream-item application, closing the window where a
revert could land between check and merge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…te update
The merge previously read the loaded thread outside SubscriptionRef.update
and committed the result inside it, so a concurrent setThread between read
and commit could be overwritten. The merge now composes with the value the
update callback receives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ility, no-op refresh when fully loaded
Second round of review findings on the revert-refresh path:
- The refresh's staleness check and snapshot application now share one
applyLock acquisition (via applyItemLocked), so a live event cannot
advance lastSequence between check and apply and be swallowed by a
regressing watermark.
- paginationSupported is reset on disconnect: the capability belongs to
the session that advertised it, and a stale true during reconnect could
send window params to a newly prepared pre-pagination server.
- The post-revert refresh is skipped when hasMore is false: there is no
cursor to re-mint and the refresh would discard already-merged older
pages for nothing. The revert reducer's own filtering handles history.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Third-party review round on the pagination design:
- Cursors are now an (anchor timestamp, turn id) keyset instead of
projection_turns.row_id. Row ids are rewritten by the revert projector
and by projection rebuilds, silently invalidating persisted cursors;
the keyset is derived from event content and survives both. This
deletes the client's entire revert-refresh machinery (refresh queue,
refreshWindowedSnapshot, revert-triggers-refresh wiring) — the revert
reducer's turn filtering is sufficient on its own. Pinned by a server
test that rewrites all turn row ids and re-pages with the old cursor.
- Thread cache schema bumped to 3 on web and mobile (rollback safety): a
pre-pagination client would decode a windowed v2 record, silently drop
the unknown page field, and treat the partial thread as complete
forever. v3 records fail its literal match and cold-load instead.
- The window query applies the keyset bound and 150-turn LIMIT in a
candidates CTE before the window functions run, so a page over a huge
thread scans a bounded number of turns instead of every older turn.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The anchor is COALESCE(requested_at, started_at, '') and the turn key is
COALESCE(turn_id, ''), so a server-minted cursor can legitimately carry
empty strings; the decoder rejected them as malformed, degrading a valid
cursor to a first-page request that repeats recent history. Adds a codec
test file covering round-trips (including empty boundaries) and malformed
input.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two blockers from external review:
- Pages now carry threadSequence, the highest thread-detail event sequence
applied at read time (filtered to the exact event types the subscription
delivers, so the watermark is always reachable). A page read ahead of the
client's live state parks until events catch up, closing the race where a
streaming turn outside the loaded window had its deltas replayed on top
of page content that already included them, duplicating text. Pages from
pre-watermark servers merge immediately (old behavior).
- The window query's candidates CTE now orders by raw
(requested_at, turn_id) — requested_at is NOT NULL by schema — and
migration 037 adds a (thread_id, requested_at, turn_id) index, so the
keyset range and order are both index-served with no temp B-tree: the
scan is genuinely bounded by the page LIMIT. Keyset comparisons keep
COALESCE only on the turn_id tiebreak, which does not affect index use.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 15, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
darjss pushed a commit to darjss/t3code that referenced this pull request Aug 26, 2026
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 28, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 29, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Aug 30, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 1, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
…eysetIndex
Main owns migration numbering: 037_ProjectionTurnsKeysetIndex landed on
main (#5493), so the v2 migrations shift from 037-045 to 038-046.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
juliusmarminge added a commit that referenced this pull request Sep 2, 2026
Native subagent observability (#5219), wired per its spec's v2 merge plan:
- getWorkflowScript RPC re-homed onto the v2 WS surface (contracts, rpc
group, ws handler, auth scope, client atom).
- AgentsPanel fed by the spec's mapper swap: projectedSubagentsToRuntime
maps orchestration-v2 subagent entities into the panel model;
deriveAgentPanelModel's v2Projection leg is now live and the v1 fold
never runs. Agents surface wired into ChatView + RightPanelTabs.
Other ports and reconciliations:
- Shell reconnect-loop fix (#5561) ported into the v2 shell sync
(same-session resubscribes resume from the in-memory cursor), with the
cursor-resume regression test adapted to v2 fixtures.
- Mobile end-follow latch (#5566) ported onto the v2 ThreadFeed.
- Claude ede_diagnostic interrupt classification (#5557) ported into
ClaudeAdapterV2 (aborted_tools/aborted_streaming => interrupted; CLI
telemetry never becomes the failure banner). #5559 needs no v2 port
(unknown system subtypes are already ignored).
- Plan sidebar removed from the v2 ChatView/ChatComposer per main's
plans-fold-into-chat rework (#5558); rightPanelStore stays at main's
surface set.
- SettingsPanels rebuilt as main's refactored version plus the branch's
composer-context setting; sidebar snooze respects the time format
(#4438 follow-through).
- v1-only leftovers deleted: zombie v1 adapters/ingestion/tests the v2
rewrite removes, the v1-bound transfer-budget CI harness (#5350, needs
a v2 rebuild), and main's v1 client pagination machinery (#5493 client
side; the 037 keyset migration is kept — server-side v2 windowing is a
follow-up).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@t3dotgg