Commit Graph
1135 Commits
Author SHA1 Message Date
Jesse_ChenandClaude Opus 5 34628ecb67 feat(settings): 表单分区收窄到 440px,套餐卡收敛成两种互斥状态
Independent Staging Quality Gate / validate (push) Canceled after 6m18s
Independent Staging Quality Gate / publish (push) Canceled after 0s
任务书 TASK-cend-surfaces-claude-alignment-20260916 §R8(T8.1 / T8.2)。

T8.1(E13):880px 弹窗里「个人资料」「通用设置」的一列表单铺满约 690px,
字段与标签被拉断。表单分区的内容区加 `settings-dialog-content--form`,
子元素上限 440px 并左对齐;「星盘资料」「账户与点数」两个列表分区保持铺满。
上限只挂在滚动容器的子元素上,不挂 `.settings-modal` / `.account-settings-shell`,
因此传不到固定尺寸的弹窗(BUG-554 / BUG-698 的现象无法复现)。

T8.2(D13):套餐卡的三个修饰符可同时命中,叠出没有设计定义的边框与底色。
收敛成两种互斥状态 `is-current`(当前套餐)与 `is-recommended`(推荐),
「推荐且当前」判给当前套餐(该卡的动作是续费)。
`highlighted` 不再进 className,删掉 `--highlighted` 那条描边规则,
定位交给 use-billing-panel 里已有的 scrollIntoView + focus。
手机端「月卡置顶」改挂 `[data-plan-alias="monthly"]`——版位不是状态,
月卡成为当前套餐后排序不变。

测试:3350 → 3354(+4),fail 31 → 31 且失败清单与基线逐条一致。
6 处既有断言改动均就地写了「原值/新值/原因」,另有 3 次破坏性验证。
tsc 0 错;lint 0 error / 118 warning(持平);干净 next build 后 `/` 仍 `○ Static`,
产物 CSS gzip 39,034 → 38,882 B(−0.39%),三条新规则在产物里逐条取证。

环境缺口(未记为通过):四个分区切换不跳尺寸、支付下单流程、`?plan=` 滚动定位的
视觉确认——无 Chrome、无受控账号,见 PROGRESS 的环境缺口段。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 06:24:11 +00:00
Jesse_ChenandClaude Opus 5 50ce02c837 feat(ui): 星盘/星历/报告中心并入 app 外壳,侧栏不再消失
Independent Staging Quality Gate / validate (push) Failing after 9m57s
Independent Staging Quality Gate / publish (push) Skipped
三个页面此前各是脱离外壳的独立全屏路由,各写了一套一样的
*-shell / *-topbar(只有一个「返回对话」链接)/ *-hero 骨架,
侧栏在打开它们的瞬间整个消失。

新增 AppNavRail(只读:两个 GET,零写操作)与 SecondaryShell。
会话行走 sessionHref → /?c=<uuid>,跳转复用现有侧栏的
persistLoginSessionReturn + location.assign,行为完全一致。

刻意不带重命名/收藏/归档/删除与账户菜单:那套连着 Home() 的乐观更新与
回滚层,为四个路由把它整体上提远超需要,且会撞 useState 增长门禁。

四个路由渲染标记完全不变:/ ○、/chart ○、/ephemeris ○、/reports ƒ。
CSS gzip 39,825→39,727(−0.25%);per-route JS 体积构建不输出,
已作为口径缺口记录。

两处自身问题被测试抓到并修复:usePathname() 在 app-router 上下文外
返回 null(类型说是 string)、fetch 在 jsdom 里可能不存在。
另差点随 hero 一起丢掉 BUG-717 的 eyebrow 文案(成本与速度承诺,
会印在失败页上),已放回 tab 行下方。

/reports/[reportId] 留给 R6 与目录一起做;根边界页保留「返回对话」,
它们不得 import globals.css,挂不了外壳。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 06:03:30 +00:00
Jesse_ChenandClaude Opus 5 b3ea8c336e feat(ui): 侧栏三段合成一条平铺列表,助手消息去掉头像
Independent Staging Quality Gate / validate (push) Failing after 9m19s
Independent Staging Quality Gate / publish (push) Skipped
侧栏此前在第一条会话之前压着三段:星盘名字 chip 组、收藏对话 <details>、
历史对话 <details>——两个折叠箭头,底下都没有值得折叠的东西。现在是一条
平铺列表:收藏作为首个标签组(带 13px 星标),其余沿用既有的日期分组。

星盘入口收敛到一处。这里与任务书 D6 的字面写法方向相反:D6 说留侧栏删
账户菜单,我做的是删侧栏留账户菜单。理由——D6 写于侧栏只有 2 个导航项时,
现在是 4 个;且 chip 点下去只是开弹窗(page.tsx 里三个回调都是
openAccountDialog("chart-library")),一组只会开弹窗的名字没有导航价值。
连带删 charts/onSelectChart/onAddChart props、SidebarChart 类型、
sidebarCharts 派生与一批 CSS。

助手头像删除,--assistant-content-inset 由 calc(32px + gap) 归零,
追问 chip 与运行时间轴改为与正文对齐。/jyotish-logo.png 文件保留。

顺带关闭 R2 留下的隐患:入口 pill 36px 低于 44px 触摸推荐值,补
::after inset -4px 热区扩展,并在 touch-target-contract 里接替
已删除的 .chart-nav-chip。

测试 3350 不变,fail 仍 31 且与基线逐条一致;/ 仍 Static;
CSS gzip 41,044→39,825(−3.0%),三轮累计 −3.1%。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 05:46:29 +00:00
Jesse_ChenandClaude Opus 5 62903b7a12 feat(ui): 空状态改成「问候 + 输入框 + 两枚入口 pill」
Independent Staging Quality Gate / validate (push) Failing after 9m13s
Independent Staging Quality Gate / publish (push) Skipped
此前空态是 hero 卡(h1 clamp 到 52px)加两张 min-height 228px 的产品卡,
输入框被压在约 800px 内容之下,主动作不是视觉焦点。

改法:问候拆成 StarterGreeting 留在对话区并底对齐,两个产品入口降级成
StarterEntries 渲染在 composer 之后。composer 本身一行未动——它在空态与
会话态是同一个 DOM 位置,首条消息落地时不重挂载,草稿/焦点/排队卡都不受影响。

顺带修掉:空态 composer 1040px、会话态 760px,发首条消息时输入框会当场
变窄一截。两态统一到 --session-column-width,并新增断言锁住。

校正入口保留三个服务端驱动的文案分支(我第一版收成了两个,是
rectification-agentic-entry 打红才发现)。

DESIGN.md:Product entrypoint card 整节重写为 Starter home;删掉
Suggestion card 死文档(它描述的主题卡样式正是本轮删除的 CSS)。

