Files
Jyotisha/docs/tasks/TASK-mobile-chart-and-confirmed-edit-20260929.md
T
2026-09-29 08:26:28 +08:00

133 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK · 手机上星盘显示不全 + 已确认出生时间改资料后跟着变 + 「那一刻的天空」改为动画定格(2026-09-29)
## 基线与依赖
- 基线:`origin/staging` = `da989c15`(本人编辑 + 头像菜单已部署)。开工前 `git fetch origin --prune`,基线 SHA 写进 PROGRESS。
- 分支 / 工作树:`codex/mobile-chart-confirmed-edit-20260929` / `.worktrees/mobile-chart-confirmed-edit-20260929`。
- 进度:`docs/tasks/PROGRESS-mobile-chart-confirmed-edit-20260929.md`。
- 不改 `page.tsx`。同日若有别的单改 `globals.css` 里 `.chart-page-*` 或 `lib/account-profile-patch.ts`,先停下告知 Claude。
- BUG 编号:开工时核对 `docs/BUG_HISTORY.md` 最大号(写作时 BUG-1082)。本单 M1 记 **BUG-1083**;M2 是产品决策,改的是 BUG-264 以来锁住的行为,在 BUG-264 下追加「2026-09-29 产品修订」,不另开号。
## 事实
### M1 · 手机上星盘显示不全(产品 2026-09-29 真机截图,iPhone,staging,星盘 → Bhava)
- 北印度盘远大于屏幕,右侧与下方被裁掉。星盘卡片左边框可见,右边框在屏幕外。下面的参数表与行星表看不到。
- 按截图倒推,盘面所在列约 **540px 宽**,屏幕约 390px。这与 `.chart-page-planet-table { min-width: 34rem; }`(`globals.css`,34rem = 544px)吻合。推测:宽表的最小内容宽度一路向上撑开了某层网格或弹性容器的列宽,盘面 `width:100%` 跟着变大。
- 已排除:`.chart-page-varga-table-block`、`.chart-page-planet-table-wrap`、`.chart-page-vedic` 都已有 `min-width: 0`。**哪一层没收住还没找到**,候选有:
- `.chart-page-vedic-layout`(窄屏下只有 `display:grid`,没有 `grid-template-columns`,隐式列是 `auto`,本身也没有 `min-width:0`);
- `.chart-page-params`;
- 更外层的星盘页面板与 `SecondaryPageShell`。
- 本命、D9、Bhava 各页的盘下都有宽表,所以很可能不止 Bhava 一页。9-28 的盘型改造(BUG-1076~1078)把行星表从 26rem 放宽到 34rem,这可能是诱因。
### M2 · 已确认的出生时间,改资料后排盘不变
- `lib/account-profile-patch.ts` `resolveAccountBirthTimeApplicationPatch`:当前 `birth_time_status === "confirmed"`(或 legacy 有分钟、状态为空)时直接 `return {}`。于是改了出生日期 / 时间 / 地点,`active_birth_time` 仍是旧的已确认分钟,星盘按旧时间排。
- 锁定这条行为的是 `frontend/tests/account-api.test.ts` 的测试 “ordinary declaration edits clear stale candidate application but never overwrite confirmed active time”,来自 BUG-264。
- 现在本人可以在 `/people` 编辑资料(BUG-1081),这个行为第一次对用户可见。
## 决策记录(产品 2026-09-29)
1. **M2:用户改了出生资料,就按新资料排盘,即使原来是「确认」状态**(包括采用过校正结果)。产品原话:「用户改生日肯定是得到信息了」。
- **这推翻了 BUG-264 起「已确认分钟不被普通资料修改覆盖」的约定**,以及 `account-api.test.ts` 上面那条测试的对应断言。执行方不得以既有约定为由拒改。
- 只有**声明字段**(`declarationFields`:出生日期、时间与来源、时段 / 范围、地点代码等)真的变了才重置;只改称呼、岁差、性别、头像,**不得**动已确认时间。
- 重置后与非确认状态的现有做法完全一致:给了精确的零误差时间就是 `accepted` + 新分钟,否则是 `reported`;`rectification_case_id` 清空。
2. M1 是缺陷,按「手机上完整看到盘、表格在自己的框里横向滚动」修,不改桌面布局。
3. **M4:星盘页点「那一刻的天空」,改为重放群星汇聚动画并定格在最后一帧,右上角「分享」才导出海报**。产品原话:「点击那一刻的天空,然后重新跑咱们的星星动画,最后定格到最后一帧,然后右上角可以分享,分享的时候才是咱们的海报」。
- 这替换了 polish 单 P1 的「压暗页面 + 静态图 + 图下保存图片」弹层。
- 首次建盘过场(首页)不变:仍然放完自动淡出。
4. **M5:去掉报告里的星图封面**(产品 2026-09-29:「报告首页的那个星图封面需要去掉」)。这推翻了 `TASK-birth-sky-followup-20260928` 的 F2 / F3(屏幕与打印封面、`coverSubject` 下发)。F1(生成时写入 `subject.birthFingerprint`)保留:不花钱、旧文档兼容,将来想绑定报告与资料时还能用。
## 硬红线
1. M1 只改 CSS / 结构,不改盘面绘制与数据;桌面 ≥1024px 的两栏布局不变。表格仍然是在自己的容器里横向滚动,不许为了不溢出把列挤坏或删列。
2. M2 只改服务端派生(`account-profile-patch.ts` 与账户路由),客户端不得自己写 `active_*` 或 `birth_time_status`。
3. M2 必须一并清掉跨午夜采用写入的 `active_birth_date`、`active_birth_timezone_offset`、`active_birth_provenance`(若当前行有值),不能留下「新日期 + 旧的已采用日期」的半截状态。先查清这三列由谁写入、谁读取,写进 PROGRESS。
4. 查清 `profiles` 上当前生效的触发器(`guard_birth_time_journey` 等最新版本)会不会把重置改回 `confirmed`,结论写进 PROGRESS。本机没有 Docker 跑不了 `npm run test:db`,这一项写成环境缺口,并在真机清单里列一条 staging 实测。
5. 改既有断言写「原值 / 新值 / 原因」三栏。**前端改动也要跑 Python quick 门禁**(上一单因为没跑,Python 合同测试在门禁 run 1584 上红了)。
6. 不加依赖,不改表、不加迁移(若确认必须改触发器才能生效,先停下告知 Claude,不要自行加迁移)。
## 任务分解
### M1 · 手机上星盘完整显示(BUG-1083)
- **先复现**:在无头 Chrome 里用真实组件和虚构数据(golden 夹具)搭星盘页,视口 390×844。本命、D9、Bhava、行运、D10 各截一张,量出每一层容器的实际宽度,找出第一个宽度超过视口的祖先,并写进 BUG-1083 的根因。
- **修**:在找到的那一层收住宽度(例如补 `min-width: 0`,或窄屏下给网格 `grid-template-columns: minmax(0, 1fr)`)。同类布局 `.chart-page-dasha-columns`、`.chart-page-western-layout`、`.chart-page-basics-grid` 一并检查,同样有问题就一起修。
- **验收**:
- 修复前后各截 390×844 的五张图,外加 1280×900 一张,确认桌面不变;截图放 scratchpad,路径写 PROGRESS。
- 390 宽时页面没有横向滚动,盘面宽度 ≤ 视口,表格在自己的框里能横向滑动。
- 加一条回归测试,锁住修复的那条 CSS 规则(按源码文本断言即可,写明对应 BUG-1083)。
- 如果能在无头 Chrome 里断言 `document.documentElement.scrollWidth <= innerWidth`,就加上。
### M2 · 已确认时间,改声明字段后重置
- 改 `resolveAccountBirthTimeApplicationPatch`:去掉「confirmed 直接返回 {}」。改为:声明字段有变化时,confirmed 也走与 reported 相同的派生;没有变化时维持原样(包括 legacy 分钟)。
- 按硬红线 3,把跨午夜三列也纳入重置。
- 账户路由里依赖「confirmed 不变」的并发守卫(`applyAccountProfileConcurrencyGuards`)要核对仍然正确。
- 客户端:`/people` 保存本人后,已有的缓存失效逻辑要能让星盘页拿到新的排盘时间。用单测证明保存后读取到的是新分钟。
- **验收(测试)**:
- confirmed + 改出生时间(精确) → `accepted` + 新分钟,`rectification_case_id` 为 null;
- confirmed + 改成时段 → `reported`,`active_birth_time` 为 null;
- confirmed + 只改称呼 / 岁差 / 性别 → 不变;
- confirmed + 跨午夜三列有值 + 改日期 → 三列清空;
- legacy(状态空、有分钟)+ 改时间 → 重置;不改则不变。
- `account-api.test.ts` 那条旧测试改名并改断言,三栏说明。
- BUG-264 下追加「2026-09-29 产品修订」一段:写明原约定、新决定、影响(改资料会让已采用的校正结果失效)。
### M4 · 「那一刻的天空」:重放动画 → 定格 → 右上角分享
- 星盘页点「那一刻的天空」后,打开全屏层:
- 复用首页过场的同一套时间轴与绘制(`lib/birth-sky/converge.ts` `birthSkyRevealAt` + `drawBirthSky`,组件 `components/birth-sky/birth-sky-converge.tsx`),加一个「定格」模式:汇聚 → 文字淡入 → **停在最后一帧**,不淡出,不自动关闭。每次打开都从头重放。
- 定格帧就是导出海报(沿用「最后一帧与导出封面逐调用一致」的测试)。
- 播放中点一下,直接跳到定格帧,不关闭。
- 系统开了「减少动态效果」:不汇聚,直接淡入到定格帧。
- 按钮(定格前后都在,深色底上可读,44px 触控):
- 左上角 ×:关闭(Esc 也关闭)。
- 右上角「分享」:导出海报 PNG,走现有 `saveBirthSkyImage`(能调系统分享就分享,不能就下载);失败提示沿用现有文案。
- 不再有图下方的「保存图片」按钮。
- 不等待:点按钮时若海报 PNG 还没画好,仍然先开始放动画;PNG 在后台画,「分享」按钮在 PNG 就绪前禁用,不加 spinner。星盘页已有的预取(`use-birth-sky-cover`)照用,入口按钮仍然只在数据就绪后出现。
- 删掉 polish 单的静态图弹层(`birth-sky-dialog.tsx` 里只给它用的结构与样式),确认没有别处引用。首页过场的淡出行为不变。
- **验收**:
- 测试:定格模式时间轴在终点停住,不淡出、不调用 onDone;点击跳到终点不关闭;reduced-motion 直接到终点;× 与 Esc 关闭;「分享」调用 `saveBirthSkyImage`,PNG 未就绪时禁用;首页过场仍会淡出并关闭(原测试保留)。
- 无头 Chrome:390×844 与 1280×900 各截「播放中」与「定格」两张,放 scratchpad,路径写 PROGRESS。
- DESIGN §17 与 VOICE(「分享」按钮文案)同步。
### M5 · 去掉报告星图封面
- 删除:`components/birth-sky/report-sky-cover.tsx` 与 `report-sky-cover.css`、`lib/birth-sky/report-cover.ts`、`personal-report-page.tsx` 里的动态导入与挂载点、`classifyReportEnvelope` 里的 `coverSubject` 解析与 `ReportLoadState` / `ReportEnvelopeView` 上的字段。
- 服务端:`reportView` 的 `coverSubject` 参数、`readyReportCoverSubject`、报告详情路由的 `loadCurrentBirthFingerprint` 一并删掉。没人用了,每次读报告就不必多查一次人物资料。`lib/report-birth-binding.ts` 只保留 F1 写入用到的函数,只给比对用的删掉。
- 保留:F1 的写入路径、`subject.birthFingerprint` 的 schema 可选字段及其测试。
- 测试:`report-sky-cover.test.ts` 删除;`report-birth-binding.test.ts`、`personal-report-api.test.ts` 里只测封面比对与 `coverSubject` 的用例删除或改成「详情响应不再有 `coverSubject`」。按 §7.3 把消失的测试名逐条列进 PROGRESS,并写原因(产品决定去掉封面)。
- `BLOCKED.md` 里 T5 那条保持划掉,追加一句「→ 2026-09-29 产品决定去掉报告封面」。
- **验收**:报告页没有封面,打印第一页是正文;报告详情响应不含 `coverSubject`;grep `ReportSkyCover` / `report-sky-cover` / `coverSubject` 在 `src/` 下为 0。
### M3 · 文档
- `frontend/DESIGN.md`:星盘页窄屏布局一句。
- `CHANGELOG.md`:两条。
- `docs/BUG_HISTORY.md`:BUG-1083;BUG-264 的修订段。
- `docs/testing/mobile-chart-confirmed-edit-20260929.md`(新建真机清单):
- iPhone 上星盘页的本命、D9、Bhava、行运、D10 都能看到完整的盘,表格能左右滑;
- 用采用过校正结果的账号,在星盘档案里把出生时间改掉:星盘页按新时间排,报告封面对旧报告不再显示;
- 只改称呼:排盘时间不变;
- 打开任意一份报告:顶部没有星图封面;打印 PDF 第一页就是正文;
- 星盘页点「那一刻的天空」:每次都重放汇聚,定格;右上角「分享」在手机上弹出系统分享、在电脑上下载;× 关闭。
## 验证
- `tsc --noEmit` 0 错;`npm run lint` 0 error。
- `npm test` 全量:与基线比测试名清单,不得有测试名消失;失败清单与基线(24 条 Docker / DB / 部署)逐条同名。
- **`python3 scripts/run_quality_gate.py --profile quick --skip-yoga-logic --skip-frontend-runtime`(与门禁同参数)必须通过**;`python3 scripts/commercial_privacy_artifact_scan.py --json` 为 pass。
- `rm -rf .next && next build`:`/` 仍 `○ Static`;首屏 gzip 与基线同口径对比,变化在 ±2% 内。
## 让步顺序
1. 同类布局(大运 / 西洋盘 / 基础信息)没有复现问题的,可以不改。
2. M1 的无头 Chrome `scrollWidth` 断言可以只留截图证据。
3. M4 在 1280 宽下的截图可以只留定格一张。
4. M1 手机上完整显示、M2 确认状态下改资料会重置、硬红线 3 的跨午夜三列、M4 定格帧 = 海报、M5 去掉报告封面,**不可让步**。
## 交付
- M1、M2、M4、M5+M3 分提交,**不推送**;由 Claude 独立验收后快进推 staging。