Files
Jyotisha/docs/tasks/TASK-home-state-lowering-20260915.md
T
Jesse_ChenandClaude Opus 5 e4788dfc00 docs(tasks): 换掉两条增长冻结口径 + page.tsx 状态下沉第一簇 + C1 提前
产品 2026-09-15 三项拍板,落成两份新单与两处既有单的修订:

- 新增 TASK-freeze-metric-change-20260915(无 BUG 号,后面两单的前置):
  两条冻结余量已用完(page.tsx 1951/1951 余 0;api server 11334/11363 余 29),
  冻结从「逼新代码往外走」退化成拦路。实证:page.tsx 行数砍 59% 但 Home()
  的 useState 从 56 涨到 66;api server 225 个类方法只有 12 处真碰 HTTP。
  主门换成耦合指标,行数降为粗护栏;同时推翻 §6「参数式 hook 内部保持
  0 个 React hook」——那正是状态搬不走的原因。
- 新增 TASK-home-state-lowering-20260915(无 BUG 号):先搬 rectification*
  那 15 个 state 进已经是 dynamic 子树的校正面,Home() useState 66 → ≤53。
  零行为变化;串行在 freeze-metric-change + C2 + R3 之后。
- 修订 TASK-consultation-external-evidence-cache-20260915:依赖反转,C1 排在
  API server 拆解之前(它动模块级函数,拆解动类方法);补「不得新增类方法、
  行数余量仅 29」的硬红线。
- 修订 TASK-api-server-decomposition-20260916:串行依赖加 C1 与
  freeze-metric-change;__new__ 计数按 grep 的 4 计(原文 3 是文件数);
  阶段 4 收尾口径改写;基线 11,314 → 11,334。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 23:15:37 +00:00

8.6 KiB
Raw Blame History

TASK · 把校正面的 15 个状态从首页搬下去(page.tsx 状态下沉 · 第一簇)

  • 日期:2026-09-15
  • 基线 commitorigin/staging @ 6b3248bf(开工时以最新 origin/staging 为准,见 §7
  • 执行分支:codex/home-state-lowering-20260915
  • 落点:frontend/src/app/page.tsxfrontend/src/hooks/use-rectification-surface.tsfrontend/src/components/conversational-birth-time-rectification.tsx(或新建的容器组件)
  • 串行依赖(三条,缺一不可)
    1. TASK-freeze-metric-change-20260915 —— 本单要让抽出去的 hook 持有 React 状态,那正是现行 AGENTS.md §6 禁止的;必须等新口径生效
    2. TASK-consultation-context-memory-20260915C2)—— 它在改 use-session-management.ts / use-consultation-run.ts,与本单同一片状态层
    3. TASK-rectification-settled-render-split-20260915R3)—— 它在改 rectification-agentic-chat.tsx,与本单同一片子树
  • 规模:一簇状态换个住处。零行为变化、零文案变化。

1. 为什么是这一簇

page.tsx 现在 1,951 行,行数上限 1,951余量 0。但行数不是病根:

指标 BUG-249 当时 今天
文件行数 4,766 1,951
Home()useState 56 66
useEffect 18 22
useRef 41
useCallback / useMemo 0 / 0 0 / 0

行数砍掉 59%,状态反而从 56 涨到 66。 前几轮拆的是代码不是状态:抽出去的 hook 是参数式的,useSessionManagement(params) 开头要解构约 40 个参数,useRectificationSurface(params) 约 56 个——状态所有权一个都没搬,每搬一次还要新增一批传参。

66 个 state 按归属分群:

个数
rectification* 15
session* 10
profile* 6
synastry* 4
account* 4
其余分散 27

最大的一簇服务的是一个已经是 dynamic() 懒加载的子树<ConversationalBirthTimeRectification> 挂着 24 个 props,而喂它们的 15 个 state 全住在 Home() 里。边界最清楚、收益最大,所以第一簇搬它。

那 15 个是:

rectificationSessionId          rectificationShouldStartOpening
rectificationCaseId             rectificationTurns
rectificationHeaderSlot         rectificationSnapshot
rectificationPendingQuestion    rectificationOpeningSessionId
rectificationLoading            rectificationEntrySummary
rectificationMutationPending    rectificationEntrySummarySettled
rectificationError
rectificationErrorSessionId
rectificationReadonly

2. 根因

AGENTS.md §6 现行那句「参数式 hook 内部保持 0 个 React hook 的既定模式」把状态钉死在 Home() 里;同一节的行数冻结又不许 page.tsx 增长。两条合起来等于「不许再加状态」,而每一轮新功能都要加。TASK-freeze-metric-change-20260915 已经拿到产品授权推翻前半句,本单是第一个吃到新口径的轮次。

3. 决策记录

产品 2026-09-15 拍板:

  1. page.tsx 走「状态下沉」这条路,不引外部 store、不铺全局 Context Provider。理由:不引新依赖、可以一簇一簇增量做,每搬一簇 page.tsx 就真降一截。
  2. 第一簇搬校正面的 15 个。 后续 session* / profile* / synastry* 各自另开单,本单不碰。
  3. 抽出去的 hook 与子组件从此持有自己的状态(推翻 §6 旧红线,措辞由 freeze-metric-change 单落地)。执行方不得以「AGENTS 说参数式 hook 里不能有 React hook」为由拒改。
  4. 零行为变化。 本单不修任何已知交互缺陷,发现了写进进度记录。

