产品 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
160 lines
8.6 KiB
Markdown
160 lines
8.6 KiB
Markdown
# TASK · 把校正面的 15 个状态从首页搬下去(page.tsx 状态下沉 · 第一簇)
|
||
|
||
- 日期:2026-09-15
|
||
- 基线 commit:`origin/staging` @ `6b3248bf`(开工时以最新 `origin/staging` 为准,见 §7)
|
||
- 执行分支:`codex/home-state-lowering-20260915`
|
||
- 落点:`frontend/src/app/page.tsx`、`frontend/src/hooks/use-rectification-surface.ts`、`frontend/src/components/conversational-birth-time-rectification.tsx`(或新建的容器组件)
|
||
- **串行依赖(三条,缺一不可)**:
|
||
1. `TASK-freeze-metric-change-20260915` —— 本单要让抽出去的 hook 持有 React 状态,那正是现行 `AGENTS.md §6` 禁止的;必须等新口径生效
|
||
2. `TASK-consultation-context-memory-20260915`(C2)—— 它在改 `use-session-management.ts` / `use-consultation-run.ts`,与本单同一片状态层
|
||
3. `TASK-rectification-settled-render-split-20260915`(R3)—— 它在改 `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.md`(AGENTS §7.5)。
|
||
|
||
## 6. 让步顺序
|
||
|
||
1. 5.1(分类)**不得砍**——没有分类表就动手,一定会把外壳要读的状态搬下去然后再搬回来。
|
||
2. 5.2 + 5.3 是主体。
|
||
3. 5.3 的目标值可以让步(比如只搬到 ≤ 56),但让步幅度和原因必须写进进度记录,**不得静默降低**。
|
||
4. 5.4 不得砍。
|
||
5. 5.5 不得砍。
|
||
|
||
## 7. 开工前置命令
|
||
|
||
```bash
|
||
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
|
||
```
|
||
|
||
验收命令:
|
||
|
||
```bash
|
||
./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 拆解(另一条线)
|