fix(chart): keep zero-year chara and ephemeris dates apart
A zero-year Chara period is shown as 0 years instead of failing the whole chart. Switching ephemeris dates drops the previous day immediately and can be retried. Missing birth data links to chart settings.
This commit is contained in:
@@ -13651,3 +13651,51 @@
|
||||
- 相关记录:BUG-929、BUG-699、BUG-704、BUG-988、BUG-987、BUG-992、BUG-995
|
||||
- 复发自:BUG-929(标题口径两次返工;「旧标题不批量改」被本单推翻)
|
||||
- 修复版本:本分支提交,尚未推送、尚未部署
|
||||
|
||||
## BUG-1023 | Chara 0 年大运把整张星盘收成算不出来
|
||||
|
||||
- 状态:resolved(定向回归已锁;浏览器与部署未验收,不把本分支写成已上线)
|
||||
- 首次发现:2026-09-24
|
||||
- 最近更新:2026-09-25
|
||||
- 影响面:`chart-view-mapper.ts` 的 Chara 时间分配、星盘大运 Tab
|
||||
- 用户现象:大运右栏是「这张盘算不出来,我们已经记录下来了。」
|
||||
- 触发条件:某段 Chara 大运 `duration_years` 为 0。虚构 1985-08-03 03:59、北京可复现,射手段为 0 年。
|
||||
- 根因:子运权重用 `finite(duration) ?? 1`,0 不会被换成 1。12 段子运权重都是 0 时总和为 0,`0/0` 得到 NaN,`new Date(NaN).toISOString()` 抛 `RangeError`。`assembleChartView` 把非 Zod 错误收成 `engine_bad_payload`。0 是 kn_rao「先保底 12 年、再按落陷减 1」的合法结果,不是引擎坏包。
|
||||
- 修复:总权重不是正数时不再构造非法日期。0 年段标注「0 年」,起止同一天,不展开子运,子运区写「本段时长为 0,不展开」。不改 `scripts/jaimini.py`。
|
||||
- 验证:真实 `_compute_chart` + `_compute_chara_dasha` golden。12 段、射手 0 年、前后日期相接、`assembleChartView({layers:["chara"]})` 为 ok。UI 不渲染该段子运。
|
||||
- 防复发:0 权重不得再进入 `Date#toISOString`。0 年是显示规则,不是引擎失败。BUG-715 的失败分档仍留给真正的坏响应。
|
||||
- 相关记录:BUG-715、BUG-1017
|
||||
- 复发自:无
|
||||
- 修复版本:本分支,待推送与部署核对
|
||||
|
||||
## BUG-1024 | 星历切到新日期后下面仍是前一天
|
||||
|
||||
- 状态:resolved(定向回归已锁;浏览器与部署未验收,不把本分支写成已上线)
|
||||
- 首次发现:2026-09-24
|
||||
- 最近更新:2026-09-25
|
||||
- 影响面:`ephemeris-page.tsx`、`/api/ephemeris`
|
||||
- 用户现象:顶部日期已经换成新的一天,五要素和行运还是前一天。失败后一直留着旧数据,再点也不会重取。
|
||||
- 触发条件:切到还没缓存的日期;或请求 429、非 JSON、坏包;或进页时「今天」的刷新在切日期期间回来。
|
||||
- 根因:BUG-966 为了不让整页换成等待句,删掉了缓存未命中时的清空。失败时 `load` 直接返回,effect 又只跟日期变,所以同一天不能重试。进页刷新只比较响应里的 `payload.date`,切日期期间会把今天写回去。
|
||||
- 修复:只有响应日期等于当前所选日期才算就绪,否则保留日期条,三段改静态句。失败句为「这一天的星历没取到,点日期再试一次。」再点日期或失败时的左右箭头会重试。今天的刷新和迟到响应都先看当前日期。本命盘按账户和出生资料缓存 5 分钟,引擎调用带上 `request.signal`。
|
||||
- 验证:生命周期测试覆盖未缓存静态句、迟到的今天、迟到的前一日期、429 后箭头重试。路由测试里同一账户连续两天只打一次本命 `/api/chart`,并且上游 fetch 能看到已中止的 signal。
|
||||
- 防复发:星历仍不得出现骨架、spinner 或「正在加载」。旧日期响应不得写回新日期。BUG-966 的测试只静态渲染了 `EphemerisView`,没有挂上切日期的状态机,所以没拦住这次副作用。
|
||||
- 相关记录:BUG-966、BUG-1016
|
||||
- 复发自:BUG-966
|
||||
- 修复版本:本分支,待推送与部署核对
|
||||
|
||||
## BUG-1025 | 星盘没有出生资料时只有一句话,没有去填写的入口
|
||||
|
||||
- 状态:resolved(定向回归已锁;浏览器与部署未验收,不把本分支写成已上线)
|
||||
- 首次发现:2026-09-24
|
||||
- 最近更新:2026-09-25
|
||||
- 影响面:星盘失败页、`settings-url.ts`、首页设置深链
|
||||
- 用户现象:没有出生资料时只看到说明,不能从这一页去填。
|
||||
- 触发条件:`birth_profile_incomplete`,以及资料查询失败、已采用时间缺时区、时区解析失败。
|
||||
- 根因:失败页只有一段文字。`parseSettingsQuery` 以前只认 `?settings=billing`。
|
||||
- 修复:没有资料时加标题「还没有星盘资料」、原句和主按钮「去填写出生资料」,链到 `/?settings=chart`。另外三种资料失败保留各自的句子,并给同一按钮。首页据此打开设置里的星盘资料。`?settings=billing` 仍只开账户与点数。解析只在 `settings-url.ts`。
|
||||
- 验证:四种资料失败都渲染该按钮;引擎忙不渲染。`?settings=chart` 解析为星盘资料,billing 的既有断言没改。
|
||||
- 防复发:查询失败不得再写成资料不完整。这四类以外的失败不得带上「去填写出生资料」。
|
||||
- 相关记录:BUG-996、BUG-715
|
||||
- 复发自:无
|
||||
- 修复版本:本分支,待推送与部署核对
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# PROGRESS · Chara 0 年大运 + 星历切日期 + 星盘无资料入口(2026-09-25)
|
||||
|
||||
## 当前结论
|
||||
|
||||
T1、T2、T3、T4 都已完成,没有让步,也没有写进 BLOCKED。引擎 kn_rao 口径、`HEAVY_COMPUTE_PATHS`、数据库和 workflow 都没动。浏览器登录验收没做。没有推 `staging`,也没有推 `main`。
|
||||
|
||||
- 工作树:`G:\Ferti\Jyotisha\.worktrees\chart-ephemeris-fixes-20260924`
|
||||
- 分支:`codex/chart-ephemeris-fixes-20260924`
|
||||
- 基线:`origin/staging` = `514951d7`(代码提交 `824647f2`)
|
||||
- BUG:1023 / 1024 / 1025 开工时仍空着,沿用任务书预留号。最大已占用号是 1022。没有占用 1026 及以后。
|
||||
|
||||
## 逐项
|
||||
|
||||
| 项 | 结果 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| T1 | 完成 | 0 年大运显示「0 年」,不展开子运,前后日期首尾相接。`assembleChartView({layers:["chara"]})` 对真实引擎响应返回 ok。 |
|
||||
| T2 | 完成 | 未缓存日期保留日期条,三段换成静态句。429 后点右箭头重试成功。挂载时的今天刷新和迟到的旧日期都不会盖住新日期。本命 `/api/chart` 按账户和出生资料短缓存,并把 `request.signal` 传进引擎调用。 |
|
||||
| T3 | 完成 | 四种资料类失败都有「去填写出生资料」,链到 `/?settings=chart`,首页打开星盘资料。`?settings=billing` 的解析结果没改。 |
|
||||
| T4 | 完成 | BUG 历史、DESIGN §15 / §16、VOICE 三句、CHANGELOG、本记录、真人清单和状态板同一提交。 |
|
||||
|
||||
## 真实 golden
|
||||
|
||||
本机没有仓库 `.venv`,Anaconda Python 3.11 能 `import swisseph`。fixture `frontend/tests/fixtures/chara-zero-year-1985-08-03-beijing.golden.json` 由下面的调用生成,没有手造引擎形状:
|
||||
|
||||
- `C:\Users\74082\anaconda3\python.exe`
|
||||
- `JyotishAPIHandler.__new__()._compute_chart`,再 `_compute_chara_dasha`
|
||||
- 虚构 1985-08-03 03:59,纬度 39.9042,经度 116.4074,时区 8,`ayanamsa=raman`,`node_mode=mean`,`skip_vedastro_main_entry_overview`,`antardasha=true`
|
||||
|
||||
生成结果 12 段,Sagittarius `duration_years` 为 0(debilitated)。`scripts/jaimini.py` 未改。
|
||||
|
||||
## 历史检索
|
||||
|
||||
开工读过 BUG-966、BUG-715、BUG-716、BUG-717、BUG-996、BUG-1016、BUG-1017,以及 chart-view / ephemeris / `birth_profile_incomplete` 的相关段。
|
||||
|
||||
- BUG-966 的「星历不得再上骨架 / 正在加载」还在。本单没有加骨架。它删掉未命中时清空状态的副作用,就是 BUG-1024。
|
||||
- BUG-715 的失败分档还在。0 年以前会在 mapper 里抛 `RangeError`,被收成 `engine_bad_payload`。现在 0 年是合法段,不再走这条失败。
|
||||
- BUG-1016 的骨架例外仍只在星盘盘位。星历没有用。
|
||||
- BUG-1017 的按需层失败出口没改。
|
||||
- BUG-996:查询失败仍不是 `birth_profile_incomplete`。四种资料失败各自留原文,只是多了同一颗按钮。
|
||||
|
||||
## 行为说明
|
||||
|
||||
失败当天,左右箭头重试这一天,不先改日期。日历里另选一天仍会换日期。成功之后箭头恢复成前一天 / 后一天。
|
||||
|
||||
本命缓存键用的是账户 id 加上出生日期、时间、经纬、时区、岁差和交点,与 `cachedPostEngine` 同一组字段、同一 5 分钟 TTL。键的 path 是 `/api/ephemeris/natal-chart`,避免和星盘页略有不同的 `/api/chart` 请求体串结果。行运盘仍按所选日期现算。
|
||||
|
||||
## 测试
|
||||
|
||||
改代码前,在 `frontend` 跑下面这组,93 条,失败 0:
|
||||
|
||||
`tests/ephemeris-page.test.tsx`、`tests/ephemeris-route.test.ts`、`tests/chart-page-view.test.tsx`、`tests/chart-page-hook.test.ts`、`tests/settings-url.test.ts`、`tests/home-shell-growth-contract.test.ts`、`tests/secondary-page-entry.test.ts`、`tests/billing-panel.test.ts`
|
||||
|
||||
改完后同一组再加上 `tests/ephemeris-page-lifecycle.test.tsx` 和 `tests/chart-view-zero-year.test.ts`:104 条,失败 0。改前那 93 条里没有新增失败。
|
||||
|
||||
- `.\node_modules\.bin\tsc --noEmit`:通过。
|
||||
- `npm run lint`:0 error,121 条既有 warning。本次新文件没有新增 warning,也没有为了清 warning 改业务代码。
|
||||
- 没有改既有断言的期望值,所以没有「原值 / 新值 / 原因」三栏。
|
||||
- 没有跑 Windows 全量 `npm test`,也不把别人机器上的 3809 / 56 写成这次的结果。
|
||||
- 没有跑 `next build`,没有声称 `/`、`/chart`、`/ephemeris` 的 Static 标记在本机构建里复核过。源码没有把这三条改成动态路由。
|
||||
|
||||
## 没做的验证
|
||||
|
||||
- 没有浏览器登录。真人步骤在 `docs/testing/chart-ephemeris-fixes-20260924.md`,结果都是待验。
|
||||
- 没有部署,没有对过 staging health。
|
||||
- 没有推 `origin/staging`。功能分支可以另推 `origin`,以回报里的远端核对为准。
|
||||
@@ -203,7 +203,7 @@
|
||||
| 任务书 | 进度 | 主题 | 状态 | 落点 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `TASK-chart-dasha-western-redesign-20260924.md` | — | **大运 / 西洋盘改版**(原型 https://claude.ai/artifact/DYovEPMqD1xwNgna5xVTre ,产品 09-24 全部同意,相位线常显):大运「现在」卡 + 时间条 + 默认折叠(原 81/144 行平铺);西洋盘 520 三圈、行星避让 + 引线、宫号居宫中、ASC/MC 盘内、行星位置表、点选过滤相位。排在 chart-ephemeris-fixes T1 之后 | 待领取 | — |
|
||||
| `TASK-chart-ephemeris-fixes-20260924.md` | — | **Chara 0 年大运崩溃 + 星历切日期旧数据 + 星盘无资料空状态(BUG-1023/1024/1025)**:mapper 0/0 → `RangeError`(约 7.8% 星盘,产品定照实显示 0 年、不改引擎);BUG-966 删掉重置致日期与数据分叉(回归);无资料只有一句话,加「去填写出生资料」+ `?settings=chart` 深链(T3 排在 home-slow-network 之后)。大运 / 西洋版式重做不在本单 | 待领取 | — |
|
||||
| `TASK-chart-ephemeris-fixes-20260924.md` | `PROGRESS-chart-ephemeris-fixes-20260924.md` | **Chara 0 年大运崩溃 + 星历切日期旧数据 + 星盘无资料空状态(BUG-1023/1024/1025)**:mapper 0/0 → `RangeError`(约 7.8% 星盘,产品定照实显示 0 年、不改引擎);BUG-966 删掉重置致日期与数据分叉(回归);无资料只有一句话,加「去填写出生资料」+ `?settings=chart` 深链(T3 排在 home-slow-network 之后)。大运 / 西洋版式重做不在本单 | 待验收 | `PENDING_SHA` |
|
||||
| `TASK-chart-page-skeleton-wait-20260924.md` | `PROGRESS-chart-page-skeleton-wait-20260924.md` | **星盘页骨架盘等待态 + 三个「永远还没拿到」死角**:「这一张盘还没拿到。」只代表 `view === null`,是唯一等待态,失败各有句子;但客户端无超时(A)、401 跳转前(B)、分盘层失败 / 429 后 `ChartVedicTab` 只看 `!selected` 不看 pending(C)三条路都让这句永远挂着。**产品 09-24 拍板推翻 09-18 方案一(BUG-966)**:星盘页盘位用骨架盘 + 呼吸动效(复用 `VedicChartSvg` 空模型,不复制几何;`prefers-reduced-motion` 静止),范围只限星盘页会出盘轮的位置,首页 / 侧栏 / 星历 / 报告的「不放骨架」合同不动;`AGENTS.md` §6 与 `DESIGN.md` §9 / §15 追加例外。三死角出口:客户端 25s 超时 → `timedOut` 句、401 先写失败体、按层失败态 `layerFailures`(429 独立档,BUG-715/723)。BUG-1016 / 1017 | 已验收(Claude 09-24:红线全绿、+46 测试、失败名单同基线、四路由标记与 gzip 同基线;BUG-1016/1017 resolved) | `1420471a`(staging 已部署);真机清单欠 |
|
||||
| `TASK-smalltalk-test-stdout-mock-20260921.md` | `PROGRESS-smalltalk-test-stdout-mock-20260921.md` | **测试基础设施(BUG-995)**:`consultation-smalltalk.test.ts` 为验证「SDK 不得把私密文本写进日志」,用 `t.mock.method(process.stdout/stderr, "write", …)` 全局接管标准输出——而 `node:test` 的 TAP 报告也走 `process.stdout`,于是运行器自己的 `# Subtest:` / `ok` 行被吞进测试的 `logs` 数组。实测四次全量:`default Mastra adapter` 四条用例只上报 4 / 2 / 1 / 1 条(`Subtest` 声明本身就少,不是 grep 锚点问题),`# tests` 因此 ±3 抖;单跑该文件 33 条静态展开只报 30 条,仅循环最后一个 `provider_error` 稳定可见。**更要紧**:注入必失败探针后,`invalid_schema` / `bad_json` 只剩一行 `not ok 1 - <文件绝对路径>`,**没有用例名、没有断言消息**(退出码仍是 1,门禁不会漏掉失败,不夸大)。定位 BUG-987 时靠的就是从门禁日志 grep `not ok` 抓用例名,红在这三条上那条路会断。**决策**:mock 改为记录后**透传给原始 `write`**(保留隐私断言,不换报告通道,不改 `npm test` 脚本);F3 把「比用例名列表 diff、不比 `# tests` 总数」写进 `frontend/AGENTS.md`。全仓只此一个文件用了这个手法(已 grep 确认)| 待验收 | `2503c019` |
|
||||
| `TASK-frontend-optimization-20260828.md` | `PROGRESS-frontend-optimization-20260828.md` | 前端优化九条 | 待核对 | 分支 `codex/frontend-optimization-20260828` |
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# 星历切日期、0 年大运、星盘无资料(2026-09-25)
|
||||
|
||||
状态:本环境没有可靠的浏览器登录验收。下面每条都还没在真人浏览器里走过。自动化只锁了渲染和请求生命周期,不能代替这张表。只用虚构出生时间 1985-08-03 03:59、北京,不要把真实出生资料写进记录。
|
||||
|
||||
| 项目 | 操作 | 通过标准 | 结果 |
|
||||
| --- | --- | --- | --- |
|
||||
| 0 年大运 | 用虚构盘打开星盘,点「大运」 | 射手那段写「0 年」,下面是「本段时长为 0,不展开」,没有子运列表。前后段日期接得上。整页不是「这张盘算不出来」 | 待验 |
|
||||
| 星历连点 | Slow 3G 下打开星历,连点后一天三次 | 每次日期条立刻变成新的一天。五要素和行运马上变成「还没拿到」,事件区是「换座和停滞还在取。」没有骨架、转圈或「正在加载」。后到的旧日期不会把新日期盖回去 | 待验 |
|
||||
| 断网切日期 | 星历已打开后断网,再点前一天或后一天 | 三段都是「这一天的星历没取到,点日期再试一次。」恢复网络后再点这一天或左右箭头,能重新取到。日期条一直在 | 待验 |
|
||||
| 无资料 | 用没有出生日期的账号打开星盘 | 标题「还没有星盘资料」,原说明还在,主按钮「去填写出生资料」。点下去到首页设置的星盘资料。`?settings=billing` 仍只开账户与点数 | 待验 |
|
||||
| 另外三种资料失败 | 若能在受控环境分别造出资料读失败、已采用时间缺时区、时区对不上 | 各自的原句还在,并且有同一颗「去填写出生资料」。不要出现「还没有星盘资料」这句标题 | 待验 |
|
||||
|
||||
部署后还要核对 staging `/api/health` 的 `deployment.gitCommit`。本清单未走完之前,不能写成浏览器已验收。
|
||||
Reference in New Issue
Block a user