Files
Jyotisha/docs/tasks/PROGRESS-cend-chart-eph-20260916.md
T
Jesse_ChenandClaude Opus 5 1e3570b462
Independent Staging Quality Gate / validate (push) Failing after 9m13s
Independent Staging Quality Gate / publish (push) Skipped
feat(ui): 星盘 tab 下划线化、参数收成键值表,星历日期条改 ‹ 日期 ›
星盘页(T5.1):
- 五个体系 tab 从五枚描边药丸改成顶栏下方一条下划线式 tab 行,
  flex-wrap: nowrap + 容器自身横滚,375px 下仍是一行;底线画在滚动
  容器的 border 上,不随内容滚走。眉标(BUG-717 的成本与速度承诺)
  原文保留,位置从 tab 行上方移到下方,让 tab 行直接接住 46px 顶栏。
- 分盘 chips 保留但降一级:去描边去卡面、caption 字号、三级色,
  当前项只留浅底。它是一个 tab 内部的筛选器,不是第二层导航。
- 参数从「中宫叠卡(手机两行/桌面六行)+ 盘下重复卡 + media query
  三选一」收成一张八行键值表。同一组事实原本画三遍,改一处要改三处。
  .chart-page-center-card / -compact / -extra / .chart-page-params-below
  / .chart-page-boundary-desktop 五个类连同 767/768 开关块一并删除。
  view.vedic.boundary 那句准确性边界句原文未动,紧跟在表下方,且
  DOM 里从出现两次变成一次。
- 三张行星表(印度宿度 / 西洋相位 / 七政十一曜)全部包上横向滚动
  容器,wrap 补 min-width: 0 —— 少了它 grid item 按内容定宽,表格会
  撑宽页面而不是在自己盒子里滚动。原先只有第一张有 wrap。

星历页(T5.2):
- 日期导航从三个并排等宽按钮改成居中的 ‹ 日期 ›:日期是主语,两枚
  44px 箭头是把手。箭头字形 aria-hidden,可访问名仍是「前一天」
  「后一天」,读屏不丢方向。
- 「今天」只在非今日时以文字按钮出现在日期下方;在今日时整个不渲染,
  而不是渲染成禁用按钮——灰掉的按钮仍要被读、仍要被 Tab 跳过。
- 三段统一成同一套卡片:框从内容上移到段落,.ephemeris-panchanga 的
  dl 网格原样保留。收尾句原文不变,但从底部第四张卡降为页尾一行小字。

两条既有断言改动,测试文件内就地写了原值/新值/原因,进度记录成表:
参数断点开关的三条断言换成「参数只有一张键值表且那五个类不再有规则」
(更强,且避开了原写法 indexOf 未命中后静默锚错断点块的陷阱);
「今天」在场的单状态断言拆成今日/非今日两状态并加断不出现 disabled。
测试总数 3350 → 3352,失败清单与基线逐条一致(31 条无 Docker 缺口)。

tsc 0 错;lint 0 error / 118 warning(与基线同数);/ /chart /ephemeris
渲染标记均保持 ○ Static,/reports 仍 ƒ;主 CSS gzip 36,745 → 36,788
(+0.12%)。行星表 375px 横滚、tab 行横滚、读屏播报无真机验收,已在
进度记录里如实写成环境缺口。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 06:47:50 +00:00

