按需计算:指定日期的行运(BUG-1816) #173

Open
opened 2026-11-09 00:16:18 +08:00 by Claude · 6 comments
Collaborator

聊天中可以算任意指定日期的行运。参数:日期、地点、时区、岁差、交点、位置口径,都要显式传入。输出带 profile、输入指纹、状态、原始数据;计算失败时如实留下缺口,模型不得自己编日期。依据:占星师 Q9 与第五轮第 9 条。

状态:排队。依赖第七轮整合(Narayana 第六轮 R1/R3、证据字段、新界面)先上 staging;上线后 Claude 写任务书并改为“待执行”。验收由 Claude(jyotisha-2a)负责。

聊天中可以算任意指定日期的行运。参数:日期、地点、时区、岁差、交点、位置口径,都要显式传入。输出带 profile、输入指纹、状态、原始数据;计算失败时如实留下缺口,模型不得自己编日期。依据:占星师 Q9 与第五轮第 9 条。 状态:排队。依赖第七轮整合(Narayana 第六轮 R1/R3、证据字段、新界面)先上 staging;上线后 Claude 写任务书并改为“待执行”。验收由 Claude(jyotisha-2a)负责。
Claude added the agent/试点agent/排队 labels 2026-11-09 00:16:21 +08:00
Author
Collaborator

这一单要做什么:聊天里可以算“某一天的行运”。同时搭好六类按需计算共用的骨架:统一的后端接口、统一的输出格式(口径、输入指纹、状态、原始数据、缺口)。岁差、交点、位置口径、时区、地点一律显式传入,不用默认值;算不出来时只留缺口,模型不得自己编日期。

为什么只放这一单:后面五个按需计算(行运区间、年盘、分盘、运限、问卜)都要往这个骨架里加,等它验收后再依次放出,避免互相冲突。

怎么算做完:缺任一口径就拒绝;不同岁差/交点结果确有不同且如实标注;失败时没有任何编出来的日期;Bug 记录写 BUG-1816。

<!-- agent:claude plan brief=docs/tasks/TASK-ondemand-transit-date-20261109.md branch=codex/ondemand-transit-date-20261109 base=b453505d50f8d9c5ff4a472eb225a0c60a68e607 --> **这一单要做什么**:聊天里可以算“某一天的行运”。同时搭好六类按需计算共用的骨架:统一的后端接口、统一的输出格式(口径、输入指纹、状态、原始数据、缺口)。岁差、交点、位置口径、时区、地点一律显式传入,不用默认值;算不出来时只留缺口,模型不得自己编日期。 **为什么只放这一单**:后面五个按需计算(行运区间、年盘、分盘、运限、问卜)都要往这个骨架里加,等它验收后再依次放出,避免互相冲突。 **怎么算做完**:缺任一口径就拒绝;不同岁差/交点结果确有不同且如实标注;失败时没有任何编出来的日期;Bug 记录写 BUG-1816。
Claude added agent/待执行 and removed agent/排队 labels 2026-11-09 07:19:16 +08:00
Grok added the agent/执行中 label 2026-11-09 08:31:58 +08:00
Collaborator

这一单停在任务书写的第一个「需拍板」条件上:本命计算没有显式的 node_mode / position_mode,按需工具无法「与本命同口径」。没有推任何代码,工作树是干净的。

查到的证据

环节 事实 位置
前端本命请求 schema 有 ayanamsa,没有 node_mode、position_mode frontend/src/mastra/consultation-workflow.ts:9(ayanamsa 在 :18)
发请求的 body ...workflowInput 原样发出,所以这两个值根本没到后端 同文件 :175
服务器绑定盘字段 ServerChartToolInput 里只有 ayanamsa frontend/src/lib/consultation-route-service.ts:47-59(ayanamsa 在 :57)
后端默认 body.get('node_mode', 'mean') —— 默认 mean,调用方从未显式给过 scripts/jyotish_api_server.py:2767(同类写法还有 :4366、:6140、:6277)
引擎位置口径 _calc_sidereal_planets_for_jd 里写死 _sidereal_calculation_profile(jd, 'legacy'),legacy 已等于 apparent scripts/jyotish_engine.py:1070(标准化见 :1029-1043)
领域服务默认 payload.get("node_mode", "mean") scripts/domain_calculation_service.py:134

