Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
9.2 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||||
|---|---|---|---|---|---|---|---|---|
| 2026-08-28 | completed |
|
|
Implementation Plan: Threads Multi-session Windowing
Overview
Extend the contributor Threads view so each task column can switch among its existing agent sessions without adding management actions or another header row. Correct the question icon so only an explicit clarification or permission means that a person must act. Bound expensive conversation work by the horizontal viewport: task shells stay stable, nearby session lists preload, and only the selected session in a visible column owns a transcript and full session subscription.
This package targets PR #3112. It preserves the contributor's first-class Threads route, stable task order, shared composer path, task-page round trip, and mobile snap-paged deck.
Scope
In scope
- A compact, workspace-scoped per-session pending-action event with revision ordering and no transcript content.
- Stable task shells with separate preload and detail activation windows.
- One selected transcript subscription per visible desktop task column and one total selected transcript on phone.
- Column-local session selection, exact task/session deep links, and deterministic fallback when membership changes.
- Desktop switch-only tabs on the right of the existing metadata row.
- A phone pill and bottom-sheet session picker with 44-pixel rows.
- Correct clarification, permission, working, turn-finished, and review-ready status semantics.
- Unit, component, desktop E2E, mobile E2E, and WebSocket traffic evidence.
Out of scope
- Session creation, deletion, rename, reorder, pin, primary-session mutation, or persistence of Threads selection.
- Full task-shell DOM virtualization.
- Task status summary session arrays or transcript projections.
- Changes to the task workbench's global active-session behavior.
- Plugin API changes.
Technical approach
Compact sibling status
Keep session.message.* events session-scoped. Add
session.pending_action_changed as a workspace-scoped semantic event derived
from the current authoritative pending-action projection. Reuse
pending_action_revision for cross-channel stale-event rejection. Route the
event fail-closed by workspace and merge it into the existing compact
TaskSession store fields. Existing global session.state_changed continues
to supply lifecycle and foreground activity.
Viewport activation
Keep all ActiveThread task shells mounted so stable order, flexible column
width, horizontal scroll, deep-link focus, and accessibility order do not
change. Add an IntersectionObserver rooted at ThreadsBoard.
- The preload set contains intersecting desktop columns plus one adjacent
column on each side. It mounts
useTaskSessionsonly. - The desktop detail set contains intersecting columns. It mounts one
TaskChatPanelfor each column's selected session. - The phone detail set contains only the nearest snapped column. The next column can preload membership but cannot subscribe to messages.
- Leaving the detail set unmounts the selected chat and releases its session registration. The task shell and local session selection remain.
A component test with 30 task shells is the main resource-bound oracle. It asserts that initial session-list and chat mounts follow the two viewport sets, not the task count.
Session selection and presentation
Load session membership through useTaskSessions only after preload
activation. Build a pure session view model from existing session sort/profile
helpers and compact pending status. Keep selected IDs in Threads-local state
keyed by task ID.
Desktop renders switch-only SessionTabs in the right side of the existing
metadata row. The right region scrolls internally if names do not fit. Do not
pass add, close, context-menu, double-click, drag, or management callbacks.
Phone renders a MobilePillButton in the same metadata row and a
MobilePickerSheet for the session list. This avoids a nested horizontal tab
gesture inside the horizontally paged task deck.
ThreadConversation continues to omit onSend, so TaskChatPanel owns queue
mode, model, plan mode, context, attachments, optimistic insertion, and send
reconciliation.
Status semantics
Use a shared pure helper with explicit precedence: permission, clarification,
starting, working, terminal error, then neutral settled state. Never infer a
question from WAITING_FOR_INPUT. Use task review outcome for the
Ready for review completion treatment. Task-wide pending action can rank or
decorate a task shell, but only compact per-session projection can decorate a
specific tab.
Add every new label to all five locale catalogs. Generate Traditional Chinese
translations with the existing i18n:zh-hant workflow when implementation
adds the keys.
Tests
| Acceptance criteria | Evidence |
|---|---|
AC-PLATFORM-VIEWPORT-SESSION-DELIVERY-002.1 through .6 |
Backend event routing/payload tests and frontend revision-aware reducer tests. |
AC-PLATFORM-VIEWPORT-SESSION-DELIVERY-001.1 through .6 |
Controllable IntersectionObserver component tests with 30 shells and mocked conversation/list mounts. |
AC-UI-THREADS-DECK-001.1 through .7 |
Pure selection tests, component switcher tests, and desktop task/session deep-link E2E. |
AC-UI-THREADS-DECK-002.1 through .6 |
Status precedence unit matrix plus inactive-tab live-update E2E. |
AC-UI-THREADS-DECK-003.1 through .3 |
Thirty-shell component budget and desktop scroll/subscription E2E. |
AC-UI-THREADS-DECK-003.4 through .7 |
Mobile picker component tests and mobile-chrome geometry, touch, failure, and scroll assertions. |
E2E tests
- Extend
apps/web/e2e/tests/task/threads-view.spec.tswith one real primary session plus existing test-harness sibling sessions. Verify same-row tabs, switch-only controls, selected transcript changes, inactive-tab status, exacttaskIdplussessionIdround trip, and stable task-column order. - Add a multi-column traffic scenario that records outgoing WebSocket actions.
Verify initial
session.subscribeIDs equal selected sessions in visible columns, unselected sibling IDs never subscribe, scrolling activates the new selected session, and the departed offscreen session unsubscribes. - Extend
apps/web/e2e/tests/task/mobile-threads-view.spec.tswith a multi-session task. Verify one snapped detail owner, the metadata-row pill, bottom-sheet selection, 44-pixel rows, status parity, safe-area containment, and zero document overflow. - Keep the exact 30-task resource bound in deterministic component coverage. The E2E fixture does not need to run 30 real agent turns to prove the same mount and subscription invariant.
Mobile design contract
- Desktop outcome: compact existing-session tabs share the metadata row; visible columns can each show one selected conversation.
- Mobile entry and hierarchy: the task deck remains horizontally snap-paged. A compact session pill in the metadata row opens a bottom sheet.
- Surface rationale: a bottom sheet avoids nested horizontal gestures and gives long labels and status text a full-width 44-pixel row.
- Scroll ownership: the board owns horizontal task paging; the picker owns vertical session scrolling; the transcript owns its internal vertical scroll. The page document gains no horizontal overflow.
- Shared behavior: membership, selection fallback, session status, and conversation submission are shared. Only the selector presentation and phone detail-window rule differ.
- Mobile proof: mobile-chrome validates one active detail, picker geometry, touch targets, status parity, safe area, and zero document overflow.
Work orders
- Task 01: Publish compact session attention
- Task 02: Activate task columns from the viewport
- Task 03: Add the Threads session switcher
- Task 04: Prove the Threads resource budget
All work orders are sequential. They share event types, task-session state, Threads components, and E2E fixtures, so this plan has no parallel-safe implementation candidates.
Risks
- A pending-action event must not broaden delivery of message content. Assert the exact payload and workspace routing.
- React effect cleanup during fast horizontal scroll can briefly overlap old and new chat mounts. Assertions must permit transition overlap only while guaranteeing the settled subscription set.
- A partially visible phone neighbor must not become a second detail owner. Use the nearest snap target instead of raw intersection on phone.
- A task-wide pending action has no session identity. Never assign it to the primary tab before the task-session list identifies the owner.
- Many compact tabs can compete with metadata. Keep one row, bound the right region, and test long labels at compact desktop widths.