测试 3350 不变,fail 仍 31 且与基线双向零差异;/ 仍 Static;
CSS gzip 41,096→41,044(−0.13%)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 05:31:15 +00:00
Jesse_ChenandClaude Opus 5 66d9f59d84 feat(ui): 标题不再落宋体,强调色分阶换 coral,删输入框常驻底栏(BUG-737/738)
Independent Staging Quality Gate / validate (push) Failing after 9m26s
Independent Staging Quality Gate / publish (push) Skipped
BUG-737:--font-display 以两个从未加载的 Anthropic 授权字体开头
(Tiempos Headline / StyreneB:无 @font-face、public/ 无字体、layout.tsx
只 vendor 了 Inter),于是每个中文标题都掉到 Songti SC / SimSun——20 条
规则宽,含助手回答正文的 h2/h3。display 与 body 合并为同一条无衬线栈,
层级改由字重承担(33 条 display 规则 400→500)。

拉丁衬线方案实测否决:Newsreader 拉丁子集 132 KB(Inter 的 2.7 倍),
只为给一个品牌字上衬线,且会把「D10 事业盘怎么读」劈成两种字形。

BUG-738:亮色 #85432f 与暗色 #d78064 不同源;--color-ring 在
@theme inline 里硬编码不跟随 :root。产品拍板换 Claude coral #cc785c,
但实测它作文字色只有 3.14:1,而 62 个调用点里 53 个是 color:。
按角色拆两阶:--color-action #a9583e(文字 4.85:1)、
--color-action-strong #cc785c(填充/导轨/焦点环,3:1 非文字阈值)。
--report-accent 刻意保持 #85432f(报告是纸面,不跟应用强调色)。

T1.3/T1.4:模型选择器进 ChatComposer 的 toolbar 插槽,删掉常驻 44px 的
.composer-footer;顶栏 68→46px,「分析对象:」改为标题旁静默 chip。

防复发:新增 font-stack-loadable-contract,断言字体栈里每个 family 要么
vendored 要么是系统字体,且 --font-display 不得触达任何 CJK 衬线。

测试 3346→3350,fail 仍 31 且清单与基线逐条一致;/ 仍 Static;
CSS gzip 41,095→41,096(+0.002%);快速门 pytest 段 798 passed / 0 failed。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 04:53:14 +00:00
Jesse_ChenandClaude Opus 5 3fd74daf34 docs(tasks): C 端次级页面对齐任务书(R4–R8)
星盘/星历/报告三个页面各是脱离 app 外壳的独立全屏页,侧栏整个消失,
且三家各写了一套一样的 shell/topbar/hero 骨架——与上一单空状态同根因。

R4 抽只读导航外壳(前置)→ R5 星盘+星历、R6 报告
R7 生时校正、R8 设置+充值 可并行

设置单已于 111b4a84 合入,R8 阻塞解除。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 04:18:37 +00:00
Jesse_ChenandClaude Opus 5 111b4a8455 fix(settings): 弹窗高度补 vh 基线,分区菜单去掉强调条(BUG-698)
Independent Staging Quality Gate / validate (push) Failing after 9m25s
Independent Staging Quality Gate / publish (push) Skipped
设置弹窗的固定高度只用 dvh 写、没有回退。不认识该单位的引擎会把整条
height 与 max-height 作废,盒子退回按内容撑开,于是切分区就跳大小——
这正是 BUG-554 现象的复发,而 BUG-554 的防复发「必须同时声明 width 与
height」只检查声明存不存在,挡不住「写了但没生效」。

实测(Chrome 151,真实产物 CSS + 复刻 DOM,1440×900):dvh 正常时四个
分区恒定 866.80×640px,**事故不复现**;摘掉 dvh 后变成 313/313/378/1130,
宽度不动——与用户描述的形状完全一致。因此机制已证实,但用户当时的浏览器
未定位,BUG-698 记为 investigating 而非 resolved。

附带发现:任务书要求照抄的重复声明式回退 `height: 100vh; height: 100dvh;`
在本仓根本发布不出去——Lightning CSS 会合并同名属性的重复声明只留最后一条,
全仓唯一那处回退(sidebar-provider)在线上早就是死的,还有一条测试专门守着
这个从未发布过的写法。改用 @supports (height: 1dvh):vh 作基线,dvh 作升级。
修复后不支持 dvh 的引擎也收敛到恒定 640px,支持的逐像素无变化。

同轮按产品决策去掉设置分区菜单的左侧/下方强调色条,选中与悬停改用面与
墨色等级区分,不用色相、不用字重。左侧会话列表的色条本轮不动。

- 新增 viewport-unit-fallback-contract(3 条,全文件),三次破坏性验证各自打红
- account-dialog-overlay 新增同尺寸契约与分区菜单契约
- 三条钉死旧 dvh 字面量的既有断言按「原值/新值/原因」更新,均未弱化
- tsc 0 错;lint 0 error / 118 warning(持平);npm test 3346/3300/fail 31,
  失败清单与基线逐字相同;/ 仍 ○ Static;样式 gzip +0.38%;
  快速门 pytest 段 792 passed / 1 skipped / 0 failed

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 03:50:38 +00:00
Jesse_ChenandClaude Opus 5 5582091851 refactor(api): 抽出 offline compute mixins,关掉 2/4 处 handler 伪造
Independent Staging Quality Gate / validate (push) Canceled after 2m18s
Independent Staging Quality Gate / publish (push) Canceled after 0s
spike 闸门(任务书 §5.2)结果为红,按 §6.3 退回 A 方案。

spike:115 个闭包方法整体移入 ConsultationComputeMixin 后,
tests/test_api_server_security.py 一字不改跑出 1 failed / 128 passed。
test_chart_async_job_executes_in_background 挂在
monkeypatch.setattr(jyotish_api_server, '_write_async_job_record', ...):
调用方法随 mixin 搬走后从新模块 globals 解析,补丁落在旧模块绑定上不生效。
已实证把同一 fake 打到 mixin 模块即恢复原行为,故为落点问题而非搬坏。
循环 import 不是障碍(移动集不引用 JyotishAPIHandler)。

退回 A 的实际交付:新建 scripts/offline_compute_mixins.py,
收 BadRequest、3 个模块级助手,以及 RequestParamMixin /
VedastroEvidenceMixin / SynastryMixin 共 7 个方法(300 行),
JyotishAPIHandler 通过继承保留全部方法,HTTP 侧零变化。
consultation_workflow_service.build_runtime_evidence_helpers 与
local_accuracy_report 改为直接实例化 mixin,不再伪造 handler。

11 个搬走的定义经 SHA-256 逐个比对与搬走前字节级相同;
jyotish_api_server.py 的 diff 为 11 行插入 / 378 行删除,无重排。

