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

8.2 KiB
Raw Blame History

任务书 · 拆分首页巨石组件·第一批(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 个 useEffectHome 函数体约 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.py3 条早已断掉的红(断言里嵌的源码片段/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.pyCORE_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. 测试总数不得低于基线 2427Docker 环境 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。

让步顺序:功能与测试不回归 > 可验证的拆分 > 拆分行数目标 > 代码整洁。

开工前置

git fetch origin --prune
git worktree add -b codex/home-split-20260901 \
  ../.worktrees/home-split-20260901 origin/staging

基线必须是 origin/staging。读 pre_work_error_ledger.mdscripts/pre_work_check.pyfrontend/AGENTS.mdBLOCKED.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.pyCORE_PYTEST_TARGETS,加一行注释说明"此文件正则前端源码,前端搬家轮必须同步它"。
  • 先做本任务再搬家:它是本轮搬家正确性的额外安全网。

任务 1(P0)· 模块级 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.tslib/home-cloud-sync.ts)。
  • 只搬引用不改实现;page.tsx 改为 import。类型随函数走。

任务 2(P1)· 星盘库 + 合盘面板抽组件

  • 42524380 行的 chart-library-panel(含 synastry-report-cardsynastry-history-list)连同其独占 stateotherProfileDrafteditingChartIdotherChartRelationship 等)与 handlerssaveOtherChart / deleteOtherChart / editOtherChart / makeDefaultChart)抽为 components/chart-library-panel.tsx
  • 共享依赖(accountprofilechartLibraryactiveChartId、合盘发起等)走 props;props 类型显式定义。

任务 3(P1)· starter 首页与每日星语抽组件

  • 45414640 行的 starter 区(starter-hero / product-entrypoints / starter-themes,含 daily-starlanguage-card)抽为 components/starter-home.tsx(或按现状拆两个),独占 state 随行,入口动作走 props 回调。

任务 4P2)· 度量与收尾

  • 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 字段(等观测轮)。