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

13 KiB
Raw Blame History

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。