scripts 侧 __new__ 4 → 2(剩 2 处都在咨询工作流链上);
类方法 225 → 218;行数 11,291 → 10,924。
合同测试收紧基线并新增 scripts 侧专门断言与反向 import 断言;
两次反向验证(加回 __new__ / 加类方法)均正确变红。
新增 tests/test_offline_compute_mixins.py 覆盖此前零覆盖的 MCP 路径,
并加入 CORE_PYTEST_TARGETS。

tests/test_api_server_security.py 一字未改,129 passed。
快速门 pytest 段 798 passed / 1 skipped / 0 failed。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 03:46:01 +00:00
Jesse_ChenandClaude Opus 5 30f9e0943f docs(tasks): 后门单 §5.1 闭包重算结果
从四处 JyotishAPIHandler.__new__ 的实际入口重算传递闭包(含模块级
execute_consultation_workflow 的 handler._x() 一层):实测 115 方法 /
4,104 行,非任务书估算的 8 方法 / 314 行;碰 HTTP 上下文者 0 个,
任务书 §5.1 的停手条件未触发。

闭包按入口分裂为可搬的 7 方法 / 300 行(vedastro 证据 + 合盘)与
不可搬的 114 方法 / 4,086 行(咨询工作流),后者含 _compute_chart_sync
与 _build_chart_prompt_pack 两个 ≥150 行方法,与 §4.3 冲突。

未改 scripts/ 与 tests/。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 03:46:01 +00:00
Jesse_ChenandClaude Opus 5 a2c1f1fbda docs(tasks): C 端界面向 claude.ai 产品界面对齐任务书(三轮串行)
根因:CLAUDE_DESIGN.md 扒的是 claude.com 营销官网,它自己在 Known Gaps
里写明 claude.ai 产品界面不在范围内,而 DESIGN.md 把它当成了产品界面的
实现契约。于是营销页语汇(hero band、3-up feature card)进了聊天空状态,
拉丁 display face 的衬线规则套到中文界面变成了宋体。

R1 字体 + 强调色 + chrome 瘦身(BUG-737/738)
R2 空状态重做
R3 侧栏拍平 + 入口收敛 + 去头像

三轮都动 globals.css,不得并行。附原型图链接。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 03:42:28 +00:00
Jesse_ChenandClaude Opus 5 5094fd2620 docs(tasks): 后门单改写为 mixin 方案(产品选 B),修正闭包规模
第一版写「8 方法 / 314 行」错了一个数量级。错因:闭包只跟 self._x(),而
_compute_consultation_workflow 只有 6 行、转给模块级
execute_consultation_workflow(self, ...),那个函数体 394 行、对传进来的
handler 调 16 个方法再往下扇出。跟丢那一跳,300 行被当成了全部。
执行方重算:约 115 方法 / 4,104 行,占全类 51% 方法;碰 HTTP 上下文的
仍是 0 个——本单成立的前提没变。

产品在 A/B/C 中选定 B(mixin 抽取),并授权把 §4「不得搬 ≥150 行业务
方法」按本意解释:那条红线针对的是 C 那种逐行改写,而 mixin 是把方法体
原样挪家、self 含义不变、靠 MRO 解析,HTTP 那一面零变化。决策记录里已
写明这是该红线的推翻记录。

新增 spike 闸门:搬进 mixin 后 test_api_server_security.py 一字不改直接
跑,绿则继续、红则退回 A(7 方法/300 行、关 2 个伪造点)。已查明两个降
风险事实(security 测试无结构性断言、增长合同用整文件正则),并点名真
风险是循环 import——闭包引用同文件 44 个模块级函数 + 21 个常量/类。

另修正 __new__ 归零口径:合同基线 33 = scripts 4 + tests 29,tests 侧含
不许改的 security 测试,所以归零只针对 scripts 侧 4 → 0。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 03:14:41 +00:00
Jesse_ChenandClaude Opus 5 dc8cae316e test(contract): 让前端源码合同跟上搬家,快速门 Python 段恢复全绿(BUG-736)
Independent Staging Quality Gate / validate (push) Failing after 10m4s
Independent Staging Quality Gate / publish (push) Skipped
三条断言过期,不是保证丢了:

- 149e1ec4 把创建路由改走 chatSessionCreateInsertRow(...),`user_id: user.id`
  字面量消失。按三栏改成路由断 `userId: user.id`、write-contract 断
  `user_id: input.userId`,两处都断,不放宽。
