Commit Graph
2260 Commits
Author SHA1 Message Date
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 2533d5a328 fix(web): update chart-page sidebar contract to document-load navigation
Independent Staging Quality Gate / validate (push) Successful in 12m25s
Independent Staging Quality Gate / publish (push) Successful in 2m6s
Independent Staging Quality Gate / validate (pull_request) Successful in 14m58s
Independent Staging Quality Gate / publish (pull_request) Skipped
2026-09-15 19:48:10 +08:00
jesse-ux c6ecb86fb4 fix(web): leave chat with a document load for chart, ephemeris, and reports
Independent Staging Quality Gate / validate (pull_request) Failing after 9m45s
Independent Staging Quality Gate / publish (pull_request) Skipped
Independent Staging Quality Gate / validate (push) Failing after 9m14s
Independent Staging Quality Gate / publish (push) Skipped
Session URLs are written with history.pushState, so App Router
router.push cannot leave the home page. Sidebar destinations now
assign the document and stash the current conversation for return.
2026-09-15 19:29:41 +08: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
Jesse_ChenandClaude Opus 5 fadb64fbcf docs(tasks): accept the three read-only page briefs and file the fixes
Re-ran the checks independently rather than taking the progress notes at
their word. Most red lines hold: the api server sits at 11334 of 11363,
vendor/** is gated, the image installs nodejs and copies vendor, NOTICE
carries the Apache-2.0 attribution, the forbidden CLI subcommands are
blocked, neither new BFF imports billing or mastra, vedic-chart-svg did
not move, tsc is clean and lint has no errors.

Three findings. The qizheng adapter validates ketu_mode and
sidereal_mode, echoes them into calculation.*, and never passes them to
the engine: asking for descending-node returns 200 with a chart still
computed on the apogee school and no warning. The ephemeris brief
asserted that app-sidebar must not mention /ephemeris, which contradicts
the chart-page brief that was told to add both entries, so staging is
red. The ephemeris_events golden compares full-precision floats and
regenerates itself when missing.

Staging also still reports deployment.gitCommit 2d7698ea, six commits
behind, with gated paths changed in between.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 09:35:49 +00:00
Jesse_ChenandClaude Fable 5 4161222b2b docs(tasks): accept f51e494c and file the page.tsx growth-freeze fix
六条缺陷(BUG-699/704/705/706/708/709)全部实现,实现方式与任务书一致:
lookup 三分支(found/missing/unavailable,5xx 不宣告删除也不清 ?c=)、
交付卡保留而只置灰采用、按钮判据用 vargaStyleFollowupRenderable 复用
buildChoiceCard 的同一套门而不是复制条件、「相对支持度」进 MACHINE_VOICE_
LEXICON。文档齐全,生产 7b620c7a 受影响面也核对过了(不受影响)。

Linux 门禁:tsc 0 错;lint 0 error / 119 warning;本轮 8 个合同套件 130 项
全绿;build exit 0、/ 仍 ○ Static;首屏 gzip +0.13%。全量失败 父提交
d3a2c48b 32 → f51e494c 33。

多的一条是 page.tsx 从 1951 涨到 1964 行,撞了 chart-view-route.test.ts 的
<= 1951 上限,即 AGENTS.md §6 的增长冻结。d3a2c48b 绿、f51e494c 红,各跑
两次稳定复现。逻辑本身已经在 lib 里,超的只是十来行接线,搬出去即可,
不得放宽上限。

连带:staging 的 deployment.gitCommit 停在 2d7698ea,其后 6 个含门禁路径的
提交未部署,这条红很可能是原因之一。修好前产品没有环境可以实测。

另记两条无自动化覆盖的欠账:本轮动了数据库结构(新增触发器与函数)但
test:db 没跑,而门禁 workflow 里也不跑 DB 套件;标题与 updated_at 的修补
脚本在 staging 未执行,损坏面数字还空着。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 09:23:30 +00:00
jesse-ux f51e494c5a fix(chat): keep rectification sessions findable and keep the delivery card
Independent Staging Quality Gate / validate (push) Failing after 6m45s
Independent Staging Quality Gate / publish (push) Skipped
Rectification answers now advance chat_sessions.updated_at (BUG-704).
A ?c= id missing from the loaded page is fetched before anyone may call
it deleted (BUG-705). The range card no longer has a post-card tie-break
button; live questions leave the card visible with adopt locked
(BUG-706/708). Spoken copy bans 相对支持度 (BUG-709).

Task docs assigned 700-704; qizheng already took 700-703.
2026-09-15 17:10:53 +08:00
jesse-ux d3a2c48ba5 feat(web): add read-only /ephemeris page
Independent Staging Quality Gate / validate (push) Failing after 7m30s
Independent Staging Quality Gate / publish (push) Skipped
2026-09-15 16:40:56 +08:00
jesse-ux f7386e0717 fix(qizheng): pin vendor bytes to local a911c890 checkout
Independent Staging Quality Gate / validate (push) Failing after 6m58s
Independent Staging Quality Gate / publish (push) Skipped
Re-copy LICENSE/README/package.json/cli.cjs from the local yinduzhanxing snapshot. Drop dist/index.cjs that was assembled from npm. Do not include 6c27aab6 or 8bba9cb5.
2026-09-15 16:33:31 +08:00
jesse-ux 830799fafb feat(chart): add a read-only natal chart page
Independent Staging Quality Gate / validate (push) Canceled after 5m23s
Independent Staging Quality Gate / publish (push) Canceled after 0s
Open /chart from the sidebar without billing or a model. Five tabs; Western and Qizheng stay unavailable until those endpoints land. Ephemeris nav points at /ephemeris (404 until that page ships).
2026-09-15 16:27:50 +08:00
jesse-ux a3dbbde4a3 docs(tasks): record qizheng staging SHA e776cf9d 2026-09-15 16:24:33 +08:00
jesse-ux e776cf9d83 fix(qizheng): copy vendored stem-branch files from local upstream checkout
Independent Staging Quality Gate / validate (push) Canceled after 4m51s
Independent Staging Quality Gate / publish (push) Canceled after 0s
Read G:/Ferti/yinduzhanxing-codex-add-birth-time-rectification-skill (a911c890) and copy the listed vendor files by content. Rebuild the adapter from the 168-line CLI wrapper, then apply school parameters, boundary rewrite, and sanitized errors.
2026-09-15 16:21:04 +08:00
jesse-ux 25851dd338 feat(qizheng): vendor stem-branch and expose three read-only chart APIs
Add Apache-2.0 @4n6h4x0r/stem-branch 0.8.0, a seven-governors adapter,
and POST /api/qizheng, /api/western, /api/ephemeris_events.

BUG-700 remains blocked (do not call --pillars). BUG-701 and BUG-702 are
resolved. BUG-703 is investigating (panchanga Lahiri). Skill is not bumped.
2026-09-15 16:10:21 +08:00
Jesse_ChenandClaude Fable 5 3e58e85f8f docs(tasks): P0 — tie-break entry destroys the delivery card; session list lies about rectification
两组缺陷,分两单。

会话列表单追加 BUG-700/701:全仓只有 append_consultation_question 这个
咨询 RPC 写 chat_sessions.updated_at,校正的 turn 走自己的表从不推进,于是
校正会话的 updated_at 冻结在创建时刻——连着几小时答题也不动位置。叠加
BUG-699 的改名,列表变成「名字是今天、排序是旧日期」。而 resolveBootstrap-
SessionSelection 的 ?c= 只比对当前已加载那一页(SESSION_PAGE_SIZE = 40),
翻不到就判 missing、打「该对话不存在或已被删除」并清掉 URL。查过了没有任何
删除路径被触发,会话大概率仍在库里。

新单 BUG-702~704:applyLiveCandidateOffer 遇到任何未答的 choice/collect_spoken
就把 candidateOffer 从每一条消息上剥掉,而 requestTieBreak 必然写入这样一道题
——点卡上的按钮必然丢卡。按钮亮不亮看 tieBreakPersonalityAvailable(只看
followup),题能不能画成选择题看 buildChoiceCard 的 styleOptions.ok /
canRenderYearlessChoice,两个判据不一致,于是按钮亮着、点开是裸题,卡又没了,
两条路都断。交付旁白还写了 VOICE 明令禁止的「相对支持度」,并在自称不再问
分盘题的同一屏提供分盘题入口。

产品重申 BUG-686 的原意:卡上不要参考题按钮,出卡前收集完,以卡结算。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 07:44:40 +00:00
Jesse_ChenandClaude Opus 5 4cacea8eb1 docs(tasks): brief the api server decomposition
The line-count cap is nearly spent (11314 of 11363), but counting lines
misreads the problem. Three call sites outside the HTTP layer reach the
business logic by doing JyotishAPIHandler.__new__ on an uninitialised
handler — consultation_workflow_service twice, which is what MCP calls,
plus the golden capture and the offline accuracy report. The declared
"shared boundary" module imports back into the monolith, so the
dependency arrow points the wrong way and new logic has nowhere to land
except that class.

Four phases: remove the __new__ backdoor, extract the remaining methods
over 150 lines, replace the 72-branch elif dispatch with a table, then
re-freeze the baseline with a 50-line allowance instead of 300. Pure
relocation; the 3841-line security suite is the safety net and none of
its assertions may change. Serial after the qizheng brief, which owns
the file until it merges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 07:19:05 +00:00
Jesse_ChenandClaude Opus 5 6f74aa6704 docs(tasks): brief the read-only chart and ephemeris pages
Splits the remaining work into three briefs that own disjoint files so
agents can run them in parallel. The qizheng brief is widened to own
scripts/jyotish_api_server.py outright and register all three read-only
endpoints (/api/qizheng, /api/western, /api/ephemeris_events), because
the chart page needs a tropical natal route that no path exposes today
and the ephemeris page needs ingress/station scanning that /api/transit
does not provide.

The chart-page brief owns app-sidebar.tsx and adds both nav entries; the
ephemeris-page brief owns only its own route. Checking the tree changed
one plan: vedic-chart-svg.tsx is also imported by rectification-board, so
the component stays where it is instead of moving to a shared layer.

BUG ranges are pre-allocated per brief to keep parallel work from
colliding, and the panchanga Lahiri/Raman split found while prototyping
is filed as investigating rather than fixed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 07:09:23 +00:00
Jesse_ChenandClaude Opus 5 b3ccef4cbb docs(tasks): brief the native qizheng chart integration
Upstream branch codex/add-birth-time-rectification-skill a911c890 vendors
@4n6h4x0r/stem-branch 0.8.0 (Apache-2.0) and adds a seven-governors chart
adapter. Brief scopes the intake: vendored archival plus NOTICE, Node
runtime in the API image, vendor/** in gated-paths, a parameterised
adapter, and a thin /api/qizheng registration under the 11363-line cap.

Three defects were reproduced locally before filing: the four-pillars
hour branch is derived from the UTC wall clock (BUG-700, out of scope and
red-lined), ketuMode is pinned to the apogee school with no request
parameter (BUG-701), and the adapter boundary claims star spirits and
dignities that come back empty or unclosed (BUG-702).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-15 06:59:47 +00:00
jesse-ux 2d7698ead3 fix(chat): keep stored rectification titles on open
Independent Staging Quality Gate / validate (push) Successful in 11m43s
Independent Staging Quality Gate / publish (push) Successful in 2m3s
Opening a saved birth-time session no longer restamps the title or updatedAt from the wall clock. Occupies BUG-699, recurrence of BUG-553.
2026-09-15 14:48:03 +08:00
Jesse_ChenandClaude Fable 5 224244c014 docs(tasks): P0 brief — opening a stored rectification session renames and re-sorts it
openRectificationCase 构造 merged 时无条件 title: resolveSessionTitle(…) 与
updatedAt: timestamp()。同一个对象里 pinned 和 archivedAt 是从 existing 继承
的,说明作者知道这条路径会跑在已存在的会话上,只是漏了这两个字段。
resolveSessionTitle 的日期来自 new Date(),于是 9/12 建的会话被改名成
「9月15日 · 生时校正」,同名时再追加时:分。

两种损坏持久性不同,修复时要分开:persistSession 的 update 分支写 title
但不写 updated_at(BUG-553 的正确遗产),所以标题是永久写坏服务端,排序
只坏在客户端 state、刷新自行恢复。已坏的历史标题按 created_at 修回,取不到
就退回不带日期的中性标题,不猜。

复发自 BUG-553——它的防复发「updatedAt 只由对话活动推进」只是 Bug 记录里
的一句话,没有任何测试执行,且当时只覆盖元数据 PATCH 与五条客户端路径,
漏了当时就存在的校正 open 路径。本单要求把那句话变成测试。

咨询侧三处 resolveSessionTitle 都有 messages.length === 0 && 通用标题的守卫,
不受影响,明令不得顺手改。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 06:25:18 +00:00
jesse-ux ff5023a282 test(chat): restore two-layer markdown contract counts
Independent Staging Quality Gate / validate (push) Successful in 9m19s
Independent Staging Quality Gate / publish (push) Successful in 11m32s
Spoken and report layers each keep a message-markdown shell and both must call renderProse; login hard-jumps drop from 4 to 3 after the onboarding suggestion effect went away. No product code.
2026-09-15 13:27:17 +08:00
Jesse_ChenandClaude Fable 5 ca5ecafc1a docs(tasks): accept the two UI rounds and file the contract-test fix
Linux 上补了执行方在 Windows 上做不到的两项:全量 npm test 与 next build。

通过:tsc 0 错;lint 0 error / 120 既有 warning;测试总数 3214 → 3232;
next build exit 0、/ 仍是 ○ Static;首屏 JS gzip-9 585,246 → 583,660 B,
-1,586 B / -0.27%(口径同 09-02、09-06)。任务书逐条对照,删除范围与保留
范围都对,guided_topic 枚举保留、录入链路未被误删、复制仍走全文。

未通过 2 条,同一类——契约测试跟着代码漂了没更新,不是产品回归:
chat-bundle-splitting-contract 断言 message-markdown 包裹恰好 1 个,两层
可见性后是 2 个(同一 test 里 plainParagraphs(spoken) 字面量也已不存在);
chat-navigation-a11y-contract 断言 window.location.assign("/login") 恰好
4 处,删建议问题入口带走一处变成 3。基线 27 条失败与改后逐条一致,新增
的就是这两条。

执行方把全量测试记成 Windows 环境缺口(SKILL.md symlink EPERM、CRLF),
判断对他们的机器成立,也因此没机会看到这两条。修复单只改测试、禁止碰
frontend/src,要求失败数回到 27。

顺带澄清:PROGRESS 里记的 membership-page「login redirects」CRLF 失败在
Linux 上通过,不是回归。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 05:14:43 +00:00
Jesse_ChenandClaude Fable 5 4c002a084e docs(tasks): brief the settings dialog size recurrence and the nav emphasis bar
BUG-698 复发自 BUG-554。四个分区确实都映射到 .settings-modal,CSS 里
width 与 height 也都写了——但 .settings-modal 的 height/max-height 只用
dvh,没有 vh 回退。不支持 dvh 时整条声明作废,height 退回 auto,高度改由
内容决定,正是「切分区就立马缩小」。全文件 18 处 dvh 只有 sidebar-provider
那一处配了回退,本仓自己知道这个写法。

BUG-554 的防复发「设置弹窗必须同时声明 width 与 height」拦不住这次:它
检查声明存在性,不检查声明是否生效;守它的断言也只是一句 CSS 文本匹配。
本单把防线换成「height 用 dvh 必须先写 vh 回退」的全文件契约测试。

首要嫌疑不等于已证实——本会话没有浏览器。任务 1.1 要求执行方先量四个分区
的 getBoundingClientRect 并确认 height 是否被划掉,量不出来就转 investigating
交回产品,不得盲改。

另去掉设置分区菜单的左侧强调条(移动端下边框同理)。删之前必须先拆开选中态
与悬停态——它们共用同一条声明,色条是当前唯一的区分。左侧会话列表的 2px 色条
本轮保留,口径暂时不一致已授权。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 04:56:45 +00:00
jesse-ux 6c748d86b0 fix(ui): 44px coarse hits and align CSS breakpoints
Independent Staging Quality Gate / validate (push) Failing after 8m53s
Independent Staging Quality Gate / publish (push) Skipped
Touch-screen message actions get a 44x44 hit once gap and bottom margin open to 20px; fine-pointer geometry stays 27x34. Tablet CSS cuts at 1023 to match sidebarViewportForWidth. Report centre/reader join the 767 mobile cut; TOC keeps 860. Occupies BUG-695/696/697.
2026-09-15 12:46:59 +08:00
jesse-ux 8144fca27d fix(chat): fold natal reports and drop homepage topic cards
Independent Staging Quality Gate / validate (push) Failing after 9m47s
Independent Staging Quality Gate / publish (push) Skipped
Homepage no longer waits on /api/onboarding for six starter questions.
Natal answers show the spoken layer first; the Level 2 skeleton sits in a
collapsed 完整分析 block. Wide tables scroll sideways on a phone. Form
inputs are 16px so iOS does not zoom on focus.
2026-09-15 12:27:16 +08:00
Jesse_ChenandClaude Fable 5 899f955d4b docs(tasks): fold two mobile blockers into the reading-load round, brief touch targets and breakpoints
2026-09-15 的 UI 走查(web + 移动端)结果落盘。

并入 TASK-chat-reading-load:折叠层里的四列表在窄屏没有重排规则
(767 的卡片化只认三列,width:100% 又让 overflow-x 永不触发),它是
折叠能不能落地的前置;全局 input/select 是 14px,iOS 聚焦会把整页放大,
命中整条注册与资料录入漏斗。

新单 TASK-mobile-touch-and-breakpoints(BUG-695~697):消息操作按钮
命中区 27×34 且相邻只隔 1px;CSS 平板上限 900px 与 sidebar-state.ts 的
1024 不一致,901–1023 是混合态;报告域 720/760/860 三刀互不对齐,
761–860 目录已塌、正文还是桌面。含断点白名单契约测试作为防复发。

另加 docs/testing/ios-keyboard-composer-20260915.md:html/body overflow
hidden + 100dvh 外壳 + sticky 输入框 + interactiveWidget 只有 Android 认,
是键盘遮挡的风险形状,但代码断不了真假,交真机确认后再决定是否立单。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 04:02:50 +00:00
Jesse_ChenandClaude Fable 5 4147326115 docs(tasks): brief the homepage topic-card removal and the two-layer answer fold
首页「从一个主题开始」整段下线,连同它背后 /api/onboarding 的 LLM 取数
链路和 bootstrapPrepareReady 的揭幕闸门;聊天回答改成两层可见性——口语层
默认展开,第一个 H2 起的骨架进默认收起的「完整分析」折叠块。内容一字不
删,只改默认可见性与口语层形状。

记下与待验收项 BUG-630 的冲突:主题卡就是 guided_topic 的唯一发出点,
入口下线后该项走查不可执行,枚举值保留供历史会话读回。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
2026-09-15 03:18:22 +00:00
Jesse_ChenandClaude Opus 5 ebd5ba68a2 docs: clear the timezone gap and record what actually keeps the gate red
验收 8d56d0ab:字面量锁经变异法确认(加 **.generated_by 只红这一条,恢复即
绿),生产代码零改动。timezone 那条查下来不是缺口,是验收机少装了已声明的
timezonefinder>=6.5;装上后快速门 pytest 段 740 passed / 0 failed,BLOCKED.md
该条划掉。真正让门停在 exit=1 的是 npm test 的 27 条无 Docker 失败,另记一节
并写明本机「快速门通过」的口径。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-15 02:50:56 +00:00
jesse-ux 8d56d0ab0b test(report): lock binding exclusion allowlist literals (BUG-694)
Independent Staging Quality Gate / validate (push) Successful in 9m52s
Independent Staging Quality Gate / publish (push) Successful in 2m6s
Contract-test the D2 exclusion tuples so widening them cannot silently pass. Record the timezonefinder quality-gate gap in BLOCKED.md.
2026-09-15 10:41:10 +08:00
Jesse_ChenandClaude Opus 5 10b463b9e8 docs(tasks): lock the binding exclusion list and record the timezone gap
BUG-693/694 实现(1d2aeffa)验收通过:三次 CLI 加三个 PYTHONHASHSEED 哈希
全同,变异法验证覆盖 33/40 顶层键,耗时中位数 2737 ms(修复前 2769 ms)。
补漏单处理两个没被机制挡住的洞:排除集的「只能三类」靠的是生产者、质量门、
测试引用同一对常量,加第四类会自动放行,改为把字面量钉进合同测试;快速门
必红的 timezone inference 依赖缺口记进 BLOCKED.md(修复前同样红,非回归)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-15 02:34:37 +00:00
jesse-ux 1d2aeffaef fix(report): bind professional report hash to the delivered packet (BUG-693, BUG-694)
Independent Staging Quality Gate / validate (push) Successful in 9m45s
Independent Staging Quality Gate / publish (push) Successful in 2m14s
Rebind after sanitize, write an explicit binding_scope, and make the quality gate recompute coverage. Wall-clock fields stay in the packet but out of the hash.
2026-09-15 10:09:26 +08:00
jesse-ux 039b0a2608 fix(rectification): say 这两分钟 only when two candidates remain (BUG-692)
Independent Staging Quality Gate / validate (push) Successful in 9m43s
Independent Staging Quality Gate / publish (push) Successful in 8m50s
Count-aware closed-pool invite, catch the five stale contract assertions, and mark M1b V1/V2 as not_measured.
2026-09-15 09:43:51 +08:00
Jesse_ChenandClaude Opus 5 416b9a693c docs(tasks): bind the professional report receipt to what is actually delivered
上游 2026-09-14 的 4 个新提交里 SKILL.md 与校正代码零改动,核"要不要抄
它的 PL9 绑定投影"时量出我们自己两个问题:result_binding 绑的是中间态包
(18/36 个顶层键、6.24 MB,交付 10.04 MB),质量门只比自洽所以恒 passed;
被哈希的载荷含墙钟 elapsed_seconds,同一输入两次跑出不同 result_hash。
任务书写末尾按交付对象重绑、排除集显式进回执、质量门补覆盖校验;上游那条
投影优化实测收益 < 0.1 秒,记为不抄。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-15 01:29:00 +00:00