也就是说:岁差是显式的,节点口径和位置口径是后端默认值替用户做了选择——正是占星师 Q9 反对的那件事。信封里如果写 profile_source: "engine_default",按需工具就把这个默认固化了;如果写成"与本命同口径",那句话本身不成立。

顺带确认(会影响方案):引擎现在只能算 apparent(:1070 写死)。请求 position_mode: "mean" 只能返回 blocked + gap position_mode_unsupported。要真正支持 mean,得改冻结的 scripts/jyotish_engine.py 的 _calc_sidereal_planets_for_jd,那不在本单范围内。

请拍板的三件事

  1. 本命计算要不要从现在起显式传口径?(我倾向要)
    • A(推荐):前端本命请求加 node_mode / position_mode,写进 consultationInputSchema 与 ServerChartToolInput,随回执一起返回;按需工具直接沿用同一份显式口径。代价:动 consultation-workflow.ts、consultation-route-service.ts 和回执,得另开一单(本单任务书明确不许改答题与 route)。
    • B:产品定一组默认(例如 node_mode=mean、position_mode=apparent)写进计算合同文档,按需工具显式填这两个值并在信封里标 profile_source: "engine_default"。代价小,但默认值仍然替用户做了选择。
    • C:本单只做后端共用模块与信封(scripts/ondemand_calc/),前端接入等 A 或 B 定下来再做。
  2. 上面那个 position_mode 的缺口怎么办:先接受「mean 一律 blocked + gap」,还是安排一单去改引擎(要解冻 jyotish_engine.py)。
  3. #173–#178 要不要等口径定了再依次放开:骨架本身(信封字段、指纹、失败不编日期)不依赖口径,A/B 定下来只影响 profile.ts 一个文件。若先做 C,后面的单可以并行。

我这边不占着这一单,已经放开锁;定了口径或选了 C,我随时接着做。

<!-- agent:grok decision --> **这一单停在任务书写的第一个「需拍板」条件上:本命计算没有显式的 node_mode / position_mode,按需工具无法「与本命同口径」。没有推任何代码,工作树是干净的。** **查到的证据** | 环节 | 事实 | 位置 | | --- | --- | --- | | 前端本命请求 schema | 有 `ayanamsa`,**没有** `node_mode`、`position_mode` | `frontend/src/mastra/consultation-workflow.ts:9`(`ayanamsa` 在 :18) | | 发请求的 body | `...workflowInput` 原样发出,所以这两个值根本没到后端 | 同文件 `:175` | | 服务器绑定盘字段 | `ServerChartToolInput` 里只有 `ayanamsa` | `frontend/src/lib/consultation-route-service.ts:47-59`(`ayanamsa` 在 :57) | | 后端默认 | `body.get('node_mode', 'mean')` —— 默认 mean,调用方从未显式给过 | `scripts/jyotish_api_server.py:2767`(同类写法还有 :4366、:6140、:6277) | | 引擎位置口径 | `_calc_sidereal_planets_for_jd` 里写死 `_sidereal_calculation_profile(jd, 'legacy')`,`legacy` 已等于 `apparent` | `scripts/jyotish_engine.py:1070`(标准化见 :1029-1043) | | 领域服务默认 | `payload.get("node_mode", "mean")` | `scripts/domain_calculation_service.py:134` | 也就是说:岁差是显式的,节点口径和位置口径是**后端默认值替用户做了选择**——正是占星师 Q9 反对的那件事。信封里如果写 `profile_source: "engine_default"`,按需工具就把这个默认固化了;如果写成"与本命同口径",那句话本身不成立。 **顺带确认(会影响方案)**:引擎现在只能算 `apparent`(`:1070` 写死)。请求 `position_mode: "mean"` 只能返回 `blocked` + gap `position_mode_unsupported`。要真正支持 mean,得改冻结的 `scripts/jyotish_engine.py` 的 `_calc_sidereal_planets_for_jd`,那不在本单范围内。 **请拍板的三件事** 1. **本命计算要不要从现在起显式传口径?**(我倾向要) - A(推荐):前端本命请求加 `node_mode` / `position_mode`,写进 `consultationInputSchema` 与 `ServerChartToolInput`,随回执一起返回;按需工具直接沿用同一份显式口径。代价:动 `consultation-workflow.ts`、`consultation-route-service.ts` 和回执,得另开一单(本单任务书明确不许改答题与 route)。 - B:产品定一组默认(例如 `node_mode=mean`、`position_mode=apparent`)写进计算合同文档,按需工具显式填这两个值并在信封里标 `profile_source: "engine_default"`。代价小,但默认值仍然替用户做了选择。 - C:本单只做后端共用模块与信封(`scripts/ondemand_calc/`),前端接入等 A 或 B 定下来再做。 2. **上面那个 `position_mode` 的缺口怎么办**:先接受「mean 一律 blocked + gap」,还是安排一单去改引擎(要解冻 `jyotish_engine.py`)。 3. **#173–#178 要不要等口径定了再依次放开**:骨架本身(信封字段、指纹、失败不编日期)不依赖口径,A/B 定下来只影响 `profile.ts` 一个文件。若先做 C,后面的单可以并行。 我这边不占着这一单,已经放开锁;定了口径或选了 C,我随时接着做。
Grok added agent/需拍板 and removed agent/执行中agent/待执行 labels 2026-11-09 08:34:05 +08:00
Author
Collaborator

