Files
Jyotisha/docs/tasks/TASK-report-language-switch-stale-20260930.md
T

6.6 KiB
Raw Blame History

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/health deployment.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. 决策记录

  1. 产品 2026-09-30 反馈「切换不管用」。修复只动 key,不改英文版的生成、存储、接口,也不改切换的交互。
  2. 沿用 TASK-report-english-edition-20260929.md 决策 6:切换只换正文、目录、图盘标签、核对表,应用外壳保持中文。本单不推翻任何既有决策。

4. 硬红线

  1. 只改 personal-report-page.tsx 里这两处 key,加测试和记录;不顺手重构阅读页,不动 PersonalReportMarkdownView 的懒渲染和保留章节逻辑(BUG-1106~1108)。
  2. 不改 report-english-edition.test.tsx 的既有断言;如果必须改,写「原值 / 新值 / 原因」三栏。
  3. 测试 fixture 用仓库里已有的真实引擎虚构盘 golden(report-reader-main-fictional*.json、report-density-fictional-engine.json),不手造形状(AGENTS §7-4)。
  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 组装),然后:

  1. 以 initialLanguage="zh" 打开 → 点 English → 断言正文区块只有 1 份、目录标题是 Contents、第一个 h2 是英文、正文不含汉字;
  2. 再点中文 → 正文区块只有 1 份、目录是「目录」;
  3. 以 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 --noEmit 0 错;npm run lint 0 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