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.
10 KiB
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状态列