产品负责人已拍板(2026-11-09),三条:

  1. 本命计算以后要显式传入交点和位置口径,默认值就是现在实际在用的“平交点 + 视位置”。这部分另开一单做,前端和回执不在本单。
  2. 平位置(position_mode=mean)暂不支持:请求时返回 blocked,并附 position_mode_unsupported 缺口。不要改冻结的引擎文件。
  3. 本单按方案 C 做:只做后端共用模块、输出信封和第一个工具(指定日期的行运)。

详细要求在分支上的 docs/tasks/FIX-ondemand-transit-date-1.md(与原任务书冲突时以它为准)。

<!-- agent:claude plan brief=docs/tasks/FIX-ondemand-transit-date-1.md branch=codex/ondemand-transit-date-20261109 base=b453505d50f8d9c5ff4a472eb225a0c60a68e607 --> **产品负责人已拍板(2026-11-09)**,三条: 1. 本命计算以后要显式传入交点和位置口径,默认值就是现在实际在用的“平交点 + 视位置”。这部分另开一单做,前端和回执不在本单。 2. 平位置(position_mode=mean)暂不支持:请求时返回 blocked,并附 position_mode_unsupported 缺口。不要改冻结的引擎文件。 3. 本单按方案 C 做:只做后端共用模块、输出信封和第一个工具(指定日期的行运)。 详细要求在分支上的 `docs/tasks/FIX-ondemand-transit-date-1.md`(与原任务书冲突时以它为准)。
Claude added agent/待执行 and removed agent/需拍板 labels 2026-11-09 09:04:21 +08:00
Collaborator

按 FIX 任务书的 C 方案做完了:后端共用骨架 + 第一个工具(指定日期的行运),没有碰前端。

建了什么

文件 内容
scripts/ondemand_calc/contract.py 信封 jyotish.ondemand_calc.v1;公共校验(日期 / lat / lon / tz 或 timezone_id);口径解析;input_fingerprint(sha256,键排序、浮点固定 6 位);blocked_envelope。顶部 docstring 写明字段、错误规则和 #174–#178 怎么注册
registry.py TOOLS = {"transit_date": ...} + 唯一入口 ondemand_calc_api(body);未知/缺 tool → blocked 并点名
transit_date.py 九曜恒星黄经 / 星座 / 度数 / 星宿与 pada / 逆行 / 日速度;按传入的本命上升与月亮算宫位;UTC 与当地时间都给
jyotish_api_server.py 一条薄 elif /api/ondemand_calc(_load_local_module('ondemand_calc.registry')),无新增类方法

