Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
8.3 KiB
8.3 KiB
TASK · Chara 0 年大运崩溃 + 星历切日期旧数据 + 星盘无资料空状态(2026-09-24)
基线
origin/staging = 9c9b66d6。分支codex/chart-ephemeris-fixes-20260924。- 串行:T1、T2 可立即做;T3 碰
page.tsx/settings-url.ts,排在TASK-home-slow-network-20260924.md合入之后(或 T3 单独后合)。大运页、西洋盘 UI 重做不在本单(等原型定稿另出单),本单只修 bug 不改版式。
事故实证
T1 · 大运右栏「这张盘算不出来,我们已经记录下来了。」
frontend/src/lib/chart-view-mapper.tscharaTrack()→addWeightedSpan(start, end, index, weights),权重finite(duration_years) ?? 1;?? 1不替换0。某段 Chara 大运为 0 年时 12 个子运全为 0 →total = 0→0/0 = NaN→new Date(NaN).toISOString()抛RangeError。chart-view-load.tsassembleChartViewcatch 非 ZodError →engine_bad_payload→use-chart-page.tsrequestLayerfail(...)→chartLayerFailureCopy→unavailable句。- 0 来自
scripts/jaimini.py_chara_dasha_duration_profile(kn_rao):years = count-1,<=0改 12,之后再按旺 +1 / 弱 -1,于是"一宫之隔且落陷"= 0。排查实测随机 2000 个生日(1960–2005)有 7.8% 至少一段 0 年;虚构 1985-08-03 03:59 北京可复现(Sagittarius 0 年)。 - 引擎响应形状与 mapper 读取路径一致,不是请求或超时问题。
T2 · 星历切换日期,下方仍是前一天数据
frontend/src/components/ephemeris/ephemeris-page.tsxchangeDate:setDate(next); const cached = …; if (cached) setState(ready…),缓存未命中无 else,state.payload保留旧日;顶部日期已是新日。- 回归来源:
9ccb65b7(BUG-966,09-18)删掉原else setState({ phase: "open" }),因为同时加的if (!payload) return <SecondaryPageShell waiting…>会把整页(含日期条)换成等待句。 - 请求失败(429 / 非 JSON / 坏包)时
load直接return,旧数据永久留着,且不重试(effect 只随date变)。 - 挂载时
refreshEphemerisPage()(今天、无 date)不可中止,其回写守卫只比payload.date,会在"切到未缓存日期"期间把今天的数据写回。 app/api/ephemeris/route.ts每切一天都并行重算本命/api/chart(与日期无关),且不把request.signal传给引擎调用。- 违反
frontend/DESIGN.md§16:「切日期立刻换五要素和行运……数据未到时写静态句「这一天的五要素还没拿到。」「这一天的行运还没拿到。」」。 - 无 BUG 记录、无测试覆盖
EphemerisPage状态机(ephemeris-page.test.tsx只静态渲染EphemerisView)。
T3 · 星盘页无出生资料时只有一句话
chart-page-view.tsx:任何非 ok 状态只渲染<section className="chart-page-message"><p>{view.message}</p></section>;birth_profile_incomplete文案「还没有可用来排盘的出生资料。把日期、时间和地点填进星盘资料后,打开就能看见盘。」但没有按钮;lib/settings-url.tsparseSettingsQuery只支持?settings=billing,没有跳到星盘资料的深链。
根因
- T1:mapper 按权重分配时间,未处理总权重为 0;引擎 kn_rao 口径可产出 0 年(合法值,不是引擎错误)。
- T2:BUG-966 为避免整页换等待句,删掉了"未命中就清空",导致日期与数据分叉;失败无出口。
- T3:失败页是纯文案设计,缺行动入口与深链。
决策记录(产品 2026-09-24)
- D1 0 年大运照实显示:该段标注「0 年」,不占时间轴、不展开子运(子运区写「本段时长为 0,不展开」),前后段日期连续;不改引擎口径(kn_rao 规则不动)。
- D2 星历切到未缓存日期:日期条与布局保留,五要素 / 行运区立即换成现有静态句(「这一天的五要素还没拿到。」「这一天的行运还没拿到。」),事件区写新句「换座和停滞还在取。」(不再误用「还没接上」)。不加 spinner / 骨架(星盘骨架例外不外溢到星历)。请求失败 → 各区显示「这一天的星历没取到,点日期再试一次。」,再点同一日期或左右箭头即重试。
- D3 星盘无资料:
chart-page-message加标题「还没有星盘资料」+ 现有文案 + 按钮「去填写出生资料」→ 打开设置弹窗的星盘资料面板(新增深链?settings=chart,与?settings=billing同一 helper)。timezone_resolver_failure/adopted_calculation_incomplete/profile_query_error也给同一按钮(文案各自不变)。样式:居中、标题--type-title-md、按钮为主按钮,其余沿用现有 token。 - D4
/api/ephemeris本命盘按账户 + 资料指纹做服务端短缓存(复用chart-view-engine的cachedPostEngine或同等 5 分钟 TTL),并把request.signal传入引擎调用。
硬红线
- 不改
scripts/jaimini.py口径;不改HEAVY_COMPUTE_PATHS与并发(BUG-717)。 - 星历不得出现骨架 / spinner / 「正在加载」(DESIGN §9 例外只限星盘)。
- 旧日期响应不得覆盖新日期(含挂载时的今天刷新)。
- 深链解析只在
settings-url.ts一处;/、/chart、/ephemeris保持○ Static。 - 既有断言三栏;测试总数不低于基线;不改 Python。
任务分解
T1 · Chara 0 年(chart-view-mapper.ts、chart-dasha-tab.tsx)
addWeightedSpan/charaTrack处理 0 权重与 0 年大运;0 年段在Track里显示「0 年」且无子运列表。
验收:chart-view-mapper 测试用真实引擎响应 golden(虚构 1985-08-03 03:59 北京,按 AGENTS §7.4 由真实 _compute_chara_dasha 生成并入库 fixture)→ 12 段 periods、Sagittarius 段 0 年、无 RangeError、前后日期连续;assembleChartView({layers:["chara"]}) 返回 ok;UI 测试 0 年段不渲染子运。
T2 · 星历(ephemeris-page.tsx、ephemeris-view.ts、app/api/ephemeris/route.ts)
state只在payload.date === date时视为 ready,否则EphemerisView payload={null}(保留日期条);事件区 pending 文案;失败态与重试;挂载刷新守卫比对date;路由本命缓存 + 传 signal。
验收:新增 EphemerisPage 生命周期测试——切到未缓存日期立即显示静态句且日期条仍在;旧响应迟到不覆盖;429 → 失败句,再点重试成功;挂载时今天刷新不覆盖正在看的其它日期。路由测试:同账户连续两天只调一次本命 /api/chart。
T3 · 星盘空状态 + 深链(chart-page-view.tsx、settings-url.ts、设置弹窗打开入口;排在 home-slow-network 之后)
验收:四种资料类失败都渲染按钮;点按钮 → /?settings=chart → 设置弹窗打开到星盘资料;?settings=billing 行为不变;/chart 仍 ○。
T4 · 记录
docs/BUG_HISTORY.md:BUG-1023 Chara 0 年大运前端崩溃(关联 BUG-715、1017);BUG-1024 星历切日期旧数据(复发自 BUG-966 的修复副作用,写明旧测试为何没拦住);BUG-1025 星盘无资料无入口。- DESIGN §15 / §16、VOICE(新增三句)、CHANGELOG、PROGRESS、
docs/testing/chart-ephemeris-fixes-20260924.md(Slow 3G 下星历连点三天、断网切日期、0 年大运样例、无资料账号点按钮)。
让步顺序
- T1 若 golden 生成需要 swisseph 而执行环境无,允许用排查时的虚构生日在有 swisseph 的机器生成后入库,注明生成命令。
- D4 缓存若与路由结构冲突,可只做传 signal,缓存写入 BLOCKED。
- 不得让步:D1 不改引擎、红线 2、红线 3。
开工前置命令
git fetch origin --prune
git worktree add -b codex/chart-ephemeris-fixes-20260924 .worktrees/chart-ephemeris-fixes-20260924 origin/staging
cd .worktrees/chart-ephemeris-fixes-20260924/frontend
./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | tail -5
npx tsx --test tests/ephemeris-page.test.tsx tests/ephemeris-route.test.ts tests/chart-page-view.test.tsx tests/chart-page-hook.test.ts
BUG 编号
本单 BUG-1023 / 1024 / 1025(1021/1022 由慢网单预留),开工时核对。