4. 硬红线

  1. 不是 15 个都能搬。 有几个外壳自己要读(例如 rectificationSessionId / rectificationCaseId 参与决定显示哪个界面、侧栏会话列表也要知道)。第一步必须逐个分类:「只服务子树 → 搬下去」「外壳也要读 → 留在外壳,但收敛成一个对象,不再是散装的多个 useState」。分类表写进进度记录,不许含糊。
  2. 零行为变化是唯一成败判据:进入校正面、退出、刷新、从首页卡片打开、打开历史校正、开场自动触发、只读态、报错态、换模型、采用后回首页——逐条与改前一致。
  3. next build/ 仍须 ○ Static;首屏 JS gzip 变化在 ±2 % 内(上次实测 584,413 B)。
  4. 测试总数不得低于开工时 origin/staging 的实测;改任何既有断言必须写「原值 / 新值 / 原因」三栏(AGENTS §7.3)。
  5. 不得新写第二个聊天输入框、第二套滚动跟随、第二套加载动画(§6 第三条原样有效)。
  6. 不得顺手升级依赖、不得顺手修不在本单里的 warning。
  7. 不得改数据库、不得改任何 API 路由。 本单只动前端状态的住处。

5. 任务分解

5.1 先分类,再动手

把 15 个逐个归类并写进进度记录:

类别 处置
只服务校正子树 搬进子树(useRectificationSurface 变成真 hook,或由容器组件持有)
外壳也要读 留在外壳,但合并成一个状态对象,散装 useState 数下降
  • 验收:分类表在进度记录里,15 个一个不漏,每个写明依据(谁在读它)。

5.2 useRectificationSurface 变成真 hook

现在它要解构约 56 个参数。改成自己 useState / useEffect 持有第一类状态,对外只暴露子树真正需要的接口;page.tsx 侧的传参随之消失。

  • 验收:useRectificationSurface 的参数个数显著下降,新值写进进度记录(改前约 56)。
  • 验收:<ConversationalBirthTimeRectification> 的 props 个数下降,新值写进进度记录(改前 24)。

5.3 Home() 的状态计数必须真降

  • 验收:Home()useState 数从 66 降到 ≤ 53(搬走至少 13 个;允许留 2 个在外壳,多留必须逐个说明理由)。
  • 验收:useRef 数不得上升(改前 41)——不许把 state 改写成 ref 来凑数字。
  • 验收:frontend/tests/home-shell-growth-contract.test.ts(由 freeze-metric-change 单建立)在本单收尾时更新为新基线,并贴一次反向验证。

5.4 行为等价证明

  • 验收:改动前后各跑一次全量前端套件,失败清单逐条一致(无 Docker 时数据库套件照常红)。
  • 验收:npx tsx --test tests/rectification-*.test.ts 全绿,断言零改动——如果必须改,按 §4.4 写三栏说明。
  • 验收:docs/testing/ 下留一份真人走查清单,覆盖 §4.2 那十条路径(本仓没有浏览器与登录态,这一项只能人工)。

5.5 记录

本单不产生 Bug 记录(不是缺陷,是结构改造),不进 CHANGELOG.md(无用户可感知变化)。若过程中确实改了任何可见样式,必须同提交更新 frontend/DESIGN.mdAGENTS §7.5)。

6. 让步顺序

  1. 5.1(分类)不得砍——没有分类表就动手,一定会把外壳要读的状态搬下去然后再搬回来。
  2. 5.2 + 5.3 是主体。
  3. 5.3 的目标值可以让步(比如只搬到 ≤ 56),但让步幅度和原因必须写进进度记录,不得静默降低
  4. 5.4 不得砍。
  5. 5.5 不得砍。

7. 开工前置命令

git fetch origin --prune
# 三条串行依赖必须都已合入 staging,逐个确认
git log --oneline origin/staging | head -20
git worktree add -b codex/home-state-lowering-20260915 \
  .worktrees/home-state-lowering-20260915 origin/staging
cd .worktrees/home-state-lowering-20260915/frontend
git status -sb | head -1
npm ci
# 取当时实测基线,不要抄本任务书里的数字(七条在飞分支合并后会变)
grep -cE '\buseState[<(]' src/app/page.tsx
grep -cE '\buseRef[<(]' src/app/page.tsx
grep -oE 'const \[rectification[A-Za-z]+' src/app/page.tsx | wc -l

验收命令:

./node_modules/.bin/tsc --noEmit
npm run lint                       # 0 error
npx tsx --test tests/rectification-*.test.ts tests/home-shell-growth-contract.test.ts
npx tsx --test tests/*.test.ts     # 与基线逐条比对失败清单
npm run build                      # `/` 仍须 ○ Static,首屏 gzip ±2%

8. BUG 编号起点

本单不占 BUG 号。基线 6b3248bf 上最大号 BUG-720,721–732 已被两轮审计七单预占。

9. 不在本单范围

  • session* / profile* / synastry* / account* 四簇(各自另开单)
  • Context Provider 或外部 store(§3.1 已否决这一轮走这两条路)
  • 校正面自身的任何交互缺陷(本单零行为变化)
  • API server 拆解(另一条线)