# PROGRESS · 校正会话已结算行记忆化(2026-09-15) 工作树:`.worktrees/rectification-settled-render-split-20260915` 分支:`codex/rectification-settled-render-split-20260915` 开工基线:`origin/staging` @ `a8d29d1b`(任务书写的 `6b3248bf` 已被后续合入;以当前 origin/staging 为准) 开工后远端又快进 1 个纯文档提交 `11893c7f`(普通聊天审计三单),本分支 rebase 到其上。 **BUG 编号:** 本树最大号仍是 **BUG-720**。721–724 / 726 未进本树,**BUG-725** 无冲突,未顺延。 未改 `docs/tasks/README.md` 状态列。未 `git push origin HEAD:staging`。未碰 `page.tsx`、`route.ts`、Python 引擎、React Compiler、`React.lazy`。未改 DESIGN.md(无可见样式变化)。未新写第二套输入框 / 滚动跟随 / 加载动画。 ## 改前红 / 改后绿 ### 5.4 结算态 Markdown 解析次数 同一段文本连续 `renderToString` 两次,可计数桩 renderer: ``` # 改前(StableMarkdownPrefix 已 export,尚无内容缓存) not ok 5 - settled markdown parses the same text only once across consecutive renders Expected values to be strictly equal: 2 !== 1 ``` ``` # 改后(rememberedProse + 结算口语/报告走 StableMarkdownPrefix) ok 5 - settled markdown parses the same text only once across consecutive renders # tests 5 # pass 5 # fail 0 ``` ### 5.5 按帧渲染计数 ``` # 改前(行组件文件尚不存在) Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../frontend/src/components/rectification-message-entry.tsx' not ok 1 - tests\\rectification-settled-render-split.test.ts ``` ``` # 改后 ok 1 - the chat container no longer derives per-row timeline, varga, or choice cards ok 2 - the extracted row is memoised and takes no function props except actionsRef ok 3 - the split architecture renders settled rectification rows once while streaming tokens # tests 3 # pass 3 # fail 0 ``` 手驱动 4 条已结算 + 5 个流式帧:拆分路径 `settledRowRenders = 4`、`streamingRowRenders ≤ 5`;未拆分对照 `unsplitListRenders = 5`、`settledRowRenders = 25`。拆分计数严格小于对照。 ## 做了什么 | 任务 | 状态 | 落点 | | --- | --- | --- | | 5.4 结算态 Markdown 记忆化 | 完成 | `chat-message-content.tsx`:`StableMarkdownPrefix` 加按文本解析缓存;结算口语层与报告层都走它 | | 5.1 抽出 `RectificationMessageEntry` + `memo` | 完成 | 新文件 `rectification-message-entry.tsx`;时间轴 / varga / choiceCard / afterAnswer 全部在组件内 | | 5.2 `actionsRef` | 完成 | 容器 `useEffect` 每帧写 `.current`(与咨询面 `page.tsx` 相同,避免渲染期写 ref 撞 `react-hooks/refs`) | | 5.3 `ChatMessageRow` `memo` | 完成,未砍 | 咨询面同样受益 | | 5.5 渲染计数断言 | 完成,未砍 | `tests/rectification-settled-render-split.test.ts` | | 5.6 BUG-725 | 完成,未砍 | 关联 BUG-473、BUG-249 | 交付卡 / 只读范围仍在容器 `messages.map` 里(标量 host 判定 + 既有 `candidateResult` state),不把每帧新建的 JSX 当行 props。 ## 验收命令 | 命令 | 结果 | | --- | --- | | `./node_modules/.bin/tsc --noEmit` | 退出 0,无输出 | | `npm run lint` | **0 error**,119 warning(既有,本单未新增、未顺手修) | | `npx tsx --test tests/rectification-*.test.ts tests/home-streaming-render-split.test.ts tests/chat-markdown-split.test.ts tests/stream-frame-buffer.test.ts` 及本单改过的合同文件 | 定向套件 fail=0 | | `npm test` | **3108** 条(含本单新增 4 条:结算 Markdown 1 + 行拆分 3)。pass 3021 / fail 73 / skipped 14。失败清单见下,均为环境缺口,不是本单回归 | | `npm run build` | 默认 Turbopack 因 worktree `node_modules` junction 指向主仓而 panic(`points out of the filesystem root`) | | `next build --webpack` | Compile + TypeScript 通过(3.7 min + 46 s)。Collecting page data 在 `/api/birth-time-guide` 因 Windows `EPERM` 无法为 `SKILL.md` 建 runtime symlink 而失败。本机看不到 `○ /` 路由表。`page.tsx` / `layout.tsx` / `globals.css` 未改,首屏源码差为 0 | ## 全量失败清单(环境缺口,与本单无关) Windows、无 Docker、无 Git Bash、skill runtime 不能建 symlink。典型几类: - `database-*.test.ts` / 迁移 / RLS / Better Auth:无 Docker - `skill-binding` / `rectification-v9-agent` / `rectification-v9-stream` / `rectification-exhaustion-exit` 等整文件:`SkillPackageRegistryError` `EPERM: symlink` - `*.sh` / staging sync / compose env / is-docs-only-range:Windows 无 POSIX shell - `every color token used as a Tailwind utility is exposed through @theme`:既有 warning 级合同,本单未改 CSS 本单引起、后来已修的合同红(改 token 路径,三栏见各测试注释):`chat-answer-detail`、`chat-bundle-splitting-contract`、`rectification-agentic-entry`、`rectification-spoken-collect`、`rectification-surface-contract`、`chat-composer-queue`、`rectification-adopt-flow`、`rectification-delivery-ui-simplify`、`rectification-targeted-card-live`、`rectification-timeline-adapter`、`chat-stream-layout`、`agent-voice-copy-contract`、`rectification-question-in-message`、`rectification-varga-style-copy`、`rectification-walkthrough-polish`。修完后这些在定向重跑里全绿。 ## 既有断言三栏(摘要) | 文件 | 原值 | 新值 | 原因 | | --- | --- | --- | --- | | `chat-markdown-split.test.ts` | `: renderProse(spoken, renderMarkdown)` | `: ` | BUG-725 结算口语层记忆化 | | `chat-bundle-splitting-contract.test.ts` | `renderProse(spoken/report)` 计数 2 | `StableMarkdownPrefix` 结算两层计数仍为 2;尾块仍 `renderProse(split.tail)` | 同上,计数不放宽 | | `chat-answer-detail.test.ts` | `{renderProse(report, renderMarkdown)}` | `` | 报告层同样记忆化 | | 若干校正源码合同 | token 在 `rectification-agentic-chat.tsx` 的 `messages.map` | 同一 token 在 `rectification-message-entry.tsx` | 5.1 抽出行组件 | ## 真人验收 `docs/testing/rectification-settled-render-split-20260915.md`。本环境无登录态、无 Chrome,长会话是否还卡**未测**,不要写成通过。 ## 明确未做 - 把流式文本从 `messages` 搬进独立 state(任务书 §3.4 否决) - React Compiler - 首屏包体积(584 KB gzip 是全站壳,另议;本单未改首屏源) - 校正面任何交互缺陷