179 lines
14 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.
# PROGRESS · 星盘 + 星历 R5
任务书:`docs/tasks/TASK-cend-surfaces-claude-alignment-20260916.md` 的 R5
执行方式:**直接执行模式**(subagent
分支:`codex/cend-chart-eph-20260916`
基线:`origin/staging` = `50ce02c8`R4 次级页外壳合入后)
BUG 段:不占用(产品改造,未发现真实缺陷)
---
## 开工基线实测
`50ce02c8` 干净检出、`npm ci` 之后实测:
| 项 | 基线值 |
|---|---|
| `tsc --noEmit` | 0 错 |
| `npm run lint` | 0 error / **118 warning** |
| `npm test` | tests **3350** · pass 3304 · fail **31** · skipped 15 |
| `next build` 路由标记 | `/` `○` · `/chart` `○` · `/ephemeris` `○` · `/reports` `ƒ` |
| 主 CSS chunk | 242,608 字节(gzip **36,745** |
31 条失败全部是无 Docker 的既有缺口,清单落在 `/tmp` 基线文件,改后逐条对比。
---
## T5.1 · 星盘页
### 做了什么
| 任务书要求 | 做法 |
|---|---|
| 五个体系 tab 改顶栏下方下划线式 tab 行 | `.chart-page-tabs` 从「五枚描边药丸 + 可换行」改成一条 `flex-wrap: nowrap` + 自身横滚的下划线行,整行 1px 底线,当前项 2px 下划线。JSX 里眉标从 tab 行**之上**移到**之下**,让 tab 行直接接住 46px 顶栏 |
| 分盘 chips 保留、视觉降一级 | `.chart-page-chip` 从与 tab 共用的药丸规则里拆出来:去描边、去卡面、caption 字号、三级文字色,当前项只留一块浅底。触摸目标仍 44px |
| 参数收进统一键值表 | 新增 `chart-param-table.tsx`(由 `chart-param-lines.tsx` 改名而来),八行 `dl` 键值表。删除 `.chart-page-center-card` / `-compact` / `-extra` / `.chart-page-params-below` / `.chart-page-boundary-desktop` 五个类及其 767/768 开关块 |
| 边界句放表下方、文案一字不改 | `{view.vedic.boundary}` 直接跟在表后。改前 DOM 里它出现**两次**(一次给手机一次给桌面,靠 CSS 藏一个),现在只渲染一次。**句子本身是服务端字符串,没有被碰过** |
| 行星表加横向滚动容器 | `.chart-page-planet-table-wrap``min-width: 0`(缺它 grid item 按内容定宽,表格撑宽页面而不是滚动),表加 `min-width: 26rem`。**三张**表全部包上:印度盘宿度、西洋相位、七政十一曜(原来只有第一张有 wrap) |
眉标 `CHART_VIEW_COPY.eyebrow`(「主盘直接算 · 分盘按需 · 不消耗点数」,BUG-717)保留,只换了位置。
按需 layer 拉取(`onNeedLayer("chara"/"western"/"qizheng"/"varga")`)、`CHART_VIEW_COPY.waitingLayer` 等待文案、`waitingChart` / `waitingVarga` 全部未动,没有引入 spinner 或骨架。
### 顺带修掉的一处错位
`.chart-page-eyebrow` 原本同时吃 `.chart-page-body``padding-inline` 和 767 块里给它自己的一份,手机上比 tab 行多缩进一个 `--space-4`。眉标移到 tab 行下方后这个错位会直接看得见,所以把 `.chart-page-eyebrow` 从那条共享选择器列表里摘掉了——**只摘这一个选择器**,同列表里 R6 的 `.report-center-body` / `.report-center-message` 一个没动。
---
## T5.2 · 星历页
| 任务书要求 | 做法 |
|---|---|
| 日期导航改居中 ` 日期 ` | 两枚 `size="icon"`(44px)箭头按钮夹住日期;箭头字形 `aria-hidden`,可访问名用 `EPHEMERIS_COPY.previousDay` / `nextDay`,读屏拿到的仍是「前一天」「后一天」 |
| 「今天」非今日时以文字按钮出现在日期下方 | `isToday ? null : <Button variant="ghost">`,在日期条下方 |
| `isToday` 时不出现禁用按钮 | 整个不渲染。改前是 `disabled={isToday}`,禁用按钮仍要被读屏读、仍要被 Tab 跳过 |
| 三个 section 统一成同一套卡片 | 框从内容上移到段落:`.ephemeris-section` 自己成为卡片,`.ephemeris-transits` / `.ephemeris-events` / `.ephemeris-panchanga-item` 交出各自的描边与卡面 |
| `.ephemeris-panchanga` 的 dl 网格保留 | 桌面 `repeat(5, ...)`、手机 `1fr` 两条规则原样保留(`viewport-breakpoint-contract``ephemeris-page` 两个测试都在守) |
**`.ephemeris-footer` 的处理(与任务书原文的差异,请复核)**:任务书 T5.2 写「底部 `.ephemeris-footer` 删除」。删掉的是那张**卡片**`EPHEMERIS_COPY.footerNote`(「这一页是天象本身,不是对你的判断。」)**原文保留**,改挂成页尾一行 `.ephemeris-outro` 三级色小字。理由:该句是这一页的定性边界句(DESIGN §16「文案」条:这一页是天象本身,不得写运势结论),连句子一起删会丢掉一条口径;而既有测试 `copy stays factual` 也在断言它在场。若产品要的是连句子一起删,请回我,这是一行的事。
四个降级分支 `natalMissing` / `panchangaUnavailable` / `transitsUnavailable` / `eventsUnavailable` 文案与可达性未动;未登录 `.ephemeris-message` 分支未动。
---
## 被改的既有断言
两条,都在下面列清「原值 / 新值 / 原因」,测试文件里也就地写了同样的三行注释。**没有静默弱化**:两条改后都比改前严格。
### 1 · `tests/chart-page-view.test.tsx`
原测试名:`mobile width keeps two centre lines and moves the full parameter card below the chart`
新测试名:`the parameters are one key/value table, not a per-breakpoint duplicate`
| | |
|---|---|
| **原值** | 断 `@media (max-width: 767px)` 块里三个开关:`.chart-page-center-compact { display: block; }``.chart-page-center-extra { display: none; }``.chart-page-params-below { display: block; }` |
| **新值** | 断参数只有一张 `.chart-page-param-row` 网格表;并断上述五个类名(含 `.chart-page-center-card``.chart-page-boundary-desktop`)在整份 CSS 里**都不再作为规则出现** |
| **原因** | 原断言守的正是「同一组参数按断点画三遍」,而 T5.1 要求的就是把它收成一张表,断言无法原样保留。新断言更强:不只要求当前画法对,还禁止任何按断点复制参数的写法回来 |
附带:原写法本身有个陷阱——`globalStyles.indexOf(".chart-page-center-compact")` 未命中时返回 `-1``- 2000` 之后 `indexOf("@media ...", -2001)` 会从文件开头重新搜,**静默锚到无关的断点块上**。新写法走 `cssDeclarations()` / 选择器集合,不做偏移量切片。
同一文件新增一条测试 `the planet table scrolls inside its own box instead of widening the page`(断 `overflow-x: auto` + `min-width: 0` + 表 `min-width`,并断三个 tab 源文件里 `<table>` 数与 `<div wrap>` 数相等)。
### 2 · `tests/ephemeris-page.test.tsx`
| | |
|---|---|
| **原值** | `copy stays factual` 里一句 `assert.match(markup, new RegExp(EPHEMERIS_COPY.today))`,只在 `date === today` 这一种渲染下断言「今天」在场 |
| **新值** | 拆成独立测试 `今天 is absent on today and present off it, never disabled`:今日断「今天」**不**在场,非今日断在场,两个状态都断 `disabled=""` 不出现 |
| **原因** | T5.2 验收标准要求「在今日时不出现『今天』按钮,而不是出现一个禁用按钮」。原断言恰好只覆盖今日那一种情况,照搬会要求今日也渲染该按钮,与验收标准直接冲突。新断言覆盖两个状态并额外禁掉禁用态,严于原来 |
注:断言用 `/disabled=""/` 而不是 `/disabled/`——`Button` 的 Tailwind 类串里本来就含 `disabled:opacity-50`,后者恒真。
测试总数 3350 → **3352**+2,均为新增,无删除)。
---
## 收尾验收对照
| 硬约束 | 结果 | 实测 |
|---|---|---|
| 1 · 只动 `chart-page/` `ephemeris/``.chart-page-*` / `.ephemeris-*` 区段 | ✅ | 见下「改了哪些文件」。`.rectification-*` / `.settings-*` / `.membership-*` / `.report-center-*` / `.personal-report-*` 一处未改;唯一触到的共享规则只摘掉了 `.chart-page-eyebrow` 一个选择器 |
| 2 · 按需 layer 行为不变、等待文案不换 spinner | ✅ | `onNeedLayer` 调用点与 `waitingLayer` / `waitingChart` / `waitingVarga` 逐字未动;`a pending western tab uses inline waiting copy instead of a spinner` 绿 |
| 3 · 四个降级分支文案与可达性不变 | ✅ | `EPHEMERIS_COPY` 未改任何字符串;四个分支渲染路径未动 |
| 4 · `CHART_VIEW_COPY.eyebrow` 保留 | ✅ | 保留,位置从 tab 行上方移到下方 |
| 5 · `tsc` 0 错 / `lint` 0 errorwarning ≤ 118 | ✅ | tsc 0 错;lint 0 error / **118 warning**,与基线同数 |
| 6 · 失败清单与基线逐条一致 | ✅ | `diff base.txt new.txt`**完全相同**fail 仍 31 |
| 7 · 改断言写「原值/新值/原因」三行 | ✅ | 两条,测试文件里就地注释 + 上面成表 |
| 8 · `/chart` `/ephemeris` 保持 `○ Static``/` 保持 `○` | ✅ | 干净重建后 `/` `○` · `/chart` `○` · `/ephemeris` `○` · `/reports` `ƒ`,与基线逐个相同 |
| 9 · 同提交更新 `DESIGN.md`;新文案对照 VOICE | ✅ | §15 §16 重写,见下 |
| 10 · 不升级依赖、不修范围外 warning | ✅ | `package.json` / `package-lock.json` 未动 |
### 改完实测
| 项 | 基线 | 改后 | 差 |
|---|---|---|---|
| `tsc --noEmit` | 0 错 | **0 错** | — |
| `npm run lint` | 0 error / 118 warning | **0 error / 118 warning** | 0 |
| `npm test` | 3350 / fail 31 | **3352 / fail 31** | +2 tests,失败清单逐条一致 |
| `next build` | `/` `○` `/chart` `○` `/ephemeris` `○` `/reports` `ƒ` | **完全相同** | — |
| 主 CSS chunk | 242,608 Bgzip 36,745 | **242,576 Bgzip 36,788** | 原始 32 B(−0.013%),gzip **+43 B+0.12%**,在 ±2% 内 |
gzip 基线是把工作树还原到 `50ce02c8` 后**干净重建**量到的,不是估算。首次改后构建复用了缓存、`.next/static` 里留着基线那份 CSS,两次数字曾一模一样——发现后两边都 `rm -rf .next` 重量,上表是重量后的值。
### 改了哪些文件
```
frontend/src/app/globals.css .chart-page-* / .ephemeris-* 区段)
frontend/src/components/chart-page/chart-page-view.tsx
frontend/src/components/chart-page/chart-param-lines.tsx → chart-param-table.tsx(改名 + 重写)
frontend/src/components/chart-page/chart-qizheng-tab.tsx
frontend/src/components/chart-page/chart-vedic-tab.tsx
frontend/src/components/chart-page/chart-western-tab.tsx
frontend/src/components/ephemeris/ephemeris-page.tsx
frontend/tests/chart-page-view.test.tsx
frontend/tests/ephemeris-page.test.tsx
frontend/DESIGN.md
docs/tasks/PROGRESS-cend-chart-eph-20260916.md
```
CSS 注释配平:改前改后都是 **84 / 84**。含花括号的注释 1 条,是 R4 留下的 `` `*-shell { padding-inline }` ``,本轮未碰;全部删改都走整段精确字符串替换,没有按逗号切选择器。
---
## 触发的让步顺序
**没有触发任何一条。** 让步顺序第 3 条(T5.1 的参数统一表:若合并后信息密度过高则退回保留 `.chart-page-center-card`)是本轮唯一相关的一条,没有用上——八行键值表在 ≥1024 与盘面左右并排、在窄屏是一张独立卡,没有出现密度问题。其余六条属于 R4 / R6 / R7 / R8。
---
## 环境缺口(不得记作「通过」)
本会话**无登录态、无 Chrome、无真实引擎返回**,以下全部只有静态与单测证据,浏览器级行为未验:
1. **行星表在 375px 宽下横向滚动、页面本身不横滚**(任务书环境缺口原文列明的一条)。已有的是 CSS 契约断言(`overflow-x: auto` + `min-width: 0` + 表 `min-width: 26rem`)与「三张表都包了 wrap」的源码断言,**不是真机滚动验收**。
2. **Tab 行在 375px 下横滚**(本轮新写法):五个 Tab 不折行靠 `flex-wrap: nowrap` + 容器横滚,同样只有静态证据。
3. **` 日期 ` 箭头按钮的读屏可访问名**`aria-label` 存在有断言,实际读屏播报未验。
4. **切 tab 时按需 layer 的真实拉取**`onNeedLayer` 调用点未改、单测覆盖渲染分支,但没有真实 `/api/varga_full`、`/api/western`、`/api/qizheng` 往返。
5. **五要素 / 行运 / 未来九十天三张卡在真实数据下的疏密**:fixture 是 golden,但卡片化后的实际观感未上真机。
以上第 1、2、3、5 条建议并进 `docs/testing/` 的人工清单,与 R4 的抽屉手势、R6 的报告目录、R7 的常驻条、R8 的弹窗尺寸一起走一次真机。
---
## 事故:误 pop 了 R6 会话的 stash(已完全恢复,但请知会)
量 gzip 基线时我用了 `git stash push` 把改动暂存、还原到 `50ce02c8` 重建,再 `git stash pop`。**stash 栈是整个仓库共享的一个 ref,不是每个 worktree 一份**——在我 push 与 pop 之间,`codex/cend-report-20260916`(R6)那个会话也 push 了一个 stash,于是我 pop 到的是**他们的** `r6-wip`,落进了我的工作树(`personal-report-center.tsx`、`personal-report-page.tsx`、两个 report 测试,以及他们那份 `globals.css`)。
处置:
1. 从 `git fsck --unreachable` 找回两个 stash commit:我的 `4c112c5b``r5-wip`)、R6 的 `40ff9a82``r6-wip`)。
2. `git stash store` 把 R6 的 `40ff9a82` **原样放回 stash 栈**(内容是 commit 对象,未被改写)。
3. 把误落进我工作树的 5 个文件还原成 `HEAD` 内容,工作树回到干净基线。
4. `git stash apply 4c112c5b` 取回我自己的改动,`git diff HEAD --stat` 与 stash commit 的 stat **逐行相同**10 文件 / +336 203)。
**没有任何 R6 的改动进入本分支的提交**(见上面「改了哪些文件」)。但请主会话转告 R6 会话:他们的 stash 位置变过,现在在栈上(`git stash list` 里的 `On codex/cend-report-20260916: r6-wip`),内容完整;直接 `git stash pop` 之前先确认自己的工作树是干净的。
教训,建议写进 `AGENTS.md` §3**多 worktree 共享一个 stash 栈,禁止用 `git stash` 做临时还原**。要量基线就先提交,或另开一个一次性 worktree 构建,不要动共享的 stash。