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

14 KiB
Raw Blame History

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-wrapmin-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-bodypadding-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-contractephemeris-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 popstash 栈是整个仓库共享的一个 ref,不是每个 worktree 一份——在我 push 与 pop 之间,codex/cend-report-20260916(R6)那个会话也 push 了一个 stash,于是我 pop 到的是他们的 r6-wip,落进了我的工作树(personal-report-center.tsxpersonal-report-page.tsx、两个 report 测试,以及他们那份 globals.css)。

处置:

  1. git fsck --unreachable 找回两个 stash commit:我的 4c112c5br5-wip)、R6 的 40ff9a82r6-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。