Files
Jyotisha/TASK-home-split-20260901.md
T
Jesse_Chen 8558900525
Independent Staging Quality Gate / validate (push) Successful in 13m7s
Independent Staging Quality Gate / publish (push) Successful in 50m57s
docs(chat): add home-split batch-one task brief
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVapmh2oGNyr6ECHKjPJY8
2026-09-01 13:47:24 +00:00

87 lines
8.2 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.
# 任务书 · 拆分首页巨石组件·第一批(2026-09-01)
基线:`origin/staging` @ `ce6a8a7e`(开工时以 `origin/staging` 最新为准)。这是 BUG-464/465/466 三轮之后的收官轮:前三轮把真相收归服务端,本轮开始拆运载这一切的 4,766 行 `frontend/src/app/page.tsx`。与任何同期改 `page.tsx` 的轮次**不得并行**。
**本轮性质是纯搬家,不是重写。** 逐行行为必须保持原样——不改逻辑、不改用户可见文案、不改 DOM 结构与 class 名、不调整时序。这也是 2026-08-17 React Compiler 轮 `BLOCKED.md` 的结论指出的正道("值得做的是按职责把 Home 拆小"),但本轮**不重开 React Compiler**。
---
## 为什么要做(事故实证)
1. `page.tsx` 4,766 行、65 个 `useState`、21 个 `useEffect``Home` 函数体约 3,470 行(1295 行起)。聊天、引导、星盘库、合盘、每日星语、starter 首页、账户弹窗全部同函数。历轮回归(BUG-409、445–448 等)多数落在此文件。
2. React Compiler 轮量化过:全项目 44 个组件可被编译,唯独 `Home` 因体量与结构被拒(`BLOCKED.md` 2026-08-17 记录)。同文件里两个小组件正常编译——问题就是"函数太大"本身。
3. **36 个测试文件用正则直接读 `page.tsx` 源码**`grep -rln 'app/page.tsx' frontend/tests tests` 可证)。这是本轮最大的爆炸半径,红线 3 专门处置。
4. 存量地雷(验收 BUG-466 时发现):`tests/test_supabase_user_data_contract.py`**3 条早已断掉的红**(断言里嵌的源码片段/UI 文案在此前轮次被改走,如 `添加其他星盘`、account 路由的数组守卫表达式、synastry 路由的 `apiBase` 行),而 staging quick gate 的 `CORE_PYTEST_TARGETS` 白名单不含此文件——一份没人运行的契约测试。它恰好大量正则 `page.tsx`,与本轮直接纠缠,必须先修。
## 决策记录(产品授权,2026-09-01)
1. **拆分分批进行,本轮只做第一批**helpers 出仓 + 星盘库/合盘面板 + starter 首页/每日星语)。聊天主链路(composer/transcript/consult 编排)**本轮不动**。
2. **允许成批修改"读 `page.tsx` 源码"的合同测试的读取路径**:仅限其锁的代码被本轮搬走的测试;断言的语义内容不得改变(同一正则、同一 token,换文件路径),逐条在 PROGRESS 登记"原路径 → 新路径"。这是对"不得修改既有测试断言"红线的定向豁免,超出此范围的断言改动仍被禁止。
3. **`test_supabase_user_data_contract.py` 修复后进 quality gate 白名单**`scripts/run_quality_gate.py``CORE_PYTEST_TARGETS`)。修复方向是让断言对齐现状源码、保住其锁的性质(如"数组 payload 仍被拒"),不是删除检查。
4. P1 验收遗留的小项(popstate 回默认会话未走 `selectSession` 副作用)**本轮不修**——纯搬家轮不夹带行为变化,另行小刀。
## 硬红线
1. **行为零变化。** 不改任何逻辑表达式、用户可见文案、class 名、aria 属性、时序。搬家中发现的疑似 bug 一律登记 `BLOCKED.md`,不得顺手修。
2. **状态迁移规则**:只有被抽出 surface **独占**的 state/handler 才随组件下移;被多个 surface 共享的 state 留在 `Home`,用显式 props 传递。**不得引入 context、全局 store 或任何新状态库**props 接口用显式 TypeScript 类型。
3. **测试改动仅限决策记录 2 的定向豁免**。动手前对每个待搬区域先 `grep -rn` 两个测试目录,列出受影响清单再搬;搬完逐条验证断言在新路径上仍然锁住同样内容。
4. `page.tsx` 顶部的 `import "@/app/site-styles"` 与动态 import 结构不动;`site-style-isolation-contract` / admin CSS 隔离测试必须保持绿灯且不被修改。新组件文件不得各自 import 全局样式。
5. 不得手写 `useCallback` / `useMemo`;不重开 React Compiler;不为编译器改写代码。
6. 推 staging 前 `./node_modules/.bin/tsc --noEmit` 通过(**不要 `npx tsc`**,空包坑)。
7. 测试总数不得低于基线 **2427**Docker 环境 fail=0、skipped=0;无 Docker 既有缺口 24 失败 + 10 skipped,清单与 `ce6a8a7e` 一致,逐条比对不得新增)。本轮不动数据库。**Python 侧**:任务 0 完成后 `tests/test_supabase_user_data_contract.py` 必须全绿并附 pytest 输出。
8. `next build``/``○ Static`;首屏 JS gzip 体积与基线差异超过 ±2% 须在 PROGRESS 说明原因。
9. 不得改 `.gitea/workflows/**`(白名单在 `scripts/run_quality_gate.py`,不属于 workflows)。不在脏工作树切分支。不自行提升 main。
让步顺序:功能与测试不回归 > 可验证的拆分 > 拆分行数目标 > 代码整洁。
## 开工前置
```bash
git fetch origin --prune
git worktree add -b codex/home-split-20260901 \
../.worktrees/home-split-20260901 origin/staging
```
基线必须是 `origin/staging`。读 `pre_work_error_ledger.md``scripts/pre_work_check.py``frontend/AGENTS.md``BLOCKED.md` 的 2026-08-17 React Compiler 记录(本轮的"为什么拆"与"怎么不拆"都在里面)。改前在 `docs/BUG_HISTORY.md` 检索。
## 任务分解
### 任务 0(P0,先行)· 修复孤儿契约测试并入白名单
-`tests/test_supabase_user_data_contract.py` 的 3 条红对齐现状(决策记录 3 的方向),全文件跑绿。
- 加入 `scripts/run_quality_gate.py``CORE_PYTEST_TARGETS`,加一行注释说明"此文件正则前端源码,前端搬家轮必须同步它"。
- 先做本任务再搬家:它是本轮搬家正确性的额外安全网。
### 任务 1P0)· 模块级 helpers 出仓(约 950 行)
- `page.tsx` 1–1290 行区间内的纯函数(storage 键、read/normalize 系列、cloud fetch 系列、label/format 系列、`createSession` 等)与三个顶层组件(`BirthLocationFields` 1003、`ProfileFields` 1065、`OnboardingChatMessage` 1094)搬到 `frontend/src/lib/``frontend/src/components/` 下的新文件(按既有命名风格分组,如 `lib/home-profile.ts``lib/home-cloud-sync.ts`)。
- 只搬引用不改实现;`page.tsx` 改为 import。类型随函数走。
### 任务 2(P1)· 星盘库 + 合盘面板抽组件
- 42524380 行的 `chart-library-panel`(含 `synastry-report-card``synastry-history-list`)连同其独占 state`otherProfileDraft``editingChartId``otherChartRelationship` 等)与 handlers`saveOtherChart` / `deleteOtherChart` / `editOtherChart` / `makeDefaultChart`)抽为 `components/chart-library-panel.tsx`
- 共享依赖(`account``profile``chartLibrary``activeChartId`、合盘发起等)走 props;props 类型显式定义。
### 任务 3P1)· starter 首页与每日星语抽组件
- 45414640 行的 starter 区(`starter-hero` / `product-entrypoints` / `starter-themes`,含 `daily-starlanguage-card`)抽为 `components/starter-home.tsx`(或按现状拆两个),独占 state 随行,入口动作走 props 回调。
### 任务 4(P2)· 度量与收尾
- PROGRESS 里给出前后对比:`page.tsx` 行数(目标 **≤ 3,000**,不达标写明哪块没拆及原因)、`useState` / `useEffect` 数、受影响测试清单(原路径 → 新路径)、首屏 gzip 对比。
- 顺手项仅允许:删除搬空后残留的死 import。
## 总验收
1. `tsc --noEmit` 通过;测试满足红线 7(前端 + Python 两侧输出都附)。
2. `next build``/``○ Static`;体积对比在 ±2% 内或有说明。
3. 行为抽查(无登录态则合同测试覆盖 + 如实标注):星盘库增删改、合盘发起与历史回看、starter 首页各入口点击、每日星语加载,与拆前一致。
4. 全部被搬 token 的合同测试逐条在新路径上重新锁定,无一被弱化或删除。
## 明确不做(不要顺手做)
- 不动聊天主链路(composer、transcript、consult 编排、恢复逻辑)——第二批再拆。
- 不引入 context/store/新依赖;不重开 React Compiler。
- 不修 popstate 回默认会话的副作用差异(决策记录 4)。
- 不删 BUG-464 的 PATCH 兼容层、不删 consult 的 `history` 字段(等观测轮)。