Files
kandev/docs/plans/transcript-task-switch-continuity/task-01-stabilize-task-switch-transcript.md
2026-09-05 16:18:21 +00:00

7.0 KiB

id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
id title status wave depends_on plan requirements acceptance_criteria system_design
01-stabilize-task-switch-transcript Stabilize task-switch transcript entry done 1
plan.md
REQ-UI-TRANSCRIPT-AUTO-SCROLL-001
REQ-UI-TASK-PROMPT-TRANSCRIPT-VISIBILITY-001
AC-UI-TRANSCRIPT-AUTO-SCROLL-001.11
AC-UI-TRANSCRIPT-AUTO-SCROLL-001.12
AC-UI-TRANSCRIPT-AUTO-SCROLL-001.13
AC-UI-TRANSCRIPT-AUTO-SCROLL-001.14
AC-UI-TASK-PROMPT-TRANSCRIPT-VISIBILITY-001.10
AC-UI-TASK-PROMPT-TRANSCRIPT-VISIBILITY-001.14
../../specs/ui/system-design/transcript-auto-scroll.md
../../specs/ui/system-design/task-prompt-transcript-visibility.md

Task 01: Stabilize Task-switch Transcript Entry

Summary

Place cached transcript rows at the incoming task's intended position before the latest-window refresh resolves. Reconcile the position afterward, and require current sentinel geometry before older-history pagination starts.

In scope

  • Add token-scoped provisional and final task-entry placement phases.
  • Use the incoming session's auto-scroll preference and saved position.
  • Preserve unread-divider, explicit-navigation, and layout-restore priority.
  • Keep older-history pagination blocked through final placement.
  • Validate current geometry on eligibility retry and stale-view handoff.
  • Add bounded development diagnostics.
  • Add TDD regressions and desktop/mobile Playwright coverage.

Out of scope

  • Changing unread-divider behavior, auto-scroll persistence, backend cursors, message page size, or task navigation UI.

Acceptance

  • With cached messages and auto-scroll enabled, switching tasks shows the incoming task's newest cached message before a held refresh response and the final newest message after release. The browser-default top is never exposed.
  • With auto-scroll disabled, the same flow uses the incoming session's saved reading position before and after refresh. It never reuses the outgoing transcript's offset.
  • Releasing the placement block or transferring a stale view cannot start pagination from an old observer entry. A sentinel currently inside the preload region still loads older history.
  • Desktop and mobile browser tests prove the cached-entry behavior, and request tracing proves task entry sends no unwanted older-page request.

Files likely touched

  • apps/web/components/task/chat/message-list-native-scroll.ts
  • apps/web/components/task/chat/message-list-native.tsx
  • apps/web/components/task/chat/message-list-native.test.tsx
  • apps/web/components/task/chat/transcript-auto-scroll.ts
  • apps/web/components/task/chat/transcript-auto-scroll.test.ts
  • apps/web/hooks/use-lazy-load-sentinel.ts
  • apps/web/hooks/use-lazy-load-sentinel.test.ts
  • apps/web/hooks/domains/session/use-session-messages.ts
  • apps/web/hooks/domains/session/use-session-messages.test.ts
  • apps/web/e2e/helpers/ws-response-hold.ts
  • apps/web/e2e/tests/chat/auto-scroll-toggle.spec.ts
  • apps/web/e2e/tests/chat/mobile-auto-scroll-toggle.spec.ts

The response-hold helper is optional. Keep the WebSocket control local to a single test file if it is not shared by both viewport suites.

Verification

Follow TDD. Run the new focused tests before the production change and record the expected failures. Then run:

(cd apps && pnpm --filter @kandev/web test -- --run hooks/use-lazy-load-sentinel.test.ts components/task/chat/message-list-native.test.tsx components/task/chat/transcript-auto-scroll.test.ts hooks/domains/session/use-session-messages.test.ts)
(cd apps/web && pnpm run typecheck)
(cd apps/web && pnpm exec eslint hooks/use-lazy-load-sentinel.ts hooks/use-lazy-load-sentinel.test.ts components/task/chat/message-list-native-scroll.ts components/task/chat/message-list-native.tsx components/task/chat/message-list-native.test.tsx components/task/chat/transcript-auto-scroll.ts components/task/chat/transcript-auto-scroll.test.ts hooks/domains/session/use-session-messages.ts hooks/domains/session/use-session-messages.test.ts e2e/helpers/ws-response-hold.ts e2e/tests/chat/auto-scroll-toggle.spec.ts e2e/tests/chat/mobile-auto-scroll-toggle.spec.ts)
(cd apps/web && pnpm e2e:run --host --project chromium tests/chat/auto-scroll-toggle.spec.ts -- --grep "environment-changing task switch" --retries=0)
(cd apps/web && pnpm e2e:run --host --no-build --project mobile-chrome tests/chat/mobile-auto-scroll-toggle.spec.ts -- --grep "task switch" --retries=0)
python3 scripts/lint-spec-files.test.py
python3 scripts/lint-spec-files.py --all
git diff --check

If the optional helper is not created, omit it from the ESLint command. If the managed Playwright runner does not accept --no-build after the desktop run, remove only that flag and keep the same mobile project and grep.

Dependencies

None.

Parallelism

sequential. This task owns the shared placement and pagination lifecycle.

Risks

  • Do not clear the switch token during provisional placement.
  • Do not let provisional placement override an unread-divider target.
  • Re-resolve the live scroll element and session before every deferred write.
  • Keep the geometry predicate optional for non-transcript sentinel consumers.
  • Assert geometry while the refresh is held. An eventual-bottom assertion does not detect the visible top flash.

Mobile design contract

  • Use the current mobile task switcher and full-height Chat tab.
  • Keep the transcript as the only vertical scroll owner.
  • Keep the existing header, composer, touch targets, and safe-area geometry.
  • Exercise the same cached-entry and final-reconciliation contract as desktop.
  • Prove the task view has no horizontal document overflow after both phases.

Output contract

Report the red and green evidence, placement ownership changes, sentinel geometry rule, changed files, desktop/mobile browser results, and remaining risks. Update this work order and plan.md with implementation results in the same conversation.

Results

  • Added token-scoped provisional and final transcript placement. Cached enabled transcripts place at the bottom before refresh; cached disabled transcripts use the incoming session's saved position. Final placement reconciles current rows and clears only the matching token.
  • Preserved unread-divider, layout-restore, explicit-navigation, and programmatic-scroll ownership.
  • Added current-geometry checks to sentinel eligibility retry and stale-view handoff. Consumers without a geometry predicate retain their previous behavior.
  • Added a correlated WebSocket latest-window response hold for browser tests. Desktop and mobile tests exercise both enabled and disabled cached returns. Desktop request tracing also proves no older-page HTTP request starts during placement release.
  • Red evidence: four focused unit assertions failed on the old behavior. The desktop E2E remained 1,892 px from the bottom while refresh was held.
  • Green evidence: 142 focused unit tests passed; targeted ESLint and typecheck passed; focused Chromium and mobile-chrome runs each passed one test with retries disabled; specification lint and diff checks passed.