# PROGRESS · 拆分首页巨石组件·第一批(2026-09-01) 工作树:`.worktrees/home-split-20260901` 分支:`codex/home-split-20260901`(跟踪 `origin/staging`) 基线:`origin/staging` @ `85589005`(任务书提交;产品代码与 P2a `ce6a8a7e` 相同) 不要写成 `PROGRESS.md`。本轮未提交、未推送。 ## 度量 | 项 | 拆前 `85589005` | 拆后 | 说明 | | --- | ---: | ---: | --- | | `frontend/src/app/page.tsx` 行数 | 4766 | 3505 | 目标 ≤3000,未达标 | | `useState(` | 26 | 26 | 见下方 overlay 说明 | | `useEffect(` | 20 | 20 | 拉取/重试 effect 仍在 Home | | `/` 路由 | `○ Static` | `○ Static` | webpack `next build` | | 首屏 JS gzip -9 | 500262 B = 488.5 KB | 501315 B = 489.6 KB | +1053 B / **+0.21%**(±2% 内) | | 前端测试 | 2427 | 2427 | fail=0 skipped=0(见验证) | 未达标原因:聊天主链路(composer / transcript / `send` / 停止与恢复 / 引导对话)按任务书本批不动。抽走的是 helpers + 星盘库/合盘面板 + starter/每日星语。剩余约 505 行要等第二批。 `useState` 未下降:`otherProfileDraft` / `editingChartId` / `otherChartRelationship` / `editingSelfChart` 仍留在 `Home`。`AccountDialogOverlay` 在关闭时 `return null`,把独占 state 下移进面板会在关弹窗时丢掉未保存草稿,属于行为变化,本轮禁止。handlers(`saveOtherChart` 等)已随 JSX 进面板,state 经显式 props 传入。 ## 任务 0 · 孤儿契约测试 `tests/test_supabase_user_data_contract.py` 对齐现状源码(性质保留:浏览器不直写 `profiles` / `chat_sessions`,账户 PATCH 仍拒数组,合盘仍走 `postPython("/api/chart")`)。任务书写的三处之外,同一文件里还有过期 token,一并换成现码并在上方注释原值: - 首页不再 `.from("profiles")` / `.from("chat_sessions")`,锁 `fetch("/api/account"` / `fetch("/api/sessions"` - 账户 PATCH:`accountProfilePatchSchema.safeParse` + `z.object({`(`account-profile-patch.ts`) - 文案「添加其他人的星盘」 - 合盘:`postPython("/api/chart", selfPayload)` / `partnerPayload` - 用户消息:`messages: questionAlreadyPresent ? preservedMessages : [...preservedMessages, { role: "user", text: question }]` - 中断路径:源码已无 `await persistSession(interruptedSession)`;停止文案「正在停止回答并申请退回本次点数…」 搬家后该文件改读 `_home_surface()`(`page.tsx` + 抽出文件拼接),正则/token 未改。 `scripts/run_quality_gate.py` 的 `CORE_PYTEST_TARGETS` 已列入此文件,注释写明前端搬家轮必须带着它跑。 `pytest tests/test_supabase_user_data_contract.py tests/test_daily_and_rectification_entrypoints.py -q` → 12 passed。 ## 任务 1–3 · 搬家 新文件(实现从 `page.tsx` 原样搬出,加 `export`): | 文件 | 行 | 内容 | | --- | ---: | --- | | `frontend/src/lib/home-types.ts` | 254 | 类型、空资料、themes、storage 键常量 | | `frontend/src/lib/home-profile.ts` | 323 | 地点/资料/标签/`readProfile`/`upsertSelfChart` | | `frontend/src/lib/home-cloud-sync.ts` | 499 | 云端 fetch、登录跳转、每日星语读写 | | `frontend/src/components/birth-location-fields.tsx` | 40 | `BirthLocationFields` | | `frontend/src/components/profile-fields.tsx` | 38 | `ProfileFields` | | `frontend/src/components/onboarding-chat-message.tsx` | 28 | `OnboardingChatMessage` | | `frontend/src/components/chart-library-panel.tsx` | 269 | 星盘库 + 合盘卡/历史/他人表单 | | `frontend/src/components/starter-home.tsx` | 159 | starter hero / 每日星语 / 生时入口 / 主题卡 | `page.tsx` 仍 `"use client"`、`import "@/app/site-styles"`、`const BirthTimeRectification = dynamic(...)`。新组件未 import 全局样式。无 context/store、无手写 `useCallback`/`useMemo`、未重开 React Compiler。 本人星盘表单仍 `onSubmit={saveProfile}`(面板 prop 名就是 `saveProfile`)。starter 回调 prop 保持原标识符:`startDailyStarlanguageConsultation`、`openRectificationFromHomepage`、`startSuggestedConsultation`。 ## 合同测试路径(同一 token,只换读取面) 共用拼接件 `frontend/tests/home-surface.ts`:`page.tsx` + 上表抽出文件。Python 侧 `_home_surface()` / 显式 concat 同理。 | 测试 | 原路径 | 新路径 | | --- | --- | --- | | `birth-place-picker.test.ts` | `src/app/page.tsx` | `homeSurface`(`BirthPlacePicker` 在 `birth-location-fields.tsx`) | | `birth-time-consultation-consent.test.ts` | `page.tsx` | `homeSurface`(`readProfile` 在 `home-profile.ts`) | | `character-remaining-contract.test.ts` | `page.tsx` | `homeSurface`(姓名字数 `aria-describedby` 在 `profile-fields.tsx`) | | `chart-library-other-profile.test.ts` | `page.tsx` | `homeSurface` | | `chat-navigation-a11y-contract.test.ts` | `page.tsx` | `homeSurface` | | `chat-session-authority.test.ts` | `page.tsx` | `homeSurface` | | `chat-session-url.test.ts` | `page.tsx` | `homeSurface` | | `chat-session-write.test.ts` | `page.tsx` | `homeSurface`(`fetch("/api/sessions"` 在 `home-cloud-sync.ts`) | | `composer-isolation-contract.test.ts` | `page.tsx` | `homeSurface`(`pendingConsultationStorageKey` 在 `home-types.ts`) | | `consultation-entrypoint.test.ts` | `page.tsx` | `homeSurface`(starter 卡在 `starter-home.tsx`) | | `consultation-recovery.test.ts` | `page.tsx` | `homeSurface` | | `daily-starlanguage.test.ts` | `page.tsx` | `homeSurface` | | `membership-page.test.ts`(home 段) | `page.tsx` | `homeSurface`(`LoginRedirectError` 在 `home-cloud-sync.ts`) | | `onboarding-presentation.test.ts` | `page.tsx` | `homeSurface` | | `rectification-agentic-entry.test.ts` | `page.tsx` | `homeSurface` | | `settings-mvp-contract.test.ts` `renderProfile` | `page.tsx` 切片 | `homeSurface`(切片标记仍在 `page.tsx`) | | `settings-mvp-contract.test.ts` 星盘库表单 | `page.tsx` 的 `renderChartLibrary`→`renderGeneral` 切片 | `chart-library-panel.tsx`(切片里只剩 ``,token 已搬走) | | `starter-questions.test.ts` | `page.tsx` | `homeSurface` | | `tests/test_supabase_user_data_contract.py` | `PAGE.read_text()` | `_home_surface()` | | `tests/test_daily_and_rectification_entrypoints.py` | `PAGE` | `PAGE` + `starter-home.tsx` + `home-cloud-sync.ts` | | `tests/test_birth_time_journey_contract.py` 网页引导条 | `page.tsx` | `page.tsx` + `home-profile.ts`(`reported_birth_time` / `active_birth_time`) | 未改断言语义。锁聊天主链路、且 token 仍在 `page.tsx` 的测试继续只读 `page.tsx`(如 `site-style-isolation-contract`、composer/sidebar 壳、`rectification-lazy-loading`)。 ## 验证 - `./node_modules/.bin/tsc --noEmit`:通过。 - `npm test`:2427 条。并发下 2 条 Docker 库测 flake(`admin-database` / `model-configuration-security`,`database migration failed` / `Connection terminated unexpectedly`)。`--test-concurrency=1` 重跑这 8 条:pass 8 fail 0。与产品搬家无关。skipped=0。 - `./node_modules/.bin/next build --webpack`:`┌ ○ /`。本树 `node_modules` 仍是指向 `session-url-20260901` 的符号链接,默认 Turbopack 会拒。gzip 口径:预渲染 `index.html` 引用的 `/_next/static/**.js` 去重后 `gzipSync` level 9。基线用同 SHA 干净 worktree 同口径对照。 - 行为抽查:无登录态,未在浏览器点星盘库增删改、合盘、starter 入口、每日星语。由合同测试覆盖。 ## 明确未做 / 未修 - 聊天主链路第二批再拆。 - popstate 回默认会话未走 `selectSession`(任务书决策 4)。 - `tests/test_session_management_entrypoints.py::test_archiving_never_calls_the_delete_endpoint` 仍锁已删除的 `setArchivedSessionIds`(P2a 遗留,不在 `CORE_PYTEST_TARGETS`,本轮不顺手修)。 - `tests/test_birth_time_journey_contract.py::test_web_onboarding_uses_the_deterministic_free_journey` 在 mastra 断言 `'entry_mode: entryMode'` 上仍红(与搬家无关、不在 quick gate);本轮只补了 `page.tsx` 侧 token 路径。 - 未改 `.gitea/workflows/**`。未提升 `main`。