fix(web): paint the chart page shell before engine calls
BUG-715/716/717: typed engine failures with logs and split copy, natal-only open, on-demand tabs, 10s timeout, in-memory cache, no speed-promise eyebrow.
This commit is contained in:
@@ -11109,3 +11109,51 @@
|
||||
- 相关记录:TASK-qizheng-native-chart-20260915、TASK-readonly-pages-fix-20260916
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-715 | 星盘页引擎失败被碾成 null,忙和坏盘共用一句「过一会儿再打开」
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-15
|
||||
- 最近更新:2026-09-15
|
||||
- 影响面:`frontend/src/lib/chart-view-service.ts`、`frontend/src/lib/chart-view-load.ts`、`frontend/src/lib/chart-view-engine.ts`、`/chart`
|
||||
- 用户现象:星盘打开失败只看到「这张盘这会儿算不出来。资料还在,过一会儿再打开。」服务端日志里看不出是 429、500、超时还是坏 JSON。
|
||||
- 触发条件:`/api/chart` 返回非 2xx、超时、JSON 解析失败,或 mapper 抛错。
|
||||
- 根因:`postEngine` 把所有失败 `return null`,`catch {}` 吞掉异常且不打日志。用户文案把「等一下会好」和「这张盘有 bug」写成同一句。
|
||||
- 修复:引擎调用返回 `ok / busy / http_error / timeout / bad_payload`。每一种非 ok 打 `console.warn`(只含路径、状态码或错误名、耗时,不含出生资料)。429 文案「算盘的服务正忙,稍等几秒再打开就好。」其它「这张盘算不出来,我们已经记录下来了。」mapper 失败同样记日志。
|
||||
- 验证:`npx tsx --test tests/chart-view-engine.test.ts tests/chart-view-route.test.ts tests/chart-page-view.test.tsx`;四种桩各有可区分日志,429 与其它走不同文案。
|
||||
- 防复发:引擎调用不得用 `catch {}` 吞掉原因,失败必须留服务端日志且用户文案按原因分档。
|
||||
- 相关记录:BUG-716、BUG-717、TASK-chart-page-blocking-open-20260915
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-716 | `/chart` 动态 SSR 等完五个引擎调用才开始画,白屏最长 45 秒
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-15
|
||||
- 最近更新:2026-09-15
|
||||
- 影响面:`frontend/src/app/chart/page.tsx`、`frontend/src/components/chart-page/chart-page-view.tsx`、`frontend/src/hooks/use-chart-page.ts`、`/api/chart-view`
|
||||
- 用户现象:点侧栏「星盘」后整页空白很久,然后才出盘或失败句。侧栏已改成硬文档跳转,动态路由在服务端等完才吐 HTML。
|
||||
- 触发条件:从对话进 `/chart`。`/api/chart` 若慢或挂起,用户盯空白,最长 45 秒(`engineTimeoutMs`)。
|
||||
- 根因:`chart/page.tsx` `force-dynamic` 且 `await loadChartView()`,而 `loadChartView` 先串行 `/api/chart` 再并行四个后续调用。文档卸载重载期间浏览器里什么都没有。
|
||||
- 修复:`/chart` 改为静态壳,客户端先画标题和返回,再取 `/api/chart-view`。进页只算主盘;分盘 / Chara / 西洋 / 七政按 tab 或非 D1 chip 按需取。超时改为 10 秒(实测主盘 0.60 秒,10 秒约 16 倍余量,避免再盯 45 秒空白)。等待句用「还没拿到」,不转圈。
|
||||
- 验证:无 `view` 时外壳可见;挂起主盘不再依赖四个后续调用;源码合同禁止 `force-dynamic` / `loadChartView` 出现在 `chart/page.tsx`。
|
||||
- 防复发:`/chart` 首字节不得等待四个后续引擎调用。揭幕后填 tab 不得再上 spinner / 骨架 / 「正在加载」。
|
||||
- 相关记录:BUG-715、BUG-717、TASK-chart-page-blocking-open-20260915
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-717 | 开一次星盘页占满重计算配额,且「打开即有」印在失败页上
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-15
|
||||
- 最近更新:2026-09-15
|
||||
- 影响面:`assembleChartView` 的 layer 参数、`chart-page-view.tsx` 眉标、服务端引擎结果缓存
|
||||
- 用户现象:打开星盘常失败;失败页上还写着「直接计算 · 打开即有 · 不消耗点数」。生产与 staging 重计算并发默认 2,开页并行打 `/api/western` 与 `/api/qizheng` 就会占满。
|
||||
- 触发条件:打开 `/chart`。同时有第二个人开星盘,或校正 / 咨询在跑,更容易 429。
|
||||
- 根因:进页无条件并行打两个 `HEAVY_COMPUTE_PATHS` 端点;`cache: "no-store"` 且无记忆;失败分支也渲染同一句速度承诺眉标。
|
||||
- 修复:开页只请求 `/api/chart`。西洋 / 七政点到对应 tab 才发,不再占开页配额。同一账户 + 出生资料指纹 + ayanamsa + `node_mode` 的引擎结果内存缓存 5 分钟,资料或岁差一变即换键。失败页删除眉标;成功眉标改为「主盘直接算 · 分盘按需 · 不消耗点数」。不放宽限流。
|
||||
- 验证:无 layers 时 `assembleChartView` 的引擎路径只有 `/api/chart`;失败页无 eyebrow;缓存键随 ayanamsa / node_mode 变化。
|
||||
- 防复发:开页不得并行打 `/api/western` 与 `/api/qizheng`。不得靠放宽 `HEAVY_COMPUTE_PATHS` 或提高 `JYOTISH_HEAVY_COMPUTE_CONCURRENCY` 来「解决」429。承诺速度的文案不写。
|
||||
- 相关记录:BUG-707、BUG-715、BUG-716、TASK-chart-page-blocking-open-20260915
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# PROGRESS · 星盘页开页不再整页阻塞(2026-09-15)
|
||||
|
||||
工作树:`.worktrees/chart-page-blocking-open-20260915`
|
||||
分支:`codex/chart-page-blocking-open-20260915`
|
||||
任务书基线:`origin/staging` @ `8caa2a2b`(任务书本身;代码基线 `2533d5a3`)
|
||||
本机 Windows。
|
||||
|
||||
Skill **未 bump**。未改 `scripts/**`、`deploy/**`、`vendor/**`、`frontend/src/app/page.tsx`、`vedic-chart-svg.tsx`。未放宽 `HEAVY_COMPUTE_PATHS` / `JYOTISH_HEAVY_COMPUTE_CONCURRENCY`。
|
||||
|
||||
## 开工基线
|
||||
|
||||
| 项 | 数字 |
|
||||
| --- | --- |
|
||||
| `frontend/src/app/page.tsx` | **1951** 行 |
|
||||
| 最大 BUG 号 | **BUG-714**(本单占用 715–717) |
|
||||
| `tsc --noEmit` | 收尾 0 错 |
|
||||
| `npm run lint` | 0 error(全仓既有 warning 119;本单新文件 0 warning) |
|
||||
|
||||
`frontend/node_modules` 用 junction 指向主仓。
|
||||
|
||||
## 任务状态
|
||||
|
||||
| 任务 | 状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 1 BUG-715 失败可诊断 | 完成 | `ok / busy / http_error / timeout / bad_payload`;非 ok 打 `console.warn`(路径、状态码或错误名、耗时;不含资料);429 与其它分档文案;`catch {}` 去掉 |
|
||||
| 2 BUG-716 开页不阻塞 | 完成 | `/chart` 改为静态壳;进页只算 `/api/chart`;四个后续按 tab / 非 D1 chip 按需;超时 **10 秒** |
|
||||
| 3 BUG-717 配额与文案 | 完成 | 开页不再打 western / qizheng;内存缓存 5 分钟,键含 ayanamsa + `node_mode`;失败页无眉标;成功眉标去掉「打开即有」 |
|
||||
| 4 测试与文档 | 完成 | BUG-715/716/717、DESIGN、VOICE、CHANGELOG、真人清单、PROGRESS |
|
||||
|
||||
## 实现要点
|
||||
|
||||
- `postEngine` 不再 `return null`。分类在 `chart-view-engine.ts`,日志在 `assembleChartView` 的 `callEngine` 包装层,mapper `catch (error)` 记 `errorName` + `message`。
|
||||
- `/chart` 不再 `force-dynamic`、不再 `await loadChartView()`。`ChartPageRoute` 先画外壳,再 `GET /api/chart-view`。未登录仍跳 `/login`。
|
||||
- `GET /api/chart-view?layers=varga,chara,western,qizheng` 按需取后续。缺省 layers 只有 `/api/chart`。
|
||||
- 等待态沿用星历页静态句:「这一张盘还没拿到。」「这一栏还没拿到。」「这一分盘还没拿到。」揭幕后无 spinner / 骨架 / 「正在加载」。
|
||||
- 引擎结果缓存在 Next 进程内存(与 rate-limit / feature-flag 同一做法)。`api_scratch` 在 API 容器上,BFF 没有这个卷,没有新依赖。失败不写缓存。TTL 5 分钟。
|
||||
|
||||
## 超时取值
|
||||
|
||||
`CHART_VIEW_ENGINE_TIMEOUT_MS = 10_000`。任务书实测 `/api/chart` 0.60 秒、五个合计 0.75 秒。45 秒大两个数量级,只会让人盯空白。10 秒大约是实测的 16 倍,给冷启动和跨容器网络留余量;挂起时十秒内落到失败文案。
|
||||
|
||||
## 既有断言改动
|
||||
|
||||
| 文件 | 原值 | 新值 | 原因 |
|
||||
| --- | --- | --- | --- |
|
||||
| `chart-page-view.test.tsx` 成功页眉标 | `直接计算 · 打开即有 · 不消耗点数` | `主盘直接算 · 分盘按需 · 不消耗点数` | BUG-717:打开即有是速度承诺,且曾印在失败页上 |
|
||||
| `chart-view-route.test.ts` western/qizheng 是否被调用 | 无 layers 也会打 `/api/western` 与 `/api/qizheng` | 只有请求对应 layer 才打;无 layers 时路径只有 `/api/chart` | BUG-716/717 开页不得占满重计算配额 |
|
||||
| `assembleChartView` 的 `postEngine` 形状 | `Record \| null` | `EngineCallResult` | BUG-715 失败必须带原因 |
|
||||
|
||||
未弱化其它既有断言。未改 `page.tsx`(仍 1951 行)。
|
||||
|
||||
## 测试
|
||||
|
||||
| 命令 | 结果 |
|
||||
| --- | --- |
|
||||
| `npx tsx --test tests/chart-view-engine.test.ts tests/chart-view-route.test.ts tests/chart-page-view.test.tsx` | **27 pass / 0 fail**(本单相关;其中新增约 12 条) |
|
||||
| `./node_modules/.bin/tsc --noEmit` | **0 错** |
|
||||
| `npm run lint` | **0 error**(119 条既有 warning,本单新文件未新增) |
|
||||
| `page.tsx` | 仍 1951 行,未改 |
|
||||
| `npx next build --webpack` | compile + TypeScript 过;Collecting page data 死在既有 `SkillPackageRegistryError`(EPERM symlink `/api/birth-time-guide`),与本单无关。未能从本机构建表确认 `/` 与 `/chart` 的 `○ Static`。源码合同:`chart/page.tsx` 已去掉 `force-dynamic` / `loadChartView`。 |
|
||||
| `npm test` 全量 | `# tests 3101 / # pass 3014 / # fail 73 / # skipped 14`。失败集中在无 Docker 的 database-*、部署/Caddy、Skill SHA、Windows 路径。失败清单不含本单文件。本机不是 Linux 验收机。 |
|
||||
|
||||
## 环境缺口
|
||||
|
||||
- 无登录态、无 Chrome:真人走查见 `docs/testing/chart-page-open-20260915.md`。
|
||||
- `next build` 收集页面数据时 symlink EPERM,无法在本机核对路由表。
|
||||
@@ -227,7 +227,7 @@
|
||||
| `TASK-chart-page-20260915.md` | `PROGRESS-chart-page-20260915.md` | **前端单(独占 `app-sidebar.tsx`,同时加星盘与星历两个入口)**:P0 只读星盘页,五个 Tab(星盘 / 基础信息 / 大运 / 西洋盘 / 七政四余),中宫排盘参数卡,三套坐标系各自标注且禁止互相换算。不扣点不调模型不出 spinner;不碰 `page.tsx`(1951/2000);**不搬 `vedic-chart-svg.tsx`**(rectification-board 也在用)。任务书预占 704–706,Bug 历史未写入;校正 P0 落地占用了 704–706 / 708–709 | 已验收(带修复单) | `830799fa` |
|
||||
| `TASK-ephemeris-page-20260915.md` | `PROGRESS-ephemeris-page-20260915.md` | **前端单**:P1 星历页,今日五要素 + 当日行运(相对本命宫位)+ 未来九十天换座与停滞,底部「带这天去提问」出口。页面不得出现任何运势判断。含实证缺陷:panchanga 写死 Lahiri 与账户 Raman 分裂(关联 BUG-703;本单标注为 BUG-707)。侧边栏入口由 chart-page 单交付。BUG 段 707–709 | 已验收(带修复单) | `d3a2c48b` |
|
||||
| `TASK-readonly-pages-fix-20260916.md` | `PROGRESS-readonly-pages-fix-20260916.md` | 三份只读页单的验收修复:**BUG-710** 七政 `ketu_mode`/`sidereal_mode` 收了请求却从不传给引擎,`calculation.ketu_mode` 回写请求值而非实际值(实测请求 descending-node 仍返回 apogee 盘,无警告);**BUG-711** 星历单断言 sidebar 不得含 `/ephemeris`,与星盘单按任务书添加的入口直接冲突,staging 现在是红的;**BUG-712** `ephemeris_events` golden 存全精度浮点跨机不稳,且 golden 缺失时自动重建。另附部署缺口:`deployment.gitCommit` 仍是 `2d7698ea`。BUG 段 710+ | 待验收 | `codex/readonly-pages-fix-20260916` |
|
||||
| `TASK-chart-page-blocking-open-20260915.md` | — | **P1**:星盘页开一次要等很久且常常只给一句「过一会儿再打开」。实测引擎五个调用合计 0.75 秒、mapper 13 种形态零抛出——瓶颈在 `/chart` 是动态路由 + 侧栏改成硬文档跳转,整页 SSR 等完 1 串 4 并才开始画,白屏最长 45 秒(BUG-716);`postEngine` 把 429/500/超时/坏 JSON 全碾成 `null` 且零日志,两种性质相反的故障共用一句文案(BUG-715);开页并行打两个重计算限流端点(配额 2)、无缓存,且「打开即有」印在失败页上(BUG-717)。**串行在 readonly-pages-fix 之后** | 待领取 | `codex/chart-page-blocking-open-20260915` |
|
||||
| `TASK-chart-page-blocking-open-20260915.md` | `PROGRESS-chart-page-blocking-open-20260915.md` | **P1**:星盘页开一次要等很久且常常只给一句「过一会儿再打开」。实测引擎五个调用合计 0.75 秒、mapper 13 种形态零抛出——瓶颈在 `/chart` 是动态路由 + 侧栏改成硬文档跳转,整页 SSR 等完 1 串 4 并才开始画,白屏最长 45 秒(BUG-716);`postEngine` 把 429/500/超时/坏 JSON 全碾成 `null` 且零日志,两种性质相反的故障共用一句文案(BUG-715);开页并行打两个重计算限流端点(配额 2)、无缓存,且「打开即有」印在失败页上(BUG-717)。**串行在 readonly-pages-fix 之后** | 待验收 | `codex/chart-page-blocking-open-20260915` |
|
||||
| `TASK-api-server-decomposition-20260916.md` | `PROGRESS-api-server-decomposition-20260916.md` | **重构单(串行在 qizheng 单之后)**:把业务逻辑搬出 `JyotishAPIHandler`。核心不是行数,是全仓 3 处靠 `JyotishAPIHandler.__new__` 伪造空壳 handler 借方法(`consultation_workflow_service` ×2、`capture_report_blocked_repairs_golden`、`local_accuracy_report`,MCP 也走这条),依赖方向反了、handler 没有 `headers`/`wfile` 随时可炸。四阶段:拆 `__new__` 后门 → 抽 ≥150 行业务方法 → `do_POST`/`do_GET` 改路由表 → 重新冻结行数 baseline(余量 300→50)。纯搬运不改行为,`test_api_server_security.py` 3841 行断言一条不许改。预计 11,314 → 约 9,230 行。BUG 段 710+ | 待领取 | — |
|
||||
|
||||
## 命名与归档
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
## 五个 Tab
|
||||
|
||||
6. 登录且出生资料齐全:打开星盘没有 spinner、骨架或「正在加载」,揭幕就是完整页。
|
||||
7. 眉标是「直接计算 · 打开即有 · 不消耗点数」。点数余额不应因打开此页而变。
|
||||
6. 登录且出生资料齐全:点「星盘」后先看到外壳(返回、标题),不是白屏。主盘到达前可以出现「这一张盘还没拿到。」,不得出现 spinner、骨架或「正在加载」。
|
||||
7. 成功页眉标是「主盘直接算 · 分盘按需 · 不消耗点数」。失败页没有眉标。点数余额不应因打开此页而变。
|
||||
8. Tab 顺序:星盘 / 基础信息 / 大运 / 西洋盘 / 七政四余。都能点。
|
||||
9. 星盘 Tab:D1–D30 chip 可换;盘面是北印菱形盘;右侧有行星表(星体 / 星座与度数 / 宫位 / 状态)。
|
||||
10. 桌面中宫是六行参数;把窗口收到手机宽度(≤767)后,中宫只剩岁差和交点两行,完整参数出现在盘下方。
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# 真人验收 · 星盘页开页不再整页阻塞(2026-09-15)
|
||||
|
||||
执行环境无登录态、无 Chrome。下列条目留给有真实账号的人在 staging 走查。本单自动化不替代这些。
|
||||
|
||||
## 开页外壳
|
||||
|
||||
1. 登录后点侧栏「星盘」。**大约 1 秒内**能看到页面外壳:返回对话、标题「星盘」。不要整页白屏等到引擎全部算完。
|
||||
2. 主盘还没到时,等待句是「这一张盘还没拿到。」没有转圈、骨架或「正在加载」。
|
||||
3. 主盘到达后北印盘立刻可见。出生资料行出现。成功眉标是「主盘直接算 · 分盘按需 · 不消耗点数」,没有「打开即有」。
|
||||
|
||||
## 按需加载
|
||||
|
||||
4. 开页后(还没点其它 tab)开发者工具里发给引擎的路径只有 `/api/chart`。不要同时出现 `/api/western` 或 `/api/qizheng`。
|
||||
5. 点「大运」:Vimshottari 可以立刻出现(来自主盘);Chara 未到时写「这一栏还没拿到。」,到了再填。未点之前不应请求 `/api/dasha/chara`。
|
||||
6. 点「西洋盘」才请求 `/api/western`。未点不发。等待时写「这一栏还没拿到。」
|
||||
7. 点「七政四余」才请求 `/api/qizheng`。未点不发。等待时写「这一栏还没拿到。」
|
||||
8. 星盘 tab 默认 D1。点 D9 等非 D1 chip 才请求 `/api/varga_full`。等待时写「这一分盘还没拿到。」
|
||||
|
||||
## 失败文案
|
||||
|
||||
9. 失败页没有眉标,没有「打开即有」,没有「过一会儿再打开」。
|
||||
10. 若刚好赶上引擎忙(429):「算盘的服务正忙,稍等几秒再打开就好。」稍等再开,有机会好。
|
||||
11. 其它失败:「这张盘算不出来,我们已经记录下来了。」不要暗示等一会儿就会好。
|
||||
|
||||
## 回归
|
||||
|
||||
12. 点数余额不因打开此页而变。
|
||||
13. 资料不全时仍是人话去填星盘资料,不是 500,也没有眉标。
|
||||
Reference in New Issue
Block a user