Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
6.6 KiB
TASK · 报告阅读页切换语言后正文不换 · 2026-09-30
执行方:coding agent。验收:Claude。 分支
codex/report-language-switch-stale-20260930,worktree.worktrees/report-language-switch-stale-20260930,基线origin/staging。 BUG 编号:BUG-1126(Claude 写单时已登记为 investigating;开工时核对docs/BUG_HISTORY.md最大号,若已被占用顺延并同步改本单)。 纯前端改动,不需要 AGENTS §9 预检。
0. 基线
- 写单时
origin/staging=da3ed2f3(staging/api/healthdeployment.gitCommit同为da3ed2f3)。 - 开工前先
git fetch origin --prune,以实测origin/staging为准,写进docs/tasks/PROGRESS-report-language-switch-stale-20260930.md。
1. 事故实证
产品 2026-09-30 在 staging 实测,桌面 Dia 与 iPhone 两台设备都能复现:
- 进报告页后点「English」:地址栏会变成
?lang=en,开关也显示 English 已选中,但正文、目录(标题仍是「目录」)还是中文版。 - 直接带
?lang=en打开:正文是英文;这时点「中文」,开关会变,正文仍是英文。 - 导出面板里的「中文 / English」和导出的英文文件都正常,说明英文版数据已经完整送到浏览器。
Claude 复现情况(staging 线上 JS + 无头 Chrome;报告接口用虚构出生资料的真实引擎输出替换,也伪造了登录态):
| 响应里有什么 | 点切换后 |
|---|---|
只有 longformMarkdown / longformMarkdownEn |
正常:正文区块始终 1 份,目录变 Contents |
再加上 factTables / factTablesEn(真实报告都有) |
复现:.personal-report-md-layout 1 → 2 → 3 份,旧语言那份一直留在最上面;开发版 React 报 Encountered two children with the same key |
2. 根因
frontend/src/components/personal-report/personal-report-page.tsx → PersonalReportPage 的 markdown-ready 分支,在 .personal-report-reader-body 下同级渲染:
<PersonalReportMarkdownView key={shown} … />
{state.calculationCharts && <ReportCalculationCharts … />}
{factTables && <ReportFactTables key={shown} … />}
两个同级元素的 key 都是 shown("zh" / "en"),发生重复。每次换语言,React 按 key 对齐时旧节点清不掉,旧语言的正文留在页面上,新语言的正文追加到后面,所以读者看到的一直是第一次渲染的那个语言。开关读的是同一个 shown,所以只有开关在变。
- 引入提交:
b2ad772e(英文版上线,两处key={shown}同时加入)。 - 既有测试没拦住:
frontend/tests/report-english-edition.test.tsx只单独测了ReportActions(开关)、classifyReportEnvelope和导出面板,没有把整页连同核对表一起渲染再切换。
Claude 已验证修复方向:把两个 key 改成互不相同(例如 markdown-${shown} / facts-${shown})后,同一复现环境里切换一次就换成英文、正文区块 1 份、0 个含汉字的章节。验证后已还原,没有提交任何代码。
3. 决策记录
- 产品 2026-09-30 反馈「切换不管用」。修复只动 key,不改英文版的生成、存储、接口,也不改切换的交互。
- 沿用
TASK-report-english-edition-20260929.md决策 6:切换只换正文、目录、图盘标签、核对表,应用外壳保持中文。本单不推翻任何既有决策。
4. 硬红线
- 只改
personal-report-page.tsx里这两处 key,加测试和记录;不顺手重构阅读页,不动PersonalReportMarkdownView的懒渲染和保留章节逻辑(BUG-1106~1108)。 - 不改
report-english-edition.test.tsx的既有断言;如果必须改,写「原值 / 新值 / 原因」三栏。 - 测试 fixture 用仓库里已有的真实引擎虚构盘 golden(
report-reader-main-fictional*.json、report-density-fictional-engine.json),不手造形状(AGENTS §7-4)。 - 不动数据库、不升级依赖、不改 workflow。
5. 任务分解
T1 · 去掉重复 key
PersonalReportMarkdownView 与 ReportFactTables 的 key 改成互不相同,且仍随语言变化(保证换语言时两者都会重新挂载)。同一父级下其他带 key 的子元素一并检查。
验收:personal-report-page.tsx 中 .personal-report-reader-body 的直接子元素没有重复 key。
T2 · 整页切换回归测试(先红后绿)
新增测试:渲染 PersonalReportPage,mock fetch 返回 ready 报告,同时带 longformMarkdown、longformMarkdownEn、factTables、factTablesEn(用 golden 组装),然后:
- 以
initialLanguage="zh"打开 → 点 English → 断言正文区块只有 1 份、目录标题是 Contents、第一个 h2 是英文、正文不含汉字; - 再点中文 → 正文区块只有 1 份、目录是「目录」;
- 以
initialLanguage="en"打开 → 点中文 → 同样断言。
验收:在未修复的基线上这条测试是红的(进度记录贴失败输出),修复后是绿的。如果现有测试台(react-client-lifecycle-test-support)跑不了整页,说明原因并换可行的方案,不得退回只测组件。
T3 · 记录
docs/BUG_HISTORY.md的 BUG-1126 补齐修复、验证、防复发,状态改为 resolved(待部署、真机待产品)。CHANGELOG.md加一条:报告阅读页中英切换恢复正常。docs/testing/report-english-edition-20260929.md追加一条真机步骤:先中文打开,切 English,再切回中文,每次正文与目录都要跟着变,正文不能出现两份。- 本单不改 UI 外观,
DESIGN.md不用更新。
6. 验收口径
./node_modules/.bin/tsc --noEmit0 错;npm run lint0 error。npm test失败清单与基线逐条一致,总数不少于基线加新增条数。next build通过,/仍是 Static;首屏 gzip 在 ±2% 内(预期不变)。- 交付:快进推
origin/staging,核对远端 SHA;部署后/api/health的deployment.gitCommit等于该提交。
7. 让步顺序
时间不够时按这个顺序保:T1 → T2 → T3。T1 和 T2 必须一起交付,不接受只改代码不加回归测试。
8. 开工前置命令
cd /workspace/Jyotisha && git status -sb | head -1
git fetch origin --prune
git worktree add -b codex/report-language-switch-stale-20260930 .worktrees/report-language-switch-stale-20260930 origin/staging
cd .worktrees/report-language-switch-stale-20260930/frontend && npm ci # 各 worktree 需自己装依赖;Node 22 在 /exec-daemon/node
grep -o "BUG-[0-9]\{3,4\}" ../docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1