refactor(home): 校正面 15 个状态从 Home 下沉
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:
@@ -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` props(type 字段) | **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` props(type 字段) | 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** warning(freeze-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` 状态列
|
||||
Reference in New Issue
Block a user