refactor(chat): move ChatPage session identity into a controller hook - #9072
Conversation
|
Local gate run for
|
UX Review (Fable 5) — ✅ PASSUX-level review of This is a pure logic refactor — ~550 lines of session-identity state management moved verbatim from UX-Verdict: PASS Pure code move — no user-visible control, string, or state changes; nothing for a first-time user to encounter differently. [UX-REVIEWED] 0b11264 |
Design Review (Fable 5) — ✅ PASSDesign-level review of Design-Verdict: PASS A mechanical, order-preserving extraction following the established controller-hook precedent, with source-contract and characterization tests pinning the moved seam — sound slice design. [DESIGN-REVIEWED] 0b11264 |
Opus 4.8 Review — ✅ no blocking findingsReviewed Review detailsI've verified the extraction is clean:
The candidate list correctly found nothing, and my own falsification pass produced no grounded defect meeting (a)/(b)/(c). No findings. [OPUS-REVIEWED] 0b11264 Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 5.6 Review — ✅ no blocking findingsGPT 5.6 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
First Principles Review (Fable 5) — ✅ PASSPremise-level review of All claims verified: the code-style ban on ticket ids is real ( First-Principles-Verdict: PASS A pure code move with declared mechanical adaptations; every rider is either mandated by a documented invariant or derived from a measured CI constraint. What this change shipsIntent: make the 10k-line ChatPage reviewable by CI's one-pass review lane by slicing out its session-identity block — a FIX to a process constraint, executed as a move.
Counts run: hook consumers = 1 ( [FIRST-PRINCIPLES-REVIEWED] 0b11264 |
2ce011a to
aa4986f
Compare
GPT 5.6 Review —
|
aa4986f to
77fb03c
Compare
|
Drop the 4 remaining ticket ids from
Correct, and the same edit class the slice already performs. All four are gone; the file now has zero ticket ids and the description says seven, not three. The two that carried meaning beyond the number ( |
|
Defer the
The relation is the per-file coverage gate, not the feature. |
|
#8978 merged ( The GPT "review incomplete" and Opus "could not read this PR's comments" results on the previous head were API-read failures during the re-run wave my description edit triggered, not findings; this push gives them a fresh head. |
|
@iamwhatever thanks for taking #8978 and approving the stack. Your approval here was dismissed automatically ( Every review lane has re-stamped |
580bf4f to
08ce085
Compare
Stack reordered: #9079 now goes first
So the order of the stack, not its content, was the problem. Computed from this run's own
Every step of the new order clears the floor. The three commits are unchanged in content — the stack top is byte-identical to the previously verified one except for two adjacent import/feature-map lines — and each was re-verified on its new base ( |
|
Review-ready on Merge order is #9079 → this → #9078; once #9079 lands, this is retargeted to |
The session-identity code in ChatPage.tsx -- the lazy history seed, the per-mode localStorage slot memory, session tabs, the ?sid deep-link and URL-sync effects, the mobile drawer's pop bookkeeping, the new-slot mutation and its retry, slot auto-create, and handleResumeSession -- moves into pages/chat/useChatPageSessionController.ts. The page calls the hook once where that code used to sit and destructures what it still reads, so effect registration order is unchanged. Three edits to the moved text, none of them behaviour: location.key / location.pathname / location.hash become hook arguments; the dependency arrays name the refs the hook now receives as arguments (they are referentially stable, so nothing re-fires); and three comments drop issue-number references per AGENTS.md. ChatPage.sessionChipOffline.test.tsx's source contract now reads the callee declaration from the controller and the chip wiring from the page. Second slice of the ChatPage split proposed in #7255. Co-authored-by: Kiro Crew <noreply@kiro.dev>
08ce085 to
0b11264
Compare
|
#9079 merged ( |
Problem / Motivation
website/src/pages/ChatPage.tsxis a 10k-line page. About 550 lines of it decide which session the page is showing: the lazy history seed, the per-modelocalStorageslot memory, session tabs, the?siddeep-link and URL-sync effects, the mobile drawer's pop bookkeeping, the new-slot mutation and its retry, slot auto-create, andhandleResumeSession. They sit in one contiguous run in the middle of the component with no name.Why it matters
The whole-page split in #7255 grew past the point where CI's Opus review lane can finish one pass and collided with
main's chat-core transport work. It lands as slices that each fit one review pass. This slice owns session identity — the one regionmainhas not touched since #7255 was cut (zero drift), so it is the safest hook to move first.What changed (motivation → approach → change)
The moved code reads page inputs (slots, drafts refs, router state) and produces a small set of values the rest of the page uses. That is the shape of a custom hook.
ChatPage.tsxlines 4313–4839 and 4922–4940 move intopages/chat/useChatPageSessionController.ts. The page callsuseChatPageSessionController({...})at the exact spot the first moved line used to be and destructures the eighteen values it still reads. Because the call sits where the code sat, every effect keeps its registration order and every ref is created in the same render phase as before.Three edits to the moved text, none of them behaviour.
location.key/location.pathname/location.hashbecome hook arguments (locationKey,locationPathname,locationHash) so the hook does not calluseLocationa second time. The dependency arrays name the refs the hook now receives as arguments (activeSlotRef,newSessionRef,tokenConsumingRef, the draft refs); they are referentially stable, so no effect re-fires. Seven comments drop issue-number references perAGENTS.md(docs/system-specs/common/code-style.mdbans ticket ids in code comments); the moved file now carries none. Three page-side dependency arrays likewise addsetHighlightTs,initialMsgRef/initialMidRefanddrawerPopRef, whichreact-hooks/exhaustive-depscan no longer see as stable once they arrive through a hook return.Tests
ChatPageMoreCoverage.test.tsx: one added window-event characterization — a foregroundkirocrew-tool-callfor aplaywright-clicommand opens the Browser panel. It is here because of this slice, not beside it: the moved session code was 99% covered, so taking it out ofChatPage.tsxlowers the page's own per-file rate to 80.06% against the 80% floorcheck_per_file_coverage.pyenforces (the page is not baselined). Covering a listener the page keeps lifts it to 80.45%, clear of shard noise.ChatPage.sessionChipOffline.test.tsx: the "one session-entry path" source contract now reads theselectSessionTabdeclaration from the controller (exactly once) and theonSessionOpen={selectSessionTab}wiring from the page, and asserts the page no longer declares it.ChatPage*spec plus the session, drawer, URL-history and source-contract specs pass unchanged (67 files / 602 tests targeted; full suite result in the first comment).tsc -b,eslint(0 warnings),jscpd(0 clones),lint:phantom-classes,check_feature_map.py,check_brand_name.py,docs-lint.shall exit 0.Manual verification
N/A — the moved effects are covered by the
ChatPage.sid,ChatPage.sessionTabs,ChatPage.drawerBackClose,ChatPage.resumeSurfaceGateandChatPage.newSessionModelcharacterizations, which pass unchanged.Screenshots / video
Why no screenshot: hook extraction; nothing renders differently.
Related Issues
Part of the split of #7255. no linked issue: the parent PR has no tracking issue.
Checklist
feat|fix|docs|refactor|perf|test|chore|ci|build|revert: ...)