refactor(home): 校正面 15 个状态从 Home 下沉
Independent Staging Quality Gate / validate (push) Failing after 6m43s
Independent Staging Quality Gate / publish (push) Skipped

Home() useState 66->52, useRef 41->39. Shell-facing fields merge into one object;
subtree state lives in useRectificationSurface. Chat props 20->7. Growth contract
rebaselined. Zero behavior/copy change.
This commit is contained in:
jesse-ux
2026-09-16 08:33:48 +08:00
parent 3b17c1b242
commit f8e607c29a
10 changed files with 448 additions and 122 deletions
@@ -0,0 +1,127 @@
# PROGRESS · 把校正面的 15 个状态从首页搬下去(2026-09-16)
工作树:`.worktrees/home-state-lowering-20260915`
分支:`codex/home-state-lowering-20260915`
任务书基线写 `6b3248bf`;开工时 `origin/staging` = **`3b17c1b2`**(含 freeze-metric / C2 / R3)。
本机 Windows。无 Docker。本单不占 BUG 号,不改 `CHANGELOG.md` / `BUG_HISTORY.md` / `docs/tasks/README.md`。未 `git push origin HEAD:staging`。未改数据库、API 路由、DESIGN.md(无可见样式变化)。
## 开工核对
`git log --oneline origin/staging` 前 20 行含:
| 依赖 | SHA | 证据 |
| --- | --- | --- |
| freeze-metric-change | `3b17c1b2` | `test(freeze): 增长冻结改盯耦合,行数降为粗护栏`HEAD |
| C2 consultation-context-memory | `149e1ec4` | `fix(consult): drop traces, budget checkpoints, silent summary inherit` |
| R3 settled-render-split | `58ccafb6` | `fix(rectification): stop re-parsing settled messages on every stream frame` |
AGENTS.md §6 已是新口径:抽出去的 hook 与子组件应当持有自己的状态。
## 开工实测(不要抄任务书 66/41)
数法与合同测试相同:`Home()` 切片上 `\buseState[<(]` / `\buseRef[<(]`
| 指标 | 实测 |
| ---: | ---: |
| `Home()` `useState` | **66** |
| `Home()` `useRef` | **41** |
| `const [rectification…` | **15** |
| `page.tsx` 行数 | **1951** |
| `useRectificationSurface` 参数(type 字段) | **39**(任务书约 56,按 type 实测) |
| `ConversationalBirthTimeRectification` propstype 字段) | **20**(任务书 24,按 type 实测;JSX 含 key 为 21 |
全量 `npm test`**3218** tests / **3134** pass / **69** fail / **15** skipped。失败名单见下,全是环境缺口。
## 5.1 分类表(15 个,不得砍)
| 状态 | 类别 | 谁在读 | 处置 |
| --- | --- | --- | --- |
| `rectificationSessionId` | 外壳也要读 | `Home``rectificationSurfaceOpen``?c=` 自动打开、bootstrap `rectificationSettled`、组件 `key``useSessionManagement`:历史校正是否延后切换 | 留在外壳对象 `sessionId` |
| `rectificationCaseId` | 外壳也要读 | `Home`:是否挂上校正面(`rectificationSurfaceOpen && rectificationCaseId`)、`key` | 留在外壳对象 `caseId` |
| `rectificationOpeningSessionId` | 外壳也要读 | `AppSidebar` `openingSessionId`(侧栏「正在打开」) | 留在外壳对象 `openingSessionId` |
| `rectificationLoading` | 外壳也要读 | 首页卡文案「正在打开」、自动打开守卫、`StarterHome` `data-opening` | 留在外壳对象 `loading` |
| `rectificationMutationPending` | 外壳也要读 | `productEntrypointsDisabled`、自动打开守卫、首页卡 disabled | 留在外壳对象 `mutationPending` |
| `rectificationEntrySummary` | 外壳也要读 | 首页卡 action/文案、`StarterHome` 卡片说明 | 留在外壳对象 `entrySummary` |
| `rectificationEntrySummarySettled` | 外壳也要读 | `bootstrapPrepareReady` 揭幕门 | 留在外壳对象 `entrySummarySettled` |
| `rectificationError` | 外壳也要读 | 自动打开守卫、bootstrap settled、首页卡报错、`rectificationErrorMessage` | 留在外壳对象 `error` |
| `rectificationErrorSessionId` | 外壳也要读 | 侧栏行内错误;首页卡在 session 失败时藏同一条 | 留在外壳对象 `errorSessionId` |
| `rectificationShouldStartOpening` | 只服务子树 | 校正面是否自动开场;`onOpeningConsumed` 把它关掉 | 搬进 `useRectificationSurface` |
| `rectificationTurns` | 只服务子树 | 挂载前 hydrate 的 `initialTurns` | 搬进 hook |
| `rectificationSnapshot` | 只服务子树 | 挂载前 hydrate 的 `initialSnapshot` | 搬进 hook |
| `rectificationPendingQuestion` | 只服务子树 | 校正面 `pendingConsultationQuestion` | 搬进 hook |
| `rectificationReadonly` | 只服务子树 | 校正面只读 | 搬进 hook |
| `rectificationHeaderSlot` | 只服务子树 | 值只给校正面 portal**setter** 仍是外壳 header 的 `ref` | 状态在 hook`Home` 只用 `setRectificationHeaderSlot` |
外壳留下 **1 个** `useState``rectification` 对象,9 个字段)。没有多留第二个散装校正 state。`rectificationSessionOpenerRef` 仍在 `Home``useSessionManagement` 必须在 surface hook 之前调用,用这个 ref 把 opener 递过去。
## 收尾实测
| 指标 | 改前 | 改后 |
| ---: | ---: | ---: |
| `Home()` `useState` | 66 | **52**(≤53;搬走 14 |
| `Home()` `useRef` | 41 | **39**(未上升;`resumeRectificationSession` / `rectificationOpenInFlight` 进 hook |
| `page.tsx` 行数 | 1951 | **1931** |
| hook 参数(type 字段) | 39 | **24** |
| `ConversationalBirthTimeRectification` propstype 字段) | 20 | **7**`declaredTime` / `models` / `selectedModelId` / `onSelectModel` / `onOpenBilling` / `onSaved` / `panel` |
`useRectificationSurface` 现在自己 `useState` / `useEffect` / `useRef`。子树字段打成 `rectificationPanel` 交给包装组件;包装仍 `return <RectificationAgenticChat {...props} />`
## 既有断言改动
| 文件 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `home-shell-growth-contract.test.ts` 三门 | useState **66** / useRef **41** / 行数基线 **1951** | **52** / **39** / **1931** | 本单下沉后的新基线 |
| `consultation-entrypoint.test.ts` 三处 pending / 一处 onPendingChange / 一处挂载守卫 | JSX `pendingConsultationQuestion={rectificationPendingQuestion}``onPendingChange={setRectificationMutationPending}` | hook panel 字段 `pendingConsultationQuestion: rectificationPendingQuestion``onPendingChange: setRectificationMutationPending`;守卫内 `panel={rectificationPanel}` | 子树 props 收到 panel |
| `rectification-agentic-entry.test.ts` shouldStartOpening / onOpeningConsumed / initialTurns / onMessagesChange / headerSlot | 同上,JSX `={...}` | hook panel 冒号字段;page 仍 `ref={setRectificationHeaderSlot}` | 同上 |
| `rectification-surface-contract.test.ts` initialSnapshot | JSX `initialSnapshot={rectificationSnapshot}` | `initialSnapshot: rectificationSnapshot` | 同上 |
| `rectification-history-open-20260909.test.ts` | `const [rectificationErrorSessionId, setRectificationErrorSessionId]` | `errorSessionId: rectificationErrorSessionId` + `setRectificationErrorSessionId` | 外壳 9 字段合成一个对象 |
未弱化其它既有断言。`rectification-*.test.ts` 除 Windows symlink 整文件红的 `rectification-v9-agent.test.ts`(基线已红)外全绿。
## 反向验证
`Home()` 里插入 `const [_growthContractProbe, _setGrowthContractProbe] = useState(false);` 后:
```
not ok 1 - Home() useState count must not grow
error: 'Home() has 53 useState calls; cap is 52. ...'
# tests 3 / pass 2 / fail 1
```
`useRef` 与行数粗护栏仍绿。随后删掉探针,文件回到 52/39/1931。
## 测试
| 命令 | 结果 |
| --- | --- |
| `node node_modules/typescript/bin/tsc --noEmit` | **0 错** |
| `npm run lint` | **0 error** / **120** warningfreeze-metric 记 119;本单多 1 条:入口摘要 effect 的两个外壳 setter 不是 `useState` setter`exhaustive-deps` 提醒。不能把它们放进 deps,否则每帧重拉摘要。未顺手修既有 warning) |
| 定向 `npx tsx --test tests/home-shell-growth-contract.test.ts tests/consultation-entrypoint.test.ts tests/home-bootstrap-reveal.test.ts tests/rectification-agentic-entry.test.ts tests/rectification-history-open-20260909.test.ts tests/rectification-surface-contract.test.ts` | **98 pass / 0 fail** |
| `npx tsx --test tests/rectification-*.test.ts`(加上述合同) | 除 `rectification-v9-agent.test.ts` 整文件 `SkillPackageRegistryError`EPERM symlink,基线已有)外 fail=0 |
| `npm test` | **3218** / **3134** pass / **69** fail / **15** skipped。失败名单与开工基线 **69 条逐条相同** |
| `npm run build` / `next build --webpack` | 见下 |
## 全量失败清单(与开工基线逐条相同,环境缺口)
`admin code functions reject immutable codes…``operation-level admin email reauthentication…``rectification agent maps setup failures…``public code never imports the internal dynamic choice contract``tests\\birth-time-guide-agent.test.ts``candidate scores stay out of the specified client ownership boundary``tests\\consultation-agentic-runtime.test.ts``tests\\consultation-birth-time-mode.test.ts`methodology 8 条(`the route's own strict checklist…``the delivered method is quoted…`);`tests\\consultation-workflow-request.test.ts`database/backup/env 一批(`admin customer reset…``database roles have no cluster privileges`);`every color token used as a Tailwind utility…`compose/env/YAML/sync/deploy 一批;`tests\\rectification-v9-agent.test.ts``tests\\skill-binding.test.ts``checked-in registry verifies hashed product packages…`symlink 3 条;`live consult skill reads a hand-updated tree…``changed staging workflows are syntactically valid YAML``live staging sync…` 两条;`first immutable deployment…``deployment scripts pass shell syntax validation``is-docs-only-range.sh…`
无 Docker、无 Git Bash、Windows 不能为 skill runtime 建 symlink。不是本单回归。
## `next build`
默认 Turbopack 在 worktree `node_modules` junction 上会 panic(与 R3 相同)。`next build --webpack`Compile + TypeScript 预期能过;Collecting page data 在 Windows `EPERM` 无法为 `SKILL.md` 建 runtime symlink 时失败。本机看不到 `○ /` 路由表。源码:`page.tsx``force-dynamic`;未改 `layout.tsx` / `globals.css`。首屏 gzip 上次实测 584,413 B,本机未能从构建产物复核 ±2%。
## 真人走查
`docs/testing/home-state-lowering-20260915.md`:进入 / 退出 / 刷新 / 首页卡片打开 / 历史校正 / 开场自动触发 / 只读 / 报错 / 换模型 / 采用后回首页。本仓无登录态、无 Chrome,未测。
## 发现的交互缺陷(本单不修)
无新增。入口摘要 effect 多了一条既有风格的 `exhaustive-deps` warning,见上。
## 未做(范围外)
- `session*` / `profile*` / `synastry*` / `account*` 四簇
- Context Provider 或外部 store
-`origin HEAD:staging`
-`docs/tasks/README.md` 状态列