- 状态下沉第二批把合盘搬进新建的 use-synastry.ts,而 _home_surface() 只拼
  OPTIONAL_HOME_HOOKS 白名单,于是 fetch("/api/synastry" 与「未能存入历史」
  在并集里找不到。白名单补上该 hook 并注明新增 Home 级 hook 必须同步登记。

为什么没被拦住:这几条是 Python 测试,断言对象却是前端源码;前端轮次的验收
口径不含快速门,AGENTS §10 又只要求「任何 Python 改动」跑快速门——纯前端改动
落在两张网中间。验收方两轮都只跑前端套件,带红合入。防复发写进 BUG-736。

验证:test_supabase_user_data_contract.py 8 条全绿;快速门 pytest 段
792 passed / 1 skipped / 0 failed(此前 3 failed)。整体仍退出 1,剩余唯一
原因是本机无 rsync、无 Docker 的既有环境缺口。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 02:12:36 +00:00
Jesse_ChenandClaude Opus 5 7ae6df3ebb docs(tasks): 状态下沉第二批进度记录与真人走查清单
Independent Staging Quality Gate / validate (push) Failing after 6m17s
Independent Staging Quality Gate / publish (push) Skipped
进度记录含三簇 20 个状态的分类表(每个写明谁在读)、改前改后实测、
既有断言改动的三栏说明、反向验证、lint warning 逐条比对、以及
session 簇留 4 个在外壳的让步说明。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 02:02:22 +00:00
Jesse_ChenandClaude Opus 5 6df40c322c fix(rectification): 记录与校正区间冲突时记录优先、分歧并列(BUG-691)
Independent Staging Quality Gate / validate (push) Canceled after 3m23s
Independent Staging Quality Gate / publish (push) Canceled after 0s
医院记录那一分钟落在校正区间外时,交付卡以前只说一句「相差 N 分钟」:
没说默认按哪个时间排盘,采用按钮也仍写中性的「更像这个」,用户看不出
点下去会把之后的排盘换成另一分钟。

产品负责人 2026-09-14 拍板「记录优先,分歧如实呈现」:

- 冲突文案补满三层——默认仍按出生记录时间排盘、经历指向另一段时间相差
  N 分钟、两条路都可以走。
- 冲突态采用按钮改「改用校正结果」,按钮下按列写明
  「选它之后,排盘会从出生记录时间 hh:mm 换成 hh:mm」。
- 新增 FORBIDDEN_RECORD_VERDICT_PHRASE 锁住 D4:不得宣布记录不准,
  也不得宣布校正结果无效。

只改文案层与采用入口措辞。打分、判据、采用 RPC、置信度与确认门控、
数据库一律未动;不新增入口、不加确认弹窗;记录落在范围内或来源是
「大概时间 / 时间段」时卡片与今天完全一致。Skill 未 bump,只补
references §6.1。

验收:tsc 0 错;lint 0 error;npm test 3335 项 fail 31,失败清单与基线
37e6c519 逐条一致(全部是无 Docker / 无外网的既有环境缺口);next build
通过且 / 仍 ○ Static;首屏 chunks gzip +269 B(+0.019%)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 02:02:03 +00:00
Jesse_ChenandClaude Opus 5 63c419f375 perf(consultation): 健康探测加 TTL、yoga 表达式只编译一次
Independent Staging Quality Gate / validate (push) Canceled after 27s
Independent Staging Quality Gate / publish (push) Canceled after 0s
BUG-734: probe_official_rest_health 不是 ping —— 它把一份虚构 smoke 排盘
POST 给官方 HoroscopePredictions(实测单次 1,034 ms),还经 call() 吃掉对方
每分钟 5 个限流令牌之一,而结论零 TTL。连续 6 轮前台请求下,第 6 次探测会被
本地限流器挡下、反过来报出假的 official_blocked,真正的业务调用还要和它抢令牌。

加进程级 TTL 缓存(成功 60 s / 失败 10 s,配置变即失效,缓存键只记 key 配没配
的布尔)。force_refresh 默认 True:诊断端点调的是裸 gateway_status() 且该文件
本轮不得改,默认实时才不会让运维看到旧结论;run_gateway_packet 显式走 False。
探测在锁外执行。6 轮实测:探测 6→1、握手 5→1、限流令牌 6→1。

连接复用(任务书 6.2)按让步顺序砍掉:实测 urllib.request 没有连接池,模块级
共享 opener 在 6 次请求下仍开 6 条 TCP 连接,按任务书写法只能骗过「同一个
opener 实例」的断言而省不掉任何握手。另立单。

BUG-735: yoga_engine._eval_custom 对静态规则表的表达式每请求重新编译。实测每次
检测 386 次源码编译(182 次 eval 字符串 + 204 次 ast.parse/compile)。拆出
_build_custom_exec_globals(每次新建,绑定当前盘 ctx)与 lru_cache 的
_compiled_eval_code / _compiled_exec_code,只缓存 code object,绝不缓存求值
结果。求值语义逐条对齐改前。第二次检测起编译 0 次,单次 27.4 ms → 3.3 ms。

等价用同进程差分(BUG-733 的做法):192 条去重表达式 × 3 张公开虚构示例盘,
与逐字复刻的改前实现同值,另有反向验证证明差分非恒真。

未改 scripts/jyotish_api_server.py。既有断言一条未改。新增 23 条测试。
快速门唯一红的 test_chat_page_uses_authenticated_cloud_persistence 经干净
origin/staging 检出复跑确认为基线红,记入 BLOCKED.md BLK-002,不顺手修。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 02:01:33 +00:00
Jesse_ChenandClaude Opus 5 10afdcddeb docs(tasks): 校正标题修补迁移的进度记录与 Bug 历史回填
Independent Staging Quality Gate / validate (push) Canceled after 38s
Independent Staging Quality Gate / publish (push) Canceled after 0s
- PROGRESS-rectification-title-repair-migration-20260916.md:前提复核、
  逐字一致的复核命令、幂等两层的说明、基线比对与环境缺口。
- BUG_HISTORY:BUG-699 / BUG-704 的「修复」补记改由迁移承担,「验证」
  的欠账改成待产品在 staging 应用后从 NOTICE 回填。不新增编号。
- BLOCKED.md:BLK-002 无 Docker / 无本地 PostgreSQL,test:db 未跑、
  db:migrate:check 缺 SCHEMA_DATABASE_URL,附已实跑的替代证据。
- deploy/README.md:一次性数据修补走同一个 Migrate Staging Database
  按钮,行数看日志里的 notice 行。
- docs/tasks/README.md:该单改记待验收。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 01:39:03 +00:00
Jesse_ChenandClaude Opus 5 37e6c519f7 docs(tasks): 校正状态板 + 状态下沉第二批 + 后门单 + 对账清单
① 状态板校正:09-15~16 这 10 份任务书的实现早已合入 staging 并经逐单
   验收,状态板却仍写「待领取 / 待验收」。改成「已验收」并补上落点 SHA
   与验收要点;顺带补齐 8 个 PROGRESS 列。防复发写进「命名与归档」:
   实现合入的同一次推送必须同时改状态板那一行。

② 新增 TASK-home-state-lowering-batch2-20260916(不占 BUG 号):
   第一批 f8e607c2 已验收(useState 66→52、useRef 41→39、散装
   rectification* 归零)。本单搬剩下三簇 session*10 / profile*6 /
   synastry*4,目标 52→≤36;并修第一批尾巴——
   createRectificationShellSetters 每帧新身份多出的那条 exhaustive-deps
   warning(119→120),正解是稳住 setter 身份而不是塞进 deps。

③ 新增 TASK-api-server-backdoor-close-20260916(不占 BUG 号):
   实测四处 __new__ 的传递闭包只有 8 方法 / 314 行且 0 个碰 HTTP 上下文,
   占全类 4%。所以关后门不必捆绑 2,000+ 行体量搬运。产品拍板阶段 2/3
   不立单,由 3b17c1b2 换好的门禁长期推进。原 decomposition 单标为已取代。

④ 新增 RECONCILE-20260916:另外 7 份 09-10~14 的单没有 PROGRESS、但
   引用的 BUG 号都是 resolved,无法从 README 判断,列成一页纸让执行方
   回填;另附三条确定没做的证据、两条未闭环状态、BLK-001 仍红。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 01:13:26 +00:00
Jesse_ChenandClaude Opus 5 4f643aa095 docs(tasks): 缓存生效后剩下的两块——外网健康探测与运行时重复编译
f8e607c2 上重测:BUG-727 的快照缓存确实每轮命中、响应体 52 万→40 万
字符,但耗时几乎没变。6 次调用累计 5.30 s,网络仍占 70%(poll 2.42 +
ssl read 0.76 + 握手 0.56),本地 swisseph 只剩 2.4%。

- BUG-734:剩下那一次外网是 gateway_status 的健康探测。它不是 ping——
  probe_calculate_health 把一份虚构排盘 POST 给 api.vedastro.org,并且
  consume_rate_token() 会烧掉对方一个业务限流令牌;opener 默认 None,
  每次新建 TLS(6 次调用 3 次握手,单次 0.186 s);结果零 TTL。
  修法:成功 60 s / 失败 10 s 的 TTL,配置变即失效,诊断端点走
  force_refresh 保持实时;共享 opener 摊掉握手。
- BUG-735:yoga_engine._eval_custom 对 references/yoga_rules.json 的
  192 条静态表达式每请求重新编译 102 次,多语句的还要先抛一次
  SyntaxError 再 parse + 改写 AST + compile,占 9.4%。
  修法:lru_cache 存 (mode, code object)。硬红线:绝不缓存求值结果,
  那会跨用户串盘。

等价证明沿用 BUG-733 的同进程差分,不再写跨机 golden。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-16 00:55:05 +00:00
jesse-ux f8e607c29a refactor(home): 校正面 15 个状态从 Home 下沉
Independent Staging Quality Gate / validate (push) Failing after 6m43s
Independent Staging Quality Gate / publish (push) Skipped
Home() useState 66->52, useRef 41->39. Shell-facing fields merge into one object;
subtree state lives in useRectificationSurface. Chat props 20->7. Growth contract
rebaselined. Zero behavior/copy change.
2026-09-16 08:33:48 +08:00
jesse-ux 3b17c1b242 test(freeze): 增长冻结改盯耦合,行数降为粗护栏
Independent Staging Quality Gate / validate (push) Failing after 6m21s
Independent Staging Quality Gate / publish (push) Skipped
Home() useState/useRef 与 JyotishAPIHandler 类方法/__new__ 不得增长。行数改为开工实测基线加余量。产品授权删除参数式 hook 零 React hook 规则。
2026-09-16 08:02:43 +08:00
jesse-ux 2b7b45657b test(rectification): prove memoization in-process; tolerate golden float drift (BUG-733)
Independent Staging Quality Gate / validate (push) Canceled after 5m0s
Independent Staging Quality Gate / publish (push) Canceled after 0s
Replace whole-structure golden == with same-process cached vs None fallback equality, plus discrete-strict / measured-tolerance golden comparison. Do not rebuild the golden JSON.
2026-09-16 07:56:56 +08:00
jesse-ux 51a65d927f docs(tasks): record BUG-732 implementation SHA
Independent Staging Quality Gate / validate (push) Failing after 6m19s
Independent Staging Quality Gate / publish (push) Skipped
2026-09-16 07:41:41 +08:00
jesse-ux dcfc2f15af fix(consultation): count visible text only for session quota (BUG-732)
Replace append_consultation_question so the 200,000 quota sums only user-visible text, and add a 1,000,000-byte whole-JSON physical cap. Both still return session_full. Advisory lock, request_id idempotency, and the 200-message cap are unchanged.
2026-09-16 07:41:41 +08:00
Jesse_ChenandClaude Opus 5 7227b1ed8d docs(tasks): R1 验收修复单——等价 golden 跨机不稳,门禁靠运气绿
对 BUG-721(引擎记忆化)的验收:实现通过,等价性我独立复核过——改前
6b3248bf 与改后 e4788dfc 在同一台机器上跑同一 payload,candidate_scores
逐字相同(8.6273 / 8.6226 / 8.1701),9 条计数断言全过;tsc 0、lint 0
error、全量前端 3291(fail 31) → 3304(fail 31) 失败清单逐条一致、next
build 绿且 / 仍 Static、首屏 gzip 0.00% 变化。

唯一一条红的是 test_score_candidates_matches_baseline_golden:golden 与
本机实际输出有 4 处浮点尾数差(score 1.0e-4 ×2、margin_percent 1.1e-3
×2),改前改后都对不上,说明是 golden 存全精度浮点跨机不稳,不是实现
改坏了。复发自 BUG-712。而 tests/test_rectification_*.py 在
CORE_PYTEST_TARGETS 里,staging 自动门禁会跑它——今天绿只是因为 CI 那台
机器的舍入和执行方一致。

修复单只改测试:主证据换成同进程差分(四个缓存键置 None 即回退旧路径,
A/B 严格相等,不经过任何跨机变量),golden 降为离散字段严格相等 + 浮点
带容差;禁止用重建 golden 来修;防复发升级为仓库级并排查另外五份 golden。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 23:39:30 +00:00
jesse-ux 149e1ec4c3 fix(consult): drop traces, budget checkpoints, silent summary inherit
Independent Staging Quality Gate / validate (push) Canceled after 3m8s
Independent Staging Quality Gate / publish (push) Canceled after 0s
BUG-729: dropped history rounds leave an omission marker in the model-visible summary slot.
BUG-730: checkpoint threshold is 0.4 of historyBudgetChars (128k still 16,000).
BUG-731: session_full new chat copies owned context_summary on the server; clients send only continued_from_session_id.
2026-09-16 07:38:36 +08:00
jesse-ux e61535f464 fix(consultation): 外网证据按盘+日期缓存,超时取消前台任务
Independent Staging Quality Gate / validate (push) Canceled after 2m21s
Independent Staging Quality Gate / publish (push) Canceled after 0s
BUG-727:同日 VedAstro 快照零等待,跨日先用旧的并后台刷新;join 超时必须 cancel,budget 不超过 2×join。BUG-728:western_evidence_packet 无读取点,默认不再进咨询响应。jyotish_api_server.py 未增长(11334→11291)。
2026-09-16 07:36:09 +08:00
jesse-ux b9c053778a fix(rectification): 请求内 Case 档案只读投影写即失效缓存
Independent Staging Quality Gate / validate (push) Canceled after 2m18s
Independent Staging Quality Gate / publish (push) Canceled after 0s
同一请求里 dossier/compute 按 (fn, userId, caseId) 合并重复读,其它 RPC 与 .from 立即失效。路由入口各包一处,零调用点改动。
2026-09-16 07:32:34 +08:00
Jesse_ChenandClaude Opus 5 e4788dfc00 docs(tasks): 换掉两条增长冻结口径 + page.tsx 状态下沉第一簇 + C1 提前
产品 2026-09-15 三项拍板,落成两份新单与两处既有单的修订:

- 新增 TASK-freeze-metric-change-20260915(无 BUG 号,后面两单的前置):
  两条冻结余量已用完(page.tsx 1951/1951 余 0;api server 11334/11363 余 29),
  冻结从「逼新代码往外走」退化成拦路。实证:page.tsx 行数砍 59% 但 Home()
  的 useState 从 56 涨到 66;api server 225 个类方法只有 12 处真碰 HTTP。
  主门换成耦合指标,行数降为粗护栏;同时推翻 §6「参数式 hook 内部保持
  0 个 React hook」——那正是状态搬不走的原因。
- 新增 TASK-home-state-lowering-20260915(无 BUG 号):先搬 rectification*
  那 15 个 state 进已经是 dynamic 子树的校正面,Home() useState 66 → ≤53。
  零行为变化;串行在 freeze-metric-change + C2 + R3 之后。
- 修订 TASK-consultation-external-evidence-cache-20260915:依赖反转,C1 排在
  API server 拆解之前(它动模块级函数,拆解动类方法);补「不得新增类方法、
  行数余量仅 29」的硬红线。
- 修订 TASK-api-server-decomposition-20260916:串行依赖加 C1 与
  freeze-metric-change;__new__ 计数按 grep 的 4 计(原文 3 是文件数);
  阶段 4 收尾口径改写;基线 11,314 → 11,334。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 23:15:37 +00:00
jesse-ux 58ccafb67c fix(rectification): stop re-parsing settled messages on every stream frame
Independent Staging Quality Gate / validate (push) Failing after 6m18s
Independent Staging Quality Gate / publish (push) Skipped
2026-09-16 07:13:12 +08:00
jesse-ux 53a37ce944 fix(rectification): 候选分钟不变量记忆化(BUG-721)
Independent Staging Quality Gate / validate (push) Canceled after 1m57s
Independent Staging Quality Gate / publish (push) Canceled after 0s
Shadbala / Ashtakavarga / Dasha 时间轴进 static context;过境盘按事件日期缓存 chart;探针网格相同时只算一次。打分与决策回执与基线 golden 逐字相同(剔除计时字段)。
2026-09-16 07:11:07 +08:00
jesse-ux 8b982baf64 fix(rectification): 分类器失败、引擎忙、整轮超时不再归因错
Independent Staging Quality Gate / validate (push) Canceled after 4m2s
Independent Staging Quality Gate / publish (push) Canceled after 0s
点选题把分类器两次异常说成用户没说清(BUG-722);引擎 429 被压成坏了且重算静默失败(BUG-723);两次 attempt 总预算大于路由 maxDuration(BUG-724)。本单只改归因:classifier_unavailable 请用户重发、busy 分档并可见「这次没有重新比较」、整轮 225s 预算不够则 host fallback。不改计费、分类模型、并发闸门。
2026-09-16 07:06:57 +08:00
Jesse_ChenandClaude Opus 5 11893c7f97 docs(tasks): 普通聊天审计三单(外网缓存 / 记忆三缺口 / 对话上限)
只读审计 origin/staging @ 6b3248bf 后出的三份任务书,含产品 2026-09-15
拍板的三项口径:

- external-evidence-cache(BUG-727/728,Python,串行在 api-server-decomposition
  之后):每轮每域同步等 api.vedastro.org,cProfile 前三名全是 TLS 往返,本地
  swisseph 只占 0.022 s;前台 1.5 s / 后台 8 s / 2 个 worker 且超时不 cancel。
  定案按「出生数据+岁差+交点+UTC 日期」缓存,与引擎内部同键;不许「干脆不调」,
  那会重开 BUG-301。另 western_evidence_packet 122 KB 无人读。
- context-memory(BUG-729/730/731,TS,可并行):droppedCount 算了没人读、
  摘要阈值与预算脱钩(窗口 < 70,667 即每轮静默丢)、写满时不继承摘要。
  定案静默继承,摘要文本永不由客户端提供。
- session-capacity(BUG-732,一份迁移,可并行):200,000 额度一半被思考文本
  吃掉,约 19 轮即写满。定案思考文本不计入,另设按整条 JSON 计的物理上限。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 22:47:55 +00:00
Jesse_ChenandClaude Opus 5 a8d29d1b6c docs(tasks): 记录产品两项决定(分类用会话模型 / 年份采样不改)
产品 2026-09-15 对审计单里挂着的两个待拍板项给出结论,两项都是「不改」:

- 意图分类继续用会话选定的模型,不引入便宜快模型,模型目录不新增
  「工具模型」角色。failure-attribution 单 §4.6 立为决策记录,§10 从
  「待产品拍板后另开单」改为已决定不做;本单只改归因,不改用哪个模型。
- 只给年份的事件继续采满 12 个月,降采样不做、研究单也不立。
  engine-memoization 单 §4.2 / §11 同步,并写明后续不得以性能为由重提。

两条都加了「要重提必须先拿到产品新的授权」,避免下一轮被当成遗漏又提一次。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 17:17:29 +00:00
Jesse_ChenandClaude Opus 5 e4f9f3ee0f docs(tasks): 校正链路审计四单(引擎记忆化 / 故障归因 / 渲染拆分 / 档案缓存)
只读审计 origin/staging @ 6b3248bf 后出的四份任务书:

- engine-memoization(BUG-721,纯 Python 可并行):一次重算 45% CPU 在重复
  算同一份 Shadbala,过境盘按候选算了 2196 次(应 36),鉴别探针算两遍,
  _cached_rows 是死代码。本机等价实验 3358 → 1604 ms,candidate_scores 与
  decision_receipt 逐字相同。只做记忆化,不改算法。
- failure-attribution(BUG-722/723/724,独占 route.ts):分类器失败被说成
  用户说不清且丢证据;引擎 429 被当成引擎坏、不重试不打日志(复发自
  BUG-715);attempt 210s × 2 > maxDuration 240s(复发自 BUG-059)。
- settled-render-split(BUG-725,前端可并行):校正会话流式每帧重渲整条
  对话并重跑已结算消息的 Markdown;BUG-473 的咨询面拆分没有跟过来。
- request-dossier-cache(BUG-726,串行在 failure-attribution 之后):一轮
  取 3.44 次整份 Case 档案,改成写即失效的请求作用域缓存,零调用点改动。

纯文档推送,不触发门禁、不发布镜像、不部署。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 17:13:52 +00:00
jesse-ux 6b3248bf53 fix(vedastro): pin SDK at install and cap free-tier wait
Independent Staging Quality Gate / validate (push) Successful in 9m36s
Independent Staging Quality Gate / publish (push) Successful in 18m18s
Image build patches vedastro.check_for_update to a no-op after pip install so import cannot hit pypi or upgrade the pin. Free-tier queue waits are capped to VEDASTRO_TIMEOUT_SECONDS and fail fast as free_tier_rate_limited. Gateway status exposes runtime mode as booleans without secrets. BUG-719 resolved; BUG-720 stays investigating until production env is filled in.
2026-09-16 00:25:15 +08:00
jesse-ux 62be52dacf fix(chart): skip VedAstro on chart-page first paint
Independent Staging Quality Gate / validate (push) Canceled after 2m16s
Independent Staging Quality Gate / publish (push) Canceled after 0s
The natal /api/chart request from the chart page now sends skip_vedastro_main_entry_overview, matching the ephemeris page. Mapper and contract never read that evidence. BUG-718 recurs from BUG-161. Tests lock both foreground natal paths.
2026-09-16 00:22:00 +08:00
Jesse_ChenandClaude Fable 5 ce1939b074 docs(tasks): 星盘页与 VedAstro 外网调用脱钩 + 运行期真相两单
星盘页首屏那一发 /api/chart 没传 skip_vedastro_main_entry_overview,
本机实测冷算 0.40–0.66 秒里约 0.36 秒是 VedAstro 空转(连 endpoint 都
没配的情况下);带标志的同一调用是 5 毫秒。生产 env 开着 network 与
fanout,等于首屏同步等 24 个外部请求加 3 次领域扫描,而前端 mapper 与
contract 根本不读这份证据。BUG-718,复发自 BUG-161。

运行期单记录两条新发现:官方 vedastro==1.23.25 其实是 REST 客户端,
且 import 时请求 pypi 并 pip install --upgrade 自升级(实测 pin 装完
一 import 即变 1.23.26);无 key 时免费层排队是同步 sleep 加进程级
全局锁,24 个请求约 4.8 分钟堵住前台线程。台账补 ERR-107 / ERR-108,
生产 env 核对清单交产品负责人执行。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 15:47:32 +00:00
jesse-ux 69ede4367f fix(ci): migrate staging automatically before deploy
Independent Staging Quality Gate / validate (push) Successful in 10m6s
Independent Staging Quality Gate / publish (push) Successful in 4m18s
Quality gate now dispatches Migrate Staging Database, waits for success, then dispatches Deploy staging. Automatic migrate attests the in-progress gate run so the two jobs cannot deadlock. Manual migrate is unchanged. Staging schema changes must stay backward-compatible with the currently deployed app.
2026-09-15 23:36:09 +08:00
jesse-ux 1a73f64ecd fix(ci): let staging migration resolve the latest gated SHA
Independent Staging Quality Gate / validate (push) Successful in 9m38s
Independent Staging Quality Gate / publish (push) Successful in 2m7s
Leave Migrate Staging Database deploy_sha empty (or type latest) to use the newest successful backend-quality-gate push. Filled 40-hex still takes the original path. Production workflows stay required.
2026-09-15 23:19:44 +08:00
Jesse_ChenandClaude Fable 5 9bf13df023 docs(tasks): auto-migrate staging before deploy instead of a manual button
今天 backend-quality-gate 通过后自动 dispatch deploy-staging,但
deploy-staging.yml 里一次都没提到迁移——忘点 Migrate Staging Database 就让
新代码跑在旧 schema 上,没有任何东西会拦。这已经靠人记着(见
PROGRESS-consultation-context-and-cache-20260906「部署前须先 Migrate」)。

判据是现成的:db-migrate.mjs 的 check 模式有挂起返 3、无挂起返 0,还顺带查
checksum 漂移。而且迁移本身靠 migration.schema_migrations 台账幂等,无挂起时
天然 no-op——所以不必先检测再决定跑不跑,直接每次都跑,少一个分支。两个
workflow 又共用 concurrency group staging-mutation,链式触发不会互相踩。

新顺序:gate 通过 → 触发迁移并等它成功 → 才 dispatch 部署。迁移失败不部署。

这条顺序引入一个以前不存在的纪律:迁移完成到镜像替换之间,旧代码会短暂跑在
新 schema 上。所以 staging 迁移必须对当前已部署的代码向后兼容,破坏性变更要
拆成"先加、发代码、再删"两轮。以前迁移窗口由人控制所以不需要这条,自动化后
它是硬约束,必须同轮写进 AGENTS.md §7.6——不写就是埋雷。

回滚部署不自动迁移(迁移不会因镜像回退而撤销)。生产两个 workflow 一行不碰:
restore_verified 本质上是人对恢复点的担保,不可自动化。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 15:14:21 +00:00
Jesse_ChenandClaude Fable 5 de47c06d97 docs(tasks): stop making the product owner hand-copy a 40-hex SHA
migrate-staging-database 的 deploy_sha 挡的是「迁移必须钉在真正过了门禁的
修订上」:格式校验、查该 SHA 有没有成功的 backend-quality-gate 运行、与
staging head 比对后把纯文档前进的判定交给背书过的 controller。这三条不能丢。

但产品手填的那个值,恰恰就是「最新一个过了门禁的 staging 提交」——机器能
自己算,而且需要的 API 查询在同一步里已经写好了。改成:留空即自动解析,
填了就完全走原路径(回滚与迁移到更早修订的唯一手段)。解析出来后仍然照常
跑一遍全部校验,两条路径共用同一套门。

范围比看上去小:Deploy Staging 在门禁通过后由 backend-quality-gate 自动
dispatch,正常根本不用点;真正每次都要手填的只有 Migrate Staging Database
一个按钮。

生产两个按钮保持手填。它们额外要 allow_rollback / recovery_reference /
restore_verified,设计意图就是逼人说清楚要发什么;在生产省掉这步不是便利,
是拆护栏。

AGENTS.md §2.7 禁止代理改 workflow,产品本次明确授权,已写进决策记录,
否则执行方会拒改;授权范围仅限本单点名的文件与改动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 15:07:08 +00:00
Jesse_ChenandClaude Fable 5 ebd6175b40 docs(tasks): give the title repair a button — move it into a migration
BUG-699 / 704 的数据修补写成了 repair-rectification-session-titles.mjs,要
SCHEMA_DATABASE_URL。但 deploy/run-staging-migration.sh 只做三件事:跑
002-ensure-business-compatibility-roles.sql、compose --profile migration run
--rm migrator 应用 frontend/supabase/migrations/ 下的 SQL、打印已应用清单,
不执行任意 Node 脚本。其余 workflow 也都不跑它。于是一个已经验收的修复卡在
"没有按钮"上,用户的历史会话名字还全是错日期。

脚本里 TITLE_MATCH_SQL / TITLE_APPLY_SQL 和活跃时间回填本来就是纯 SQL,
Node 只负责连库和打印。搬进一次性迁移就能复用产品已经会用的
Migrate Staging Database 按钮,不用 SSH、不用口令。

生产安全性已核实:7b620c7a 没有 use-rectification-surface.ts,标题是固定的
「生时校正」也不写库,where 在生产上自然匹配 0 行,天然 no-op。

红线:SQL 逐字照搬不许优化;不得动 workflow 或 compose;用户手写标题不碰;
必须幂等;两段 update 各要 RAISE NOTICE 打行数——那是产品唯一看得到数字的
地方。脚本降级为只读核对工具,不删。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 15:01:30 +00:00
Jesse_ChenandClaude Fable 5 e7016551db docs(tasks): accept the chart-page unblocking (BUG-715~717)
/chart 从 ƒ Dynamic 变回 ○ Static——外壳预渲染、数据客户端取,整页不再阻塞
在五个引擎调用上。引擎超时 45s → 10s(实测单次最慢 0.60s)。postEngine 返回
ok/busy/http_error/timeout/bad_payload 并各留一条只含路径、状态码、耗时的
console.warn,不含出生资料。用户文案分两档:429 说「正忙,稍等几秒」,其它说
「算不出来,已经记录下来了」,不再把可能永不恢复的情况说成暂时的。eyebrow
只剩成功分支一处,改成「主盘直接算 · 分盘按需 · 不消耗点数」,去掉速度承诺。
引擎结果缓存也落地了,任务 3.2 未走让步。

门禁:tsc 0 错;lint 0 error / 119 warning;全量 fail 31 → 30 且零新增,总数
3275 → 3288;build exit 0、/ 仍 ○ Static;首屏 gzip +0.003%。

红线复核:page.tsx 未增长;限流名单与配额未动;四个体系数据一个没删。

欠:浏览器走查;staging 仍停在 2533d5a3 未部署。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 14:57:12 +00:00
jesse-ux 5a8328e591 fix(web): paint the chart page shell before engine calls
Independent Staging Quality Gate / validate (push) Successful in 27m22s
Independent Staging Quality Gate / publish (push) Canceled after 47s
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.
2026-09-15 22:51:15 +08:00
Jesse_ChenandClaude Fable 5 8caa2a2b4c docs(tasks): P1 — the chart page blocks the whole document on five engine calls
先排除了两个嫌疑,都有实测:本机起 6.9.16 引擎,按 chart-view-load 的同一
套参数逐个计时,/api/chart 0.60s、chara 0.00s、varga_full(17 分盘) 0.00s、
western 0.00s、qizheng 0.15s,合计 0.75 秒;把这五个真实响应喂给
buildChartView 跑 13 种形态(四种 birthTimeStatus、三种 ayanamsa、缺
placeLabel/timezoneId/name,以及 chara/varga/western/qizheng 分别为 null),
13 种全部 status=ok,一次没抛。引擎不慢,mapper 不抛。

瓶颈是结构:/chart 在构建里是 ƒ Dynamic,而 c6ecb86f 把侧栏入口从
router.push 改成 window.location.assign,于是点一下就整文档重载,服务端
SSR 里 await 完 1 串 4 并才开始画,浏览器在此之前什么都没有;engineTimeoutMs
是 45 秒,maxDuration 60,白屏能真跑满 45 秒(BUG-716)。

失败又不可诊断:postEngine 的 !response.ok 与 catch{} 把 429、500、超时、
坏 JSON 全碾成同一个 null,零日志;chart-view-load 末尾还有一个 catch{}。
「引擎忙等一下会好」和「这张盘有 bug 等多久都不会好」共用一句「过一会儿
再打开」(BUG-715)。

开页还并行打 /api/western 与 /api/qizheng——两个都在 HEAVY_COMPUTE_PATHS
里、配额只有 2,一次开页吃满整台容器的重计算配额,而这两路只喂给用户
可能根本不点的两个 tab;cache: "no-store" 且无服务端缓存。eyebrow
「直接计算 · 打开即有 · 不消耗点数」在失败分支也印一遍,正压在「算不出来」
上面(BUG-717)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 14:13:59 +00:00
jesse-ux 298a73e8e5 fix(ci): keep vendor/** on both quality-gate path filters
Independent Staging Quality Gate / validate (push) Successful in 9m36s
Independent Staging Quality Gate / publish (push) Successful in 8m7s
BUG-714: deploy/gated-paths.txt already listed vendor/** after the
qizheng vendoring, but backend-quality-gate.yml did not. The contract
test requires the two lists to match.
2026-09-15 18:31:46 +08:00
jesse-ux 8d6a4bd065 fix(audit): include /ephemeris in the capability-audit route set
Independent Staging Quality Gate / validate (push) Failing after 9m31s
Independent Staging Quality Gate / publish (push) Skipped
BUG-713: the staging quality gate failed because _scan_app_routes
found the new ephemeris page and the exact allowlist did not.
2026-09-15 18:16:57 +08:00
Jesse_ChenandClaude Fable 5 766028399c docs(tasks): accept the page.tsx growth fix — rectification P0 scope is green
page.tsx 1964 → 1951,正好回到冻结上限。tsc 0 错;lint 0 error / 118 warning;
定向 8 套件 134 项全绿;全量 fail 33 → 31 且无新增;build exit 0、/ 仍 ○ Static;
首屏 gzip +0.14%。

行为逐条核对未变:resolveBootstrapSessionSelection 与 readLoginSessionReturn
整体下沉进 home-cloud-sync 的 resolveLookupBootstrap,BUG-705 的 found /
missing / unavailable 三分支原样;await 后的 aborted 早返回改成抛 AbortError,
与该 effect 既有写法一致,外层 catch 本就放行 AbortError。

BUG-699 / 704 / 705 / 706 / 708 / 709 全部验收通过。

剩余 4 条红全属另一会话的星历 / 星盘页,已由 TASK-readonly-pages-fix-20260916
接手;staging 仍停在 2d7698ea 未部署。另记两条无自动化覆盖的欠账:动了数据库
结构但 test:db 没跑(门禁 workflow 里也没有),以及标题 / updated_at 修补脚本
在 staging 未执行。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 10:05:01 +00:00
jesse-ux a38a941522 fix(qizheng): pass school options into the vendored chart and stabilize gates
Independent Staging Quality Gate / validate (push) Failing after 8m1s
Independent Staging Quality Gate / publish (push) Skipped
BUG-710: call getSevenGovernorsChart with ketuMode/siderealMode so
calculation.ketu_mode is the engine school, not the request echo.
BUG-711: stop forbidding /ephemeris in the sidebar contract.
BUG-712: compare ephemeris event longitudes at 6 decimals and fail
closed when the golden is missing.
2026-09-15 17:54:20 +08:00
jesse-ux 6bb892b826 fix(chat): keep page.tsx at the 1951-line freeze after lookup wiring
Independent Staging Quality Gate / validate (push) Failing after 6m40s
Independent Staging Quality Gate / publish (push) Skipped
Move BUG-705 bootstrap selection + session lookup into
resolveLookupBootstrap so Home only awaits once. The 1951 cap in
chart-view-route.test.ts is unchanged.
2026-09-15 17:40:17 +08:00