Files
Jyotisha/PROGRESS-home-split-batch2-20260901.md
T
Jesse_Chen 551d6317ae
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled
refactor(chat): extract consultation and session hooks after contract repairs
Keep archive as a PATCH of archived_at rather than DELETE, pass entry_mode through onboarding, and let popstate to the default chat reuse selectSession. Then move send/stop/recovery and session management out of page.tsx so the home surface stays within the batch-two line budget.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 04:34:14 +08:00

99 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PROGRESS · 拆分首页巨石组件·第二批:聊天主链路(2026-09-01)
工作树:`.worktrees/contract-repairs-20260901`
分支:`codex/contract-repairs-20260901`
基线:小刀轮未推送,故未另开 `codex/home-split-batch2-20260901`;产品代码从 `a6148af8` + 小刀轮改动继续。
不要写成 `PROGRESS.md`。交付为快进推 `origin/staging`
React Compiler 仍关(`BLOCKED.md` 2026-08-17)。未引入 context/store。无手写 `useCallback`/`useMemo`。自定义 hook 按任务书决策记录 1 允许。`site-styles` import 仍在 `page.tsx` 顶。`const BirthTimeRectification = dynamic(...)` 未动。
## 度量
| 项 | 拆前(第一批后 3505 / 小刀后约 3510 | 拆后 | 说明 |
| --- | ---: | ---: | --- |
| `frontend/src/app/page.tsx` 行数 | 3505 | 2445 | 目标 ≤2600,达标 |
| `useState(` Home / session hook / consult hook | 26 / — / — | 26 / 0 / 0 | 独占 state 未下移,见 hook 顺序 |
| `useRef(` Home / session / consult | 19 / — / — | 19 / 0 / 0 | 同上 |
| `useEffect(` Home / session / consult | 20 / — / — | 20 / 0 / 0 | 拉取/恢复 effect 仍在 Home |
| `/` 路由 | `○ Static` | `○ Static` | webpack `next build --webpack` |
| 首屏 JS gzip -9 | 第一批后 501315 B | 501104 B = 489.4 KB | 211 B / **0.04%**(±2% 内) |
| 前端测试 | 小刀后 2428 | 2428 | 见验证 |
剩余未达标块(第三批):onboarding/profile`refreshAccount``signOut`)、rectification 胶水(`refreshRectificationEntrySummary``handleRectificationMessagesChange`)、合盘草稿、composer `submit`
## Hook 调用顺序(红线 1
搬前 `Home` 内真正的 React hook 序列(`a6148af8`):
`useRouter``useState`×26 → `useRef`×19 → `useBirthTimeGuidedJourney``useEffect`×8 → `useConversationScrollAnchor``useEffect`×12
咨询/会话的 `useState`/`useRef` **不是连续块**:中间夹着校正会话、引导草稿、星盘库、合盘等。若只把「引擎独占」的那几项抠进 hook,会改变 `Home` 里 hook 的相对次序。
因此本轮两个新 hook **内部零 `useState`/`useRef`/`useEffect`**,只搬函数体与 `.current =` 赋值。串接后 `useState`/`useRef`/`useEffect` 次序与搬前逐一相同;新增的只是两个无内部 hook 的调用点:
| 调用点 | 位置 | 原因 |
| --- | --- | --- |
| `useSessionManagement(...)` | `useBirthTimeGuidedJourney` 之后、**第一条 `useEffect` 之前** | 紧随其后的 effect 调用 `ensureSessionMessages` |
| `useConsultationRun(...)` | `useConversationScrollAnchor` 之后、其余 `useEffect` 之前 | `send` 需要 `conversationAnchor.anchorToLatest()` |
依赖方向:session hook 先返回 `persistSession` / `updateSession` / `startNewChat` / `continueInNewChat`,由 Home 传入 consult hook。两文件 **不得、也没有** 互相 import。
`setDraft` / `setDraftTheme` / `setDraftEntrypoint` / `refreshAccount` / `openAccountDialog` / `openRectificationFromHomepage` / `openRectificationSession` 仍是 `Home`**function declaration**(JS 提升),所以可以出现在 hook 调用点之上的参数列表里。这不是 React hook 顺序问题。
核对方式:对 `export default function Home` 之后的 `useRouter|useState|useRef|useEffect|useBirthTimeGuidedJourney|useConversationScrollAnchor|useSessionManagement|useConsultationRun` 计数;两 hook 文件内上述符号计数为 0。
## 任务 12 · 搬家
新文件(函数体与 `a6148af8``page.tsx` 逐行一致;允许差异仅缩进、`export`、经参数/返回值改道的标识符。popstate 以小刀轮为准,不回退到 `a6148af8`):
| 文件 | 行 | 内容 |
| --- | ---: | --- |
| `frontend/src/hooks/use-session-management.ts` | 443 | `updateSession``selectSessionModel` + 小刀修过的 `applySessionPopStateRef.current` |
| `frontend/src/hooks/use-consultation-run.ts` | 1073 | `restoreConsultationRecovery` + recovery/replay 赋值、`requestCancellation` / `confirmCancellation` / `stopResponse` / `completeConsultationInterface` / `send` / `regenerateLatestAnswer` |
函数体公证(对 `a6148af8` 去缩进后逐行):
`updateSession` 3、`persistSession` 25、`ensureSessionMessages` 24、`continueInNewChat` 7、`renameSession` 11、`deleteSession` 20、`togglePinnedSession` 10、`toggleArchivedSession` 22、`shareSession` 28、`startNewChat` 33、`startConsultationAfterRectification` 5、`selectSession` 28、`selectSessionModel` 52、`restoreConsultationRecovery` 53、`requestCancellation` 27、`confirmCancellation` 19、`stopResponse` 129、`completeConsultationInterface` 9、`send` 567、`regenerateLatestAnswer` 23`consultationRecoveryCheck.current` / `consultationReplay.current` 赋值块亦相同。
改名清单:**零**(无业务标识符重命名)。
`applySessionPopStateRef` 相对 `a6148af8` 的差异即小刀轮任务 3,原样搬进 session hook。
## 合同测试路径(同一 token,只换读取面)
拼接件 `frontend/tests/home-surface.ts` / Python `_home_surface()`:第一批文件 + 可选 `use-session-management.ts` / `use-consultation-run.ts``existsSync` / `Path.exists()`)。hook 落地后自动拼进。
| 测试 | 原路径 | 新路径 |
| --- | --- | --- |
| `sidebar-contract.test.ts`「keeps the page session selection callback…」 | `page.tsx` 正则 `selectSession` | `homeSurface`(函数已搬走;断言内容未改) |
| `consultation-birth-time-mode.test.ts` homepage `consultationMode:` | `page.tsx` | `homeSurface`token 在 `send` |
| `tests/test_supabase_user_data_contract.py` | 已是 `_home_surface()` | 可选 hook 列入清单(`persistSession(completedSession)` 等在 consult hook |
| `rectification-agentic-entry.test.ts` refreshAccount 切片 | `function updateSession` 作终点 | `function openAccountDialog``updateSession` 已搬走;若终点落在拼接后的 hook 文件,切片会吞进仍留在 page 的 `persistProfile`/`setProfileDraft`。断言内容未改) |
| `profile-state.test.ts` 同一切片 | 同上 | 同上(该文件仍只读 `page.tsx`,终点改为仍相邻的 `openAccountDialog` |
| `chat-stream-layout.test.ts` 活动/ndjson/`regenerateLatestAnswer` | `page.tsx` | `homeSurface`token 在 `send` / consult hook |
| `evidence-audit-panel.test.ts` workflow receipt headers | `page.tsx` | `homeSurface` |
| `chat-notice-and-scroll-contract.test.ts` send 切片 | `page.tsx``updateSession(sessionId, () => userSession)` | `homeSurface`(仅该条;JSX/poll 仍读 `page.tsx` |
其余已走 `homeSurface` 的聊天主链路测试(`chat-session-url` / `consultation-recovery` / `consultation-entrypoint` / `composer-isolation` / `chat-session-authority` 等)无需再改:切片标记仍在 hook 文件内且相邻。
锁 JSX/仍留在 `page.tsx` 的测试继续只读 `page.tsx``site-style-isolation``rectification-lazy-loading``chat-notice-and-scroll` 的 poll timer、profile/onboarding 等)。
小刀轮两个 Python 文件保持全绿(见小刀 PROGRESS)。
## 验证
- `./node_modules/.bin/tsc --noEmit`:通过。
- 聚焦合同:`consultation-recovery` / `chat-session-*` / `composer-isolation` / `consultation-entrypoint` / `starter-questions` / `chat-navigation-a11y` / `settings-mvp` / `sidebar-contract` / `consultation-birth-time-mode` / `rectification-agentic-entry` / `profile-state` 全绿。
- 全量 `npm test`2428 pass / 0 fail / 0 skipped。
- `./node_modules/.bin/next build --webpack``┌ ○ /` Static。首屏 JS gzip-9 501104 B vs 第一批后 501315 B(−211 B / 0.04%)。
- 行为抽查:无登录态浏览器点选会话 / 发送咨询。由合同测试覆盖抽取正确性;popstate 行为变化已在小刀轮用源码合同锁住。
未改 `.gitea/workflows/**`。未动数据库。未提升 `main`。未重开 React Compiler。
## 明确未做
- onboarding/profile 簇与 rectification 胶水(第三批)。
- 未把 streaming/pending 等 state 下移进 hook(为保住 hook 顺序)。
- 未修任何行为(popstate 已在小刀轮完成)。