调用入口两种都给了:函数 ondemand_calc_api(body) 和薄路由 /api/ondemand_calc。

口径(照你 2026-11-09 的拍板):岁差必填;节点/位置口径缺省用 mean / apparent,信封标 profile_source = product_default_explicit,没有写成「与本命同口径」;position_mode = mean 返回 blocked + position_mode_unsupported(没改冻结引擎);timezone_id 按天换算(伦敦 1 月 0、6 月 +1),tz=0 保持 0 不会变 8;不给 time 按当地 12:00 并标 local_noon_default。

测试

命令 结果
tests/test_ondemand_calc_contract_20261109.py 8 过
tests/test_ondemand_transit_date_20261109.py 12 过
tests/test_api_server_growth_contract.py 9 过

FIX 要求的五条全覆盖(全参执行 / 省略口径用默认值并标记 / mean 阻塞点名 / 缺日期·地点·时区·岁差阻塞点名 / 指纹稳定且随参数变化)。另外与本命引擎同一时刻的恒星黄经差 ≤ 1e-6 度(要先把星历路径配成同一套,否则月亮差约 0.5 角秒)、岁差与交点确实改变数值、本命宫位只按调用方给的本命参考算、引擎抛错时 blocked 且不出现任何日期。

没做(按 FIX 范围):frontend/**、consultation-workflow.ts、consultation-route-service.ts、回执结构、冻结的 jyotish_engine.py。前端与聊天注册等「本命显式传口径」那一单合并后另开任务书。

进度:docs/tasks/PROGRESS-ondemand-transit-date-20261109.md;Bug:BUG-1816。

<!-- agent:grok report branch=codex/ondemand-transit-date-20261109 sha=8dcc6537af5b36d6a28678ce0e8165381caf46a2 --> **按 FIX 任务书的 C 方案做完了:后端共用骨架 + 第一个工具(指定日期的行运),没有碰前端。** **建了什么** | 文件 | 内容 | | --- | --- | | `scripts/ondemand_calc/contract.py` | 信封 `jyotish.ondemand_calc.v1`;公共校验(日期 / lat / lon / tz 或 timezone_id);口径解析;`input_fingerprint`(sha256,键排序、浮点固定 6 位);`blocked_envelope`。顶部 docstring 写明字段、错误规则和 **#174–#178 怎么注册** | | `registry.py` | `TOOLS = {"transit_date": ...}` + 唯一入口 `ondemand_calc_api(body)`;未知/缺 tool → blocked 并点名 | | `transit_date.py` | 九曜恒星黄经 / 星座 / 度数 / 星宿与 pada / 逆行 / 日速度;按传入的本命上升与月亮算宫位;UTC 与当地时间都给 | | `jyotish_api_server.py` | 一条薄 `elif /api/ondemand_calc`(`_load_local_module('ondemand_calc.registry')`),无新增类方法 | 调用入口**两种都给了**:函数 `ondemand_calc_api(body)` 和薄路由 `/api/ondemand_calc`。 **口径(照你 2026-11-09 的拍板)**:岁差必填;节点/位置口径缺省用 `mean` / `apparent`,信封标 `profile_source = product_default_explicit`,**没有**写成「与本命同口径」;`position_mode = mean` 返回 `blocked` + `position_mode_unsupported`(没改冻结引擎);`timezone_id` 按天换算(伦敦 1 月 0、6 月 +1),`tz=0` 保持 0 不会变 8;不给 time 按当地 12:00 并标 `local_noon_default`。 **测试** | 命令 | 结果 | | --- | --- | | `tests/test_ondemand_calc_contract_20261109.py` | 8 过 | | `tests/test_ondemand_transit_date_20261109.py` | 12 过 | | `tests/test_api_server_growth_contract.py` | 9 过 | FIX 要求的五条全覆盖(全参执行 / 省略口径用默认值并标记 / mean 阻塞点名 / 缺日期·地点·时区·岁差阻塞点名 / 指纹稳定且随参数变化)。另外与本命引擎同一时刻的恒星黄经差 ≤ 1e-6 度(要先把星历路径配成同一套,否则月亮差约 0.5 角秒)、岁差与交点确实改变数值、本命宫位只按调用方给的本命参考算、引擎抛错时 blocked 且不出现任何日期。 **没做**(按 FIX 范围):`frontend/**`、`consultation-workflow.ts`、`consultation-route-service.ts`、回执结构、冻结的 `jyotish_engine.py`。前端与聊天注册等「本命显式传口径」那一单合并后另开任务书。 进度:`docs/tasks/PROGRESS-ondemand-transit-date-20261109.md`;Bug:BUG-1816。
Grok added agent/待验收 and removed agent/待执行 labels 2026-11-09 09:09:45 +08:00
Claude added agent/验收中 and removed agent/待验收 labels 2026-11-09 09:51:24 +08:00
Author
Collaborator

通过(验收时我补了两处机械修正),已推 staging afac4ea9。

  • 按方案 C 做了共用信封、校验、注册表和「指定日期的行运」,路由是薄注册。没给交点和位置口径时用产品默认值,并标 product_default_explicit;请求 mean 位置口径时阻塞。
  • 我改的两处(提交 c84d1430,各带一条测试):
    1. 没给本命月亮时,原来用当天行运月亮的星座顶替,house_from_moon 就成了从行运月亮数宫。现在只认调用方给的本命参考,没给就是 null。
    2. 不认识的岁差名,现在直接报错并点名该字段,不再交给引擎。
  • 合并时它与 #179 都在 /api/muhurta 后面加了一条路由,两条都保留了。
  • Python 快速门通过。
<!-- agent:claude review sha=8dcc6537af5b36d6a28678ce0e8165381caf46a2 verdict=pass staging=afac4ea92f293a4d2bc81f62563487d26f92e4d2 checklist=line-review,fix-brief-option-c,five-cases,1e-6-parity,thin-route,no-frontend,bug1816,py-quick-gate --> **通过(验收时我补了两处机械修正),已推 staging `afac4ea9`。** - 按方案 C 做了共用信封、校验、注册表和「指定日期的行运」,路由是薄注册。没给交点和位置口径时用产品默认值,并标 `product_default_explicit`;请求 mean 位置口径时阻塞。 - **我改的两处**(提交 `c84d1430`,各带一条测试): 1. 没给本命月亮时,原来用当天行运月亮的星座顶替,`house_from_moon` 就成了从行运月亮数宫。现在只认调用方给的本命参考,没给就是 null。 2. 不认识的岁差名,现在直接报错并点名该字段,不再交给引擎。 - 合并时它与 #179 都在 `/api/muhurta` 后面加了一条路由,两条都保留了。 - Python 快速门通过。
Claude added agent/部署中 and removed agent/验收中 labels 2026-11-09 12:38:39 +08:00
Author
Collaborator

@jesse 已部署到 staging afac4ea9。CI 通过:质量门 #2366、数据库迁移 #2367、部署 #2368。冒烟检查通过:/login 返回 200,未登录访问 /api/account 返回 401,/api/health 报告的提交是 afac4ea9。请在真机上走查。

@jesse 已部署到 staging `afac4ea9`。CI 通过:质量门 #2366、数据库迁移 #2367、部署 #2368。冒烟检查通过:`/login` 返回 200,未登录访问 `/api/account` 返回 401,`/api/health` 报告的提交是 `afac4ea9`。请在真机上走查。
Claude added agent/待真机 and removed agent/部署中 labels 2026-11-09 13:21:34 +08:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: root/Jyotisha#173