Merge remote-tracking branch 'origin/staging' into codex/login-rectify-loading-1103
Independent Staging Quality Gate / validate-python (push) Successful in 6m35s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m35s
Independent Staging Quality Gate / publish (push) Successful in 2m51s

# Conflicts:
#	docs/BUG_HISTORY.md
This commit is contained in:
2026-11-04 15:48:14 +08:00
22 changed files with 44997 additions and 149 deletions
+4
View File
@@ -1,5 +1,9 @@
# 印度占星 Skill 更新日志
## 2026-11-04 — Shadbala:月亮的盈亏力不再重复计入
- 六力里月亮的盈亏力(Paksha)以前被算了四倍(时力里乘 2,动力又取乘 2 后的值),现按 BPHS(Santhanam 译本)27.10–11 + 27.18:时力里不乘 2,动力等于盈亏力,合计两倍。月亮的六力总分、Ishta / Kashta 和「最强星」可能变化(例:奥巴马公开盘最强星由月亮变为太阳),其他六颗星不变;结果里 `method_variants.moon_paksha` 写明口径(BUG-1557)。生时校正结果不变。Skill 版本不变;没有数据库变更。
## 2026-11-04 — 对话数据卡:每个领域宫位带上 Ashtakavarga 强 / 中 / 弱
- 对话回答读的数据卡里,每个领域列出的宫位(如父母的 4、9 宫,婚恋的 5、7 宫,事业的 10 宫)多一项 `sav_strength`:该宫星座的原始 SAV 写成「强 / 中 / 弱」,不写点数。分档与星盘页一致:≥ 28 强、25–27 中、≤ 24 弱(来源 `references/ashtakavarga-complete-system.md` §三,与引擎 `scripts/ashtakavarga.py` 同界)。以前这项只能靠模型额外查,回测里 233 份回答只查了 2 次。
+18 -2
View File
@@ -21283,7 +21283,7 @@
- 根因:`phase = abs(Sun - Moon) / 3` 没有折回。Raman《Graha and Bhava Balas》:月日之差超过 180° 时用 360° 去减,余数除以 3 为吉星的 Paksha,凶星为 60 减之,月亮加倍。PyJHora 4.8.6 `_paksha_bala` 有同样写法,所以与 PyJHora 对照时这一项一直「一致」。
- 修复:`paksha_phase` 先折回 0–180° 再除以 3。
- 验证:`tests/test_shadbala_paksha_fold.py`(折回、对称、满月 60、原始差 340° 的盘木星 Paksha 恰为 6.67——旧公式为 113.33);Shadbala 相关测试改前改后失败清单一致(10 条既有失败均为 oracle / 审计研究测试,如「已验证案例 ≥ 4」实为 2,与本单无关)。
- 同轮核对结论(不改代码):Kala 里某一颗星差 ±60 是 PyJHora 时主公式错(星期一日出第一时主给成火星);金星、火星、木星 Chesta 大差中 PyJHora 是离群值(乔布斯盘火星:本仓 21.6、VedAstro 21.7、jyotishganit 22.9、PyJHora 98.6);太阳、月亮 Chesta 取 Ayana / Paksha 是 Raman 口径,VedAstro、PyJHora 给 0,属流派差。亏月(满月到新月)按凶星取「60 减」使近新月的月亮 Paksha 接近满分;占星师 2026-11-04 回复:外部实现也有此口径(如 saravali.github.io bala_kala),不是公式错误,不把月亮在各模块统一改成吉星;若产品要采用「月亮盈亏力随亮度增减」(满月 60、新月 0、上下弦同夹角等值),只能单独改月亮的 Paksha,并绑定具名来源与计算版本(月亮是否乘 2、与 Chesta 如何配合随同一算法),不得无差别修补。当前首要问题是两条计算路径口径不一致,见 BUG-1548。四家引擎 Sthana、Dig、Drik 也普遍不一致(`three_engine_parity_replay_manifest.json` 已记 `blocked_cross_engine_method_conflict`),Shadbala 绝对值暂不作数据卡上的强弱依据。
- 同轮核对结论(不改代码):Kala 里某一颗星差 ±60 是 PyJHora 时主公式错(星期一日出第一时主给成火星);金星、火星、木星 Chesta 大差中 PyJHora 是离群值(乔布斯盘火星:本仓 21.6、VedAstro 21.7、jyotishganit 22.9、PyJHora 98.6);太阳、月亮 Chesta 取 Ayana / Paksha,VedAstro、PyJHora 给 0,属流派差(更正,见 BUG-1557:原写「是 Raman 口径」不准确。Raman《Graha and Bhava Balas》例 56 的 Shadbala 总分里太阳、月亮没有 Chesta;「月亮 Chesta = Paksha」出自 BPHS 27.18)。亏月(满月到新月)按凶星取「60 减」使近新月的月亮 Paksha 接近满分;占星师 2026-11-04 回复:外部实现也有此口径(如 saravali.github.io bala_kala),不是公式错误,不把月亮在各模块统一改成吉星;若产品要采用「月亮盈亏力随亮度增减」(满月 60、新月 0、上下弦同夹角等值),只能单独改月亮的 Paksha,并绑定具名来源与计算版本(月亮是否乘 2、与 Chesta 如何配合随同一算法),不得无差别修补。当前首要问题是两条计算路径口径不一致,见 BUG-1548。四家引擎 Sthana、Dig、Drik 也普遍不一致(`three_engine_parity_replay_manifest.json` 已记 `blocked_cross_engine_method_conflict`),Shadbala 绝对值暂不作数据卡上的强弱依据。
- 防复发:回归测试;对照时「两家一致」不等于正确,盈亏力这类两家同源写法要对照原书。
- 关联记录:BUG-1188、BUG-1189、BUG-1270。
- 复发自:无
@@ -21335,7 +21335,23 @@
- 复发自:无
- 修复版本:分支 `codex/vimshottari-second-cycle-20261104`(未推送)。
## BUG-1557 | 咨询回答一上来叫用户名字;关键结论和依据没有任何强调;用户要「三条习惯」时写成一段「一是……二是……三是……」
## BUG-1557 | Shadbala 月亮盈亏力(Paksha)计入四倍:Kala 里乘 2,Chesta 又取乘 2 后的值
- 状态:resolved(引擎 + 回归测试;未部署)
- 首次发现 / 最近更新:2026-11-04(BUG-1546 之后的 Paksha 口径研究:逐一对照 BPHS 梵文与 Santhanam 英译、Raman GBB、PVR、PyJHora、VedAstro、jyotishganit、saravali、Maitreya8、jyotishyamitra)/ 2026-11-04
- 影响面:`scripts/shadbala.py` 精确路径 `calc_kala_bala_precise` 的月亮 paksha,连带 `calc_chesta_bala_precise` 的月亮 Chesta、月亮 Ishta / Kashta、Kala 与 Shadbala 总分、排名和「最强星」。凡走精确路径的都受影响:`cmd_shadbala`、全读、报告、星盘页六力表与 remedies(BUG-1548 以后同一路径)、Shadbala 服务接口。其他六颗星不变;`classify_drik_planets`(Drik 分类)不变;旧的简化路径 `calc_kala_bala` / `calc_chesta_bala` 未动(只有生时校正调用,只取 Sthana / Drik / Naisargika)。
- 现象:乔布斯公开盘月亮 Kala·paksha 21.34、Chesta 21.34;奥巴马公开盘月亮 Chesta 73.88(超过 60),Ishta 64.99(超过 60),Kashta 被截成 0。月亮来自盈亏力的总分是基数 P 的 4 倍。
- 触发条件:任何一张盘走精确路径。
- 根因:精确路径同时用了两家互斥的写法——Raman《Graha and Bhava Balas》§55(c)「Chandra's Paksha Bala is always to be doubled」(例 56 的总分里月亮 Chesta 为空),和 BPHS 27.18「Candr's Paksh Bal will itself be her Chesht Bal」(27.10–11 不乘 2);而且 Chesta 拿的是已经乘 2 的值。调查的所有来源里月亮盈亏力在总分中都是 2P,只有本仓是 4P。BUG-1546 和代码注释说「月亮 Chesta 取 Paksha 是 Raman 口径」,不准确(已在 BUG-1546 更正)。
- 修复:产品 2026-11-04 采用候选 B「BPHS-Santhanam 27.10–11 + 27.18」(与占星师引用的 saravali.github.io、Maitreya8 默认设置、jyotishyamitra 同口径)。月亮 Paksha = P,基数为折回角 min(Δ, 360 − Δ) / 3,不乘 2;上弦(盈)月按吉星取 P,下弦(亏)月按凶星取 60 − P——`classify_drik_planets` 本来就按 Δ ≤ 180° 归吉、否则归凶,与 BPHS 3.11(Santhanam:decreasing Candr 为凶)一致,未改;月亮 Chesta = Paksha(BPHS 27.18),总分里共 2P。`calc_shadbala` 的 `method_variants` 新增 `moon_paksha: "bphs_santhanam_27_10_11_chesta_27_18"`(常量 `MOON_PAKSHA_CONVENTION`,注释写出处);简化路径为 `legacy_approximation`。
- 验证:`tests/test_shadbala_moon_paksha_convention.py`(乔布斯、梦露、奥巴马三张公开盘:月亮 Paksha = P 不是 2P、Chesta = Paksha、Chesta / Ishta / Kashta 都在 0–60、吉凶侧与 BPHS 3.11 一致、方法标签;乔布斯 Paksha 10.67、总分 638.06;奥巴马 Kashta 不再为 0;其他六星 Paksha 不变)。按「原值 / 新值 / 原因」更新:`test_shadbala_precise_context.py`(月亮 Kala 对存档 PyJHora 的差 52.17 → 41.51,PyJHora 仍乘 2;月亮 Chesta = 10.66)、`test_shadbala_paksha_fold.py`(月亮上限 120 → 60)、`test_shadbala_service_api.py`(method_variants 加 moon_paksha)、`test_vp_jain_shadbala_benchmark.py`(容差内 36 → 35、方法差 6 → 7:月亮 Kala 205.96 → 151.58,公布值 205.85 按 Raman 乘 2;月亮 Chesta 108.76 → 54.38,公布值 0;两项合计 205.96 对 205.85 + 0,仍差 0.11,新增方法差标签 `moon_paksha_convention`)。三张公开盘月亮总分(Raman 岁差,平均交点):乔布斯 10.99 → 10.63 Rupa(仍最强)、梦露 9.04 → 8.28(仍第 2)、奥巴马 10.14 → 8.91(第 1 → 第 2,最强星由月亮变太阳)。Shadbala 相关 123 个测试文件改前改后失败清单一致(22 条既有失败,其中 `test_shadbala_*` 10 条,均为 oracle / 审计研究测试)。
- 冻结身份(ERR-110):`shadbala.py` 在生时校正冻结身份里。按 ERR-110 改 FREEZE / REPORT 常量后用各脚本 `--freeze` 新建记录并回放,标签 `moon_paksha_2026_11_04`(`docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.{freeze.json,json}`、`docs/research/reported_offset_moon_paksha_2026_11_04.{freeze.json,json}`),合同 `references/rectification_sealed_holdout.v1.json` 按 11-04 data_audit 先例轮换,旧记录逐字节保留。与 `data_audit_2026_11_04` 逐条逐字段比:密封 20 条全部相同、`metrics` 不变;报时窗口 900 条全部相同、`summary` 不变;相对 09-20 历史报告的 changed_trial_count 仍为 8 / 581。符合预期:校正打分只读 Sthana / Drik / Naisargika,不读 Kala / Chesta,Drik 分类未动。
- 防复发:回归测试锁「月亮 Chesta = Paksha、Paksha 不乘 2、Ishta / Kashta 在 0–60」;口径用具名常量绑定并写进结果的 `method_variants`;对照外部引擎时按分量拆开比,Kala 与 Chesta 分别对上不等于总分口径一致。
- 关联记录:BUG-1546(折回;本条更正其「Raman 口径」一句)、BUG-1548(星盘页与解读同一路径)。
- 复发自:无
- 修复版本:分支 `codex/moon-paksha-bphs-20261104`(未推送)。
## BUG-1558 | 咨询回答一上来叫用户名字;关键结论和依据没有任何强调;用户要「三条习惯」时写成一段「一是……二是……三是……」
- 状态:investigating(提示词 + 样式 + 合同测试;待 staging 真机同题对照,本机无模型密钥与排盘引擎,未跑回测)
- 首次发现 / 最近更新:2026-11-04(产品负责人拿竞品同题「借贷 + 2/11/12 宫 + 三条理财习惯」对照反馈)/ 2026-11-04
+1
View File
@@ -17,6 +17,7 @@ Purpose: read this file before substantial project work. It exists to stop repea
- BUG-1545 / BUG-1546 改了冻结身份里的 `narayana_dasha.py`、`active_rectification_event_engine.py`、`shadbala.py`,合入上游同步 10 后快速门 `test_rectification_validation_integrity_gate` 4 条红(ERR-110 同型)。按 ERR-110 重冻为 `data_audit_2026_11_04`:密封 20 条与 `d60_mapping_2026_10_29` 全同;报时 900 条 2 条 `true_rank` 变(Narayana 第二轮,同一例半径 60),`summary` 不变。教训:「只影响第一轮之后的年龄」不等于回放不变,重冻后一律逐条比,有变化照实写。
- BUG-1556(worktree `/workspace/wt-vim`,分支 `codex/vimshottari-second-cycle-20261104`):Vimshottari 过 120 年变空已修,改在冻结身份之外(`chart_dasha/birth_moment.py` 的 `next_cycle_mahadashas`,`cmd_dasha` 与星盘 / 咨询共用),`dasha_analyzer.py`、`domain_calculation_service.py` 未动,无需重冻。`pre_work_check.py` exit 0;Python quick 门一次通过。注意:`_compute_chart_sync` 里 Vimshottari 算了两次,后一次(原 `utcnow()`)才是返回的 `dasha`,改参照日要两处都改;`test_chart_dasha_birth_moment_20261028.py` 里有 1879 年等老盘,以前只因两边都只排一轮才相等。
- 数据卡宫行加 Ashtakavarga 强 / 中 / 弱(worktree `/workspace/wt-card-av`,`codex/card-ashtakavarga-20261104`):`pre_work_check.py` 第一次 exit 1(`fragment_scan` 90 s、`focused_tests` 45 s 超时,当时同机在建 worktree、跑卡片导出),机器空下来重跑 pass、六项全部 ok。分档沿用星盘页 `savBand`(≥ 28 强、25–27 中、≤ 24 弱),来源写在 `SAV_BAND_SOURCE`。注意:事业卡的 `sav_by_house`、财富 / 综合卡的 `ashtakavarga` 块本来就把原始与净化后的 SAV 点数给了模型,本单没动。
- BUG-1557 月亮 Paksha 口径(worktree `/workspace/wt-moon`,`codex/moon-paksha-bphs-20261104`):`pre_work_check.py` exit 0、六项全部 ok。精确路径 Kala 里月亮 ×2(Raman)加 Chesta = Paksha(BPHS 27.18)同时用、Chesta 又取 ×2 后的值,总分 4P;改为 BPHS-Santhanam(不乘 2,Chesta = Paksha),`method_variants.moon_paksha` 标口径。`shadbala.py` 在冻结身份里,按 ERR-110 重冻为 `moon_paksha_2026_11_04`:密封 20 条、报时 900 条与 `data_audit_2026_11_04` 全同。教训:两家来源各自「×2」「Chesta = Paksha」都对,拼在一起就错;引进一条古典规则时先看同一来源怎么处理相邻分量。Shadbala 相关测试改前改后失败清单一致(同上 10 条 + 其他既有 12 条);Python quick 门一次通过。
## 2026-11-03 · 输入框单行起步(方案 2,worktree `/workspace/wt-composer`)
@@ -0,0 +1,118 @@
{
"record_version": "reported-offset-native-candidate-date-v3",
"frozen_at_utc": "2026-11-04T07:22:52.617248+00:00",
"ayanamsa": "raman",
"node_mode": "mean",
"radii_minutes": [
15,
30,
60
],
"offsets_minutes": [
-30,
-20,
-15,
-10,
-8,
-5,
-3,
0,
3,
5,
8,
10,
15,
20,
30
],
"minute_step": 1,
"dataset": "references/real_case_calibration/minute_rectification_holdout_v3.json",
"dataset_sha256": "45aa76ab79dfc6c6404b6252083e1aa5c7e2e2b7de811fc11042a8ad2da3f0ea",
"dataset_benchmark_id": "minute_rectification_fact_ranker_v4_holdout_v3",
"implementation_sha256": "19ce36a9938928f345928fc44792eb70e6b71945aa5ab2a08a942b214cf0b085",
"implementation_sha256_prefix": "19ce36a9938928f3",
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "9857465d8305d0ccdcedff12c4c0bc572d4a12eea7e348fa4fc1b38e4f244fcf",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "8747a78a8b7a3fee0542423978adab11cee3e98880065ce13ef243f9488e5de9",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "dced0b398ad90bdec59c743a55ffe01613306127c17a1e44c8c9cfb569c57841",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "9a847d3b8d05f90d4f275079c97af1f71e83a74f930e14bd8f3f37b293d91d1e",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "1c7183e77f442b8c6b46761ff8a833b6c27b7841999426c72556237f45df1343",
"scripts/research/sealed_holdout_rerun.py": "957b824b7579c4f52681c85d7964fc802f8179470c93917cded63c7fe6c2769d",
"scripts/shadbala.py": "352a9dd91c9be6dd7a294b1dc24c62173e8f08db5fc36c453dc5dcd7e0fd62d7",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock",
"scorer": "native_event_contribution_matrix_not_shadow_fact_ranker",
"delivery": "initial_signature_clusters_peak_gap_lt_8_envelope_no_answers_no_elimination",
"rank": "score_desc_then_sha256(benchmark_id:case_id:candidate_time)",
"grid": "every_minute_inclusive_not_production_two_minute_sampling",
"cross_midnight": "date_aware_candidates_distance_and_native_single_matrix",
"evaluator_sha256": "1c7183e77f442b8c6b46761ff8a833b6c27b7841999426c72556237f45df1343",
"replay_revision": "native_candidate_date_v3",
"supersedes": "candidate_date_grouped_v2_identity_and_path_not_assumed_numerically_wrong",
"is_blind_evaluation": false,
"truth_hidden_from_ranker": true,
"official_valid_independent_blind": false,
"official_blind_trial_count": 0,
"results_previously_seen": true,
"must_not_use_for_tuning": true
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,116 @@
{
"record_version": "exposed-v3-fixed-protocol-cross-midnight-rerun-v2",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "9857465d8305d0ccdcedff12c4c0bc572d4a12eea7e348fa4fc1b38e4f244fcf",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "8747a78a8b7a3fee0542423978adab11cee3e98880065ce13ef243f9488e5de9",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "dced0b398ad90bdec59c743a55ffe01613306127c17a1e44c8c9cfb569c57841",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "9a847d3b8d05f90d4f275079c97af1f71e83a74f930e14bd8f3f37b293d91d1e",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "1c7183e77f442b8c6b46761ff8a833b6c27b7841999426c72556237f45df1343",
"scripts/research/sealed_holdout_rerun.py": "957b824b7579c4f52681c85d7964fc802f8179470c93917cded63c7fe6c2769d",
"scripts/shadbala.py": "352a9dd91c9be6dd7a294b1dc24c62173e8f08db5fc36c453dc5dcd7e0fd62d7",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"production_identity_scope": "context_only_shadow_scorer_does_not_call_transition_proximity",
"frozen_at_utc": "2026-11-04T07:22:50.077499+00:00",
"dataset_path": "references/real_case_calibration/minute_rectification_holdout_v3.json",
"dataset_sha256": "45aa76ab79dfc6c6404b6252083e1aa5c7e2e2b7de811fc11042a8ad2da3f0ea",
"algorithm_version": "birth-time-event-fact-ranker-v4-shadow",
"implementation_sha256": "19ce36a9938928f345928fc44792eb70e6b71945aa5ab2a08a942b214cf0b085",
"files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"historical_frozen_sha256": "f41c298dd6cdcebe7a93e632f7191954be7987f6012ca2a34cecb6e447fbf196",
"evaluator_sha256": "957b824b7579c4f52681c85d7964fc802f8179470c93917cded63c7fe6c2769d",
"ayanamsa": "raman",
"node_mode": "mean",
"candidate_radius_minutes": [
10
],
"minute_step": 1,
"release_metrics": {
"top_1_rate_minimum": 0.6,
"top_3_rate_minimum": 0.85,
"mean_absolute_minute_error_maximum": 2.0,
"false_confirmation_rate_maximum": 0.05,
"correct_insufficient_evidence_rejection_rate_minimum": 0.9
},
"results_previously_seen": true,
"official_valid_independent_blind": false,
"must_not_use_for_tuning": true,
"tie_breaker": "sha256(benchmark_id:case_id:candidate_time); published minute is never passed to the ranker",
"metric_rank_definition": "competition_rank_1_plus_strictly_higher_scores_legacy_protocol",
"extra_metric_rank_definition": "score_desc_then_existing_opaque_sha256_total_order"
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1763,7 +1763,7 @@ button.chat-chart-resize-handle:active { position: absolute; top: 0; left: -3px;
.message-markdown h2, .message-markdown h3 { margin: 24px 0 10px; color: var(--color-ink); font-family: var(--font-display); font-weight: 500; letter-spacing: -.3px; }
.message-markdown h2 { font-size: var(--type-display-sm); }
.message-markdown h3 { font-size: var(--type-title-lg); }
/* BUG-1557: 600, not 500 — at 500 the emphasis the answer now carries barely stood off the body. */
/* BUG-1558: 600, not 500 — at 500 the emphasis the answer now carries barely stood off the body. */
.message-markdown strong { color: var(--color-ink); font-weight: 600; }
.message-markdown a { text-underline-offset: 3px; color: var(--color-action); }
.message-markdown code { padding: 2px 5px; font-size: .9em; border-radius: var(--radius-xs); background: var(--color-canvas-muted); font-family: var(--font-mono); }
@@ -4,7 +4,7 @@ import test from "node:test";
import { productConversationVoice } from "../src/mastra/product-voice.ts";
// BUG-1557: answers opened with the user's name, had no emphasis, and wrote
// BUG-1558: answers opened with the user's name, had no emphasis, and wrote
// three asked-for habits inline as 一是……二是……三是…….
test("the answer never addresses the user by name", () => {
@@ -179,7 +179,7 @@ test("natal spoken answers default to paragraphs, not bold-label lists (BUG-1244
assert.match(productConversationVoice, /写成段落,段落之间空一行/);
// 原值(3): /有三个以上候选时间窗时才用列表/
// 新值(3): 用户要几条或有三个以上候选时间窗时用列表,每条带「为什么适合你」
// 原因(3): BUG-1557 产品对照竞品:用户说「给三条」时我们写成了一段「一是……二是……三是……」
// 原因(3): BUG-1558 产品对照竞品:用户说「给三条」时我们写成了一段「一是……二是……三是……」
assert.match(productConversationVoice, /用户要几条(「给三条」)、或有三个以上候选时间窗时用列表,每条先一句做法、再一句为什么适合你/);
assert.match(consultationSpokenHeadingRule("daily"), /Markdown bullet lists/);
assert.doesNotMatch(consultationSpokenHeadingRule("window"), /start with ## /);
@@ -120,8 +120,11 @@ const diagnosticReport = JSON.parse(readFileSync(
// 原值(13):docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json
// 新值(13):docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json
// 原因(13):数据核对 BUG-1545(narayana_dasha.py、active_rectification_event_engine.py)与 BUG-1546(shadbala.py)改了冻结身份文件,20 条回放不变,ERR-110 另存新记录。确认门行为与阈值不变。
// 原值(14):docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json
// 新值(14):docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.json
// 原因(14):BUG-1557 月亮 Paksha 口径改了冻结身份里的 shadbala.py,20 条回放不变,ERR-110 另存新记录。确认门行为与阈值不变。
const currentTreeRerun = JSON.parse(readFileSync(
new URL("../../docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json", import.meta.url),
new URL("../../docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.json", import.meta.url),
"utf8",
)) as {
frozen_record: { implementation_sha256: string };
@@ -272,9 +275,10 @@ test("sealed holdout aggregates match the v3 report and still block confirmation
// 原值(10):…upstream_sync8_2026_10_18.json / 新值(10):…upstream_sync9b_2026_10_28.json / 原因(10):sync9b 改了冻结身份里的 varga.py,输出不变,ERR-110 另存新记录。
// 原值(11):…upstream_sync9b_2026_10_28.json / 新值(11):…d60_mapping_2026_10_29.json / 原因(11):BUG-1500 修正 D60 映射,输出不变,ERR-110 另存新记录。
// 原值(12):…d60_mapping_2026_10_29.json / 新值(12):…data_audit_2026_11_04.json / 原因(12):BUG-1545 / BUG-1546 改了冻结身份文件,输出不变,ERR-110 另存新记录。
// 原值(13):…data_audit_2026_11_04.json / 新值(13):…moon_paksha_2026_11_04.json / 原因(13):BUG-1557 改了冻结身份里的 shadbala.py,输出不变,ERR-110 另存新记录。
assert.equal(
productHoldout.current_tree_scorer.source_report,
"docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json",
"docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.json",
);
assert.equal(currentTreeRerun.official_valid_independent_blind, false);
assert.equal(productHoldout.current_tree_scorer.matches_metrics_scorer, false);
+129 -129
View File
@@ -24,7 +24,7 @@
"evaluated_on": "2026-07-21"
},
"current_tree_scorer": {
"implementation_sha256": "1de938b696d9e9639f4f401a83c3c51e231f279784335869471237b0f9101d7a",
"implementation_sha256": "19ce36a9938928f345928fc44792eb70e6b71945aa5ab2a08a942b214cf0b085",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
@@ -52,7 +52,7 @@
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "975b5755ea8ba7037baf1510015fcc57e64f0620ac866ff076685d317c6f5731",
"production_scoring_sha256": "9857465d8305d0ccdcedff12c4c0bc572d4a12eea7e348fa4fc1b38e4f244fcf",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
@@ -62,7 +62,7 @@
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "e752fb86c6462b2d316902cba1e11fb55a630fe8abc43f871b53aa58a62422ed",
"research_implementation_sha256": "8747a78a8b7a3fee0542423978adab11cee3e98880065ce13ef243f9488e5de9",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "dced0b398ad90bdec59c743a55ffe01613306127c17a1e44c8c9cfb569c57841",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
@@ -90,9 +90,9 @@
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "dfea4cd09d425fbe78b8b8e5de82eab4baaea41c1cd21ea470710e1dc5e405cd",
"scripts/research/sealed_holdout_rerun.py": "cbc1ec1fdf8e22c30df1d8bd9497b0b6274cc7d383b24fefbe432972746fac90",
"scripts/shadbala.py": "658f94eaef5ad5826d10c11b58cf1a2c95e502befaea095ce3f1079d6c2f0dec",
"scripts/research/reported_offset_sweep.py": "1c7183e77f442b8c6b46761ff8a833b6c27b7841999426c72556237f45df1343",
"scripts/research/sealed_holdout_rerun.py": "957b824b7579c4f52681c85d7964fc802f8179470c93917cded63c7fe6c2769d",
"scripts/shadbala.py": "352a9dd91c9be6dd7a294b1dc24c62173e8f08db5fc36c453dc5dcd7e0fd62d7",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
@@ -100,7 +100,7 @@
"matches_metrics_scorer": false,
"official_eval_implementation_hash_matches": false,
"official_eval_trial_count": 0,
"source_report": "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json",
"source_report": "docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.json",
"fixed_protocol_rerun_trial_count": 20,
"fixed_protocol_rerun_hash_matches": true,
"metrics": {
@@ -113,6 +113,106 @@
}
},
"current_tree_fixed_protocol_rerun": {
"evaluated_on": "2026-11-04",
"report_path": "docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.freeze.json",
"implementation_sha256": "19ce36a9938928f345928fc44792eb70e6b71945aa5ab2a08a942b214cf0b085",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "9857465d8305d0ccdcedff12c4c0bc572d4a12eea7e348fa4fc1b38e4f244fcf",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "8747a78a8b7a3fee0542423978adab11cee3e98880065ce13ef243f9488e5de9",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "dced0b398ad90bdec59c743a55ffe01613306127c17a1e44c8c9cfb569c57841",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "9a847d3b8d05f90d4f275079c97af1f71e83a74f930e14bd8f3f37b293d91d1e",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "1c7183e77f442b8c6b46761ff8a833b6c27b7841999426c72556237f45df1343",
"scripts/research/sealed_holdout_rerun.py": "957b824b7579c4f52681c85d7964fc802f8179470c93917cded63c7fe6c2769d",
"scripts/shadbala.py": "352a9dd91c9be6dd7a294b1dc24c62173e8f08db5fc36c453dc5dcd7e0fd62d7",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"scorer_frozen_before_rerun": true,
"source_audit_status": "corrected_known_date_errors",
"trial_count": 20,
"official_valid_independent_blind": false,
"is_blind_evaluation": false,
"truth_hidden_from_ranker": true,
"results_previously_seen": true,
"must_not_claim_as_release_metrics": true,
"must_not_use_for_tuning": true,
"verified_minute_claim_allowed": false,
"metric_gates_passed": false,
"events_per_case": 3,
"boundary": "Previously exposed v3 shadow fixed-protocol rerun after the Moon Paksha convention fix (ERR-110, BUG-1557). Trials and metrics match the 2026-11-04 data_audit report on every field. Versus the 2026-09-20 historical report, changed_trial_count stays 8. Not a release metric. Prior reports and freezes preserved byte-for-byte.",
"report_sha256": "0dabbef823a65b089574d90bac6af3f903712684c8fd88b42cf424b650f3b532",
"freeze_record_sha256": "ad125812c8472048e012c8dbb3b7090bb3b94f2fff44ef8f3846a7d5a8f976c0",
"replay_started_at_utc": "2026-11-04T07:22:50.170060+00:00",
"replay_finished_at_utc": "2026-11-04T07:22:52.478378+00:00",
"previous_fixed_protocol_rerun": {
"report_path": "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.freeze.json",
"superseded_reason": "BUG-1557 (scripts/shadbala.py: the Moon's Paksha is no longer doubled; convention bphs_santhanam_27_10_11_chesta_27_18) changed a frozen identity file. Output is unchanged. Rectification scoring reads only Sthana, Drik and Naisargika, so ERR-110 stored a new record. Prior data_audit report and freeze preserved byte-for-byte."
}
},
"previous_fixed_protocol_rerun": {
"evaluated_on": "2026-11-04",
"report_path": "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.freeze.json",
@@ -212,106 +312,6 @@
"superseded_reason": "The data-audit fixes BUG-1545 (scripts/narayana_dasha.py, scripts/active_rectification_event_engine.py) and BUG-1546 (scripts/shadbala.py) changed frozen identity files. Output is unchanged, so ERR-110 stored a new record. Prior d60_mapping report and freeze preserved byte-for-byte."
}
},
"previous_fixed_protocol_rerun": {
"evaluated_on": "2026-10-29",
"report_path": "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.freeze.json",
"implementation_sha256": "4bb731f7b5043de0b967ccd7e852ae25a1ecdce96c2b7987c142d7878b6632b2",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "fcf10cb3a5742bb7e2d98d15d69638769cd830f470373ea93745a1cab3718c9b",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "4eb2c03b09a179dd81f912d735823dd09ec8506da2538f40d3a8e04d3ebc6c67",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "96c537d221a84680ddaaba74e3335162c44b5bbd9a60d10e69550a2095910d98",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "bc667c30c9562fb73fb0b7b4c22a5e377f9a531795141fc629b2cd3cf396773a",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "cabc96d1f8c7ed06ef34da4e02e052f598a5e62fd71a7ccbe7b0b099247c27d0",
"scripts/research/sealed_holdout_rerun.py": "69a7ddddfc4a88ec5c85f400c763f8cdbb3c58c00fe9e788a72f79daba1d3bc1",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"scorer_frozen_before_rerun": true,
"source_audit_status": "corrected_known_date_errors",
"trial_count": 20,
"official_valid_independent_blind": false,
"is_blind_evaluation": false,
"truth_hidden_from_ranker": true,
"results_previously_seen": true,
"must_not_claim_as_release_metrics": true,
"must_not_use_for_tuning": true,
"verified_minute_claim_allowed": false,
"metric_gates_passed": false,
"events_per_case": 3,
"boundary": "Previously exposed v3 shadow fixed-protocol rerun after the D60 mapping fix (ERR-110, BUG-1500). Trials and metrics match the 2026-10-18 upstream sync8 and the upstream_sync9b reports. Versus the 2026-09-20 historical report, changed_trial_count stays 8. Not a release metric. Prior reports and freezes preserved byte-for-byte.",
"report_sha256": "9e667c4e5819674e82519bfe9415d49a202515c765ea99609a9dd27feb69c77d",
"freeze_record_sha256": "8f300876eca9aac683879f1b26204be885c03b2c7b6d03e5930386852cbe4700",
"replay_started_at_utc": "2026-10-29T06:07:59.312582+00:00",
"replay_finished_at_utc": "2026-10-29T06:08:15.756678+00:00",
"previous_fixed_protocol_rerun": {
"report_path": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.freeze.json",
"superseded_reason": "The D60 mapping fix (BUG-1500) changed scripts/varga.py, which is part of the extended identity. Output is unchanged, so ERR-110 stored a new record. Prior upstream_sync9b report and freeze preserved byte-for-byte."
}
},
"current_tree_unfrozen_diagnostic": {
"is_blind_evaluation": false,
"results_already_seen": true,
@@ -330,6 +330,28 @@
"verified_minute_claim_allowed": false
},
"current_tree_reported_offset_replay": {
"report_path": "docs/research/reported_offset_moon_paksha_2026_11_04.json",
"report_sha256": "f0b602a0477d5913d4befcdf888f3687062c3e62e0b11e6ea3bc69303f0f02cb",
"freeze_record_path": "docs/research/reported_offset_moon_paksha_2026_11_04.freeze.json",
"freeze_record_sha256": "9728da404c736a85179dfbbd62ac551550ff8590494f4da62df874cac5ffbd49",
"scope": "reported_offset_sensitivity_not_product_accuracy",
"trial_count": 900,
"official_valid_independent_blind": false,
"official_blind_trial_count": 0,
"must_not_use_for_tuning": true,
"must_not_claim_as_release_metrics": true,
"replay_started_at_utc": "2026-11-04T07:22:52.718578+00:00",
"replay_finished_at_utc": "2026-11-04T07:25:28.356370+00:00",
"boundary": "Previously exposed reported-offset sensitivity after the Moon Paksha convention fix (ERR-110, BUG-1557). Summary and all 900 trials match the 2026-11-04 data_audit report on every field. Versus the 2026-09-20 historical report, changed_trial_count stays 581 of 900. Not a release metric. No tuning. Prior reports and freezes preserved byte-for-byte.",
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_data_audit_2026_11_04.json",
"report_sha256": "227498db6488da6f4841c14ea063abcd3b788a069f8e61bb3c384b8bcee55f94",
"freeze_record_path": "docs/research/reported_offset_data_audit_2026_11_04.freeze.json",
"freeze_record_sha256": "389995d59467aac0270c1395200126c9065340c8177362566bd816f8c4ef9321",
"superseded_reason": "BUG-1557 (scripts/shadbala.py: the Moon's Paksha is no longer doubled; convention bphs_santhanam_27_10_11_chesta_27_18) changed a frozen identity file. Summary and all 900 trials are unchanged. Rectification scoring reads only Sthana, Drik and Naisargika, so ERR-110 stored a new record. Prior data_audit report and freeze preserved byte-for-byte."
}
},
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_data_audit_2026_11_04.json",
"report_sha256": "227498db6488da6f4841c14ea063abcd3b788a069f8e61bb3c384b8bcee55f94",
"freeze_record_path": "docs/research/reported_offset_data_audit_2026_11_04.freeze.json",
@@ -350,27 +372,5 @@
"freeze_record_sha256": "20e7684bc6c7356a421c2c20517c153279561f810cd15d77f260c9915352aed9",
"superseded_reason": "The data-audit fixes BUG-1545 (scripts/narayana_dasha.py, scripts/active_rectification_event_engine.py) and BUG-1546 (scripts/shadbala.py) changed frozen identity files. Summary is unchanged and 2 of 900 trials changed true_rank only (BUG-1545), so ERR-110 stored a new record. Prior d60_mapping report and freeze preserved byte-for-byte."
}
},
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_d60_mapping_2026_10_29.json",
"report_sha256": "f40157139733552dbefdfc999f95458de75594cd511df0e5377d606e27559f0d",
"freeze_record_path": "docs/research/reported_offset_d60_mapping_2026_10_29.freeze.json",
"freeze_record_sha256": "20e7684bc6c7356a421c2c20517c153279561f810cd15d77f260c9915352aed9",
"scope": "reported_offset_sensitivity_not_product_accuracy",
"trial_count": 900,
"official_valid_independent_blind": false,
"official_blind_trial_count": 0,
"must_not_use_for_tuning": true,
"must_not_claim_as_release_metrics": true,
"replay_started_at_utc": "2026-10-29T06:08:17.701243+00:00",
"replay_finished_at_utc": "2026-10-29T06:29:23.437778+00:00",
"boundary": "Previously exposed reported-offset sensitivity after the D60 mapping fix (ERR-110, BUG-1500). Summary and trials match the 2026-10-18 upstream sync8 and the upstream_sync9b reports. Versus the 2026-09-20 historical report, changed_trial_count stays 581 of 900. Not a release metric. No tuning. Prior reports and freezes preserved byte-for-byte.",
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_upstream_sync9b_2026_10_28.json",
"report_sha256": "880bebc2e217100994a1442e47ead3f9d33e48aa3ac20f69d993f38def3ef25c",
"freeze_record_path": "docs/research/reported_offset_upstream_sync9b_2026_10_28.freeze.json",
"freeze_record_sha256": "385817bb27f04afeba230af5e547dd10dc8cf6db4b25c18bebe4f4e674cab972",
"superseded_reason": "The D60 mapping fix (BUG-1500) changed scripts/varga.py, which is part of the extended identity. Output is unchanged, so ERR-110 stored a new record. Prior upstream_sync9b report and freeze preserved byte-for-byte."
}
}
}
+5 -2
View File
@@ -39,8 +39,11 @@ MINUTE_STEP = 1
# 原值: docs/research/reported_offset_d60_mapping_2026_10_29.{freeze.json,json}
# 新值: docs/research/reported_offset_data_audit_2026_11_04.{freeze.json,json}
# 原因: 数据核对 BUG-1545(narayana_dasha.py、active_rectification_event_engine.py)与 BUG-1546(shadbala.py)改了冻结身份文件,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/reported_offset_data_audit_2026_11_04.freeze.json"
REPORT = ROOT / "docs/research/reported_offset_data_audit_2026_11_04.json"
# 原值: docs/research/reported_offset_data_audit_2026_11_04.{freeze.json,json}
# 新值: docs/research/reported_offset_moon_paksha_2026_11_04.{freeze.json,json}
# 原因: BUG-1557 月亮 Paksha 口径(scripts/shadbala.py)改了冻结身份文件,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/reported_offset_moon_paksha_2026_11_04.freeze.json"
REPORT = ROOT / "docs/research/reported_offset_moon_paksha_2026_11_04.json"
LEGACY_REPORT = ROOT / "docs/research/reported_offset_2026_09_20.json"
+5 -2
View File
@@ -36,8 +36,11 @@ DATASET = ROOT / "references/real_case_calibration/minute_rectification_holdout_
# 原值: docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.{freeze.json,json}
# 新值: docs/research/sealed_holdout_rerun_data_audit_2026_11_04.{freeze.json,json}
# 原因: 数据核对 BUG-1545(narayana_dasha.py、active_rectification_event_engine.py)与 BUG-1546(shadbala.py)改了冻结身份文件,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.freeze.json"
REPORT = ROOT / "docs/research/sealed_holdout_rerun_data_audit_2026_11_04.json"
# 原值: docs/research/sealed_holdout_rerun_data_audit_2026_11_04.{freeze.json,json}
# 新值: docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.{freeze.json,json}
# 原因: BUG-1557 月亮 Paksha 口径(scripts/shadbala.py)改了冻结身份文件,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.freeze.json"
REPORT = ROOT / "docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04.json"
LEGACY_REPORT = ROOT / "docs/research/sealed_holdout_rerun_2026_09_20.json"
ARCHIVE = ROOT / "docs/research/history/rectification_pre_cross_midnight_2026_09_20"
PRODUCTION_FILES = [
+20 -4
View File
@@ -387,14 +387,25 @@ def _days_elapsed_since_base(year: int, base_year: int = 1951, base_days: int =
return base_days + leap_years * 366 + (years - leap_years) * 365
# BUG-1557: the Moon's Paksha convention of the precise path, named so it is
# traceable. BPHS (Santhanam tr.) 27.10-11: benefics take the folded
# elongation / 3, malefics 60 minus that, the Moon by phase (3.11) and not
# doubled; 27.18: the Moon's Chesta Bala is her Paksha Bala. Her Paksha
# therefore counts twice in the total (Kala + Chesta), as in saravali.github.io,
# Maitreya8 (default) and jyotishyamitra. Raman's Graha and Bhava Balas doubles
# it instead and leaves the Moon's Chesta out (Ex. 56); using both gave 4x.
MOON_PAKSHA_CONVENTION = "bphs_santhanam_27_10_11_chesta_27_18"
def paksha_phase(sun_longitude: float, moon_longitude: float) -> float:
"""Paksha base value: the Sun-Moon elongation folded to 0-180 degrees, / 3.
BUG-1546: the elongation was taken as abs(Sun - Moon) without folding, so
whenever the raw difference passed 180 degrees benefics got more than 60,
malefics went negative and the doubled Moon value passed 120 (5 of 19
benchmark charts; Monroe's Moon -45.76). Raman, Graha and Bhava Balas:
if the difference exceeds 180 degrees, subtract it from 360.
benchmark charts; Monroe's Moon -45.76). Raman, Graha and Bhava Balas
and BPHS 27.10: if the difference exceeds 180 degrees (6 signs), subtract
it from 360 (12 signs).
"""
elongation = abs(float(sun_longitude) - float(moon_longitude)) % 360.0
if elongation > 180.0:
@@ -442,9 +453,12 @@ def calc_kala_bala_precise(pname: str, all_planets: Dict, context: Dict) -> Dict
benefics, malefics = classify_drik_planets(all_planets)
phase = paksha_phase(_planet_longitude("Sun", all_planets), _planet_longitude("Moon", all_planets))
# Waxing Moon is a benefic, waning Moon a malefic (BPHS 3.11, Santhanam:
# "decreasing Candr" is a malefic); classify_drik_planets already does this.
paksha = phase if pname in benefics else round(60.0 - phase, 2) if pname in malefics else 0.0
if pname == "Moon":
paksha = round(paksha * 2.0, 2)
# 原值: 月亮 paksha ×2(Raman GBB §55(c)),Chesta 又取这个 ×2 后的值,总分里月亮盈亏力 = 4P
# 新值: 月亮 paksha 不乘 2;Chesta = Paksha(BPHS 27.18),总分里 = 2P
# 原因: BUG-1557,产品 2026-11-04 采用 MOON_PAKSHA_CONVENTION(BPHS-Santhanam 27.10–11 + 27.18)
sunrise, sunset = context["sunrise_hour"], context["sunset_hour"]
day_length = sunset - sunrise
@@ -516,6 +530,7 @@ def calc_chesta_bala_precise(pname: str, all_planets: Dict, kala: Dict, context:
if pname == "Sun":
return round(float(kala["ayana"]), 2)
if pname == "Moon":
# BPHS 27.18: the Moon's Paksha Bala is her Chesta Bala (MOON_PAKSHA_CONVENTION).
return round(float(kala["paksha"]), 2)
sun_mean = _surya_mean_longitude("Sun", context)
planet_mean = _surya_mean_longitude(pname, context)
@@ -640,6 +655,7 @@ def calc_shadbala(planets: Dict, asc_sign: str, birth_hour: float,
'method_variants': {
'kala': 'bphs_local_solar_events_ahargana_declination' if context else 'legacy_approximation',
'chesta': 'bphs_bounded_surya_mean_motion_seeghrochcha' if context else 'legacy_speed_bands',
'moon_paksha': MOON_PAKSHA_CONVENTION if context else 'legacy_approximation',
},
'external_parity_boundary': 'Chesta remains cross-engine method-conflicted; totals inherit that boundary.',
'is_night_birth': is_night,
+5
View File
@@ -49,6 +49,11 @@ def _value(row: dict, path: tuple[str, ...]) -> float:
def _variant(component: str, planet: str) -> str:
if component == "sthana":
return "moolatrikona_degree_range_vs_whole_sign"
if component == "kala" and planet == "Moon":
# BUG-1557: the fixture doubles the Moon's Paksha (Raman GBB) and gives her
# Chesta 0; the engine follows BPHS-Santhanam 27.10-11 + 27.18 (P in Kala,
# P again as Chesta). The Moon's Paksha total is 2P on both sides.
return "moon_paksha_convention"
if planet in {"Sun", "Moon"}:
return "luminary_chesta_policy"
return "mean_motion_seeghrochcha_variant"
@@ -68,6 +68,11 @@ IDENTITY_FORBIDDEN_PREFIXES = (
# 原因: 数据核对 BUG-1545 / BUG-1546 改了冻结身份文件,ERR-110 另存新记录
"docs/research/sealed_holdout_rerun_data_audit_2026_11_04",
"docs/research/reported_offset_data_audit_2026_11_04",
# 原值: 排除到 data_audit_2026_11_04
# 新值: 再排除 moon_paksha_2026_11_04 两份冻结路径(追加,不替换上面的)
# 原因: BUG-1557 月亮 Paksha 口径改了冻结身份里的 shadbala.py,ERR-110 另存新记录
"docs/research/sealed_holdout_rerun_moon_paksha_2026_11_04",
"docs/research/reported_offset_moon_paksha_2026_11_04",
"docs/research/history/",
"artifacts/",
)
@@ -0,0 +1,84 @@
"""BUG-1557: the Moon's Paksha counts 2P in Shadbala, not 4P.
The precise path doubled the Moon's Paksha in Kala (Raman, Graha and Bhava
Balas §55(c)) and then took that doubled value again as her Chesta (BPHS
27.18), so her Paksha entered the total four times. Product decision
2026-11-04: BPHS (Santhanam) 27.10-11 + 27.18 -- not doubled, Chesta = Paksha,
waxing Moon benefic, waning Moon malefic (3.11).
"""
from __future__ import annotations
import sys
from pathlib import Path
from types import SimpleNamespace
import pytest
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT / "scripts") not in sys.path:
sys.path.insert(0, str(ROOT / "scripts"))
import jyotish_engine # noqa: E402
from shadbala import MOON_PAKSHA_CONVENTION, classify_drik_planets, paksha_phase # noqa: E402
# Public Rodden AA charts (Astro-Databank), Raman ayanamsa, mean node.
CHARTS = {
# Steve Jobs, San Francisco: waxing, elongation about 32 degrees.
"jobs": dict(year=1955, month=2, day=24, hour=19, minute=15, lat=37.7749, lon=-122.4194, tz=-8.0),
# Marilyn Monroe, Los Angeles: waning (raw difference past 180 degrees).
"monroe": dict(year=1926, month=6, day=1, hour=9, minute=30, lat=34.0522, lon=-118.2437, tz=-8.0),
# Barack Obama, Honolulu: waning; the old 4x value gave Chesta 73.88 and Kashta 0.
"obama": dict(year=1961, month=8, day=4, hour=19, minute=24, lat=21.3069, lon=-157.8583, tz=-10.0),
}
def _chart(name: str) -> tuple[dict, dict]:
args = SimpleNamespace(second=0, ayanamsa="raman", node_mode="mean", **CHARTS[name])
chart, _, _, _ = jyotish_engine._compute_chart_from_args(args)
return chart["planets"], jyotish_engine.cmd_shadbala(args)
@pytest.mark.parametrize("name", sorted(CHARTS))
def test_moon_paksha_is_p_and_chesta_equals_paksha(name: str) -> None:
planets, result = _chart(name)
moon = result["planets"]["Moon"]
base = paksha_phase(planets["Sun"]["degree"], planets["Moon"]["degree"])
benefics, malefics = classify_drik_planets(planets)
waxing = (planets["Moon"]["degree"] - planets["Sun"]["degree"]) % 360.0 <= 180.0
# BPHS 3.11: waxing Moon benefic, waning Moon malefic.
assert ("Moon" in benefics) is waxing and ("Moon" in malefics) is not waxing
expected = base if waxing else round(60.0 - base, 2)
assert moon["kala_bala"]["paksha"] == pytest.approx(expected, abs=0.011) # P, not 2P
assert moon["chesta_bala"] == moon["kala_bala"]["paksha"] # BPHS 27.18
assert 0.0 <= moon["chesta_bala"] <= 60.0
assert 0.0 <= moon["ishta_phala"] <= 60.0
assert 0.0 <= moon["kashta_phala"] <= 60.0
assert moon["ishta_phala"] + moon["kashta_phala"] > 0.0
assert result["method_variants"]["moon_paksha"] == MOON_PAKSHA_CONVENTION == "bphs_santhanam_27_10_11_chesta_27_18"
def test_jobs_moon_values_are_pinned() -> None:
_, result = _chart("jobs")
moon = result["planets"]["Moon"]
# Before BUG-1557: paksha 21.34, chesta 21.34, total 659.40 Virupa.
assert moon["kala_bala"]["paksha"] == 10.67
assert moon["chesta_bala"] == 10.67
assert moon["total_virupas"] == pytest.approx(638.06, abs=0.011)
def test_obama_moon_kashta_is_no_longer_clamped() -> None:
_, result = _chart("obama")
moon = result["planets"]["Moon"]
# Before BUG-1557: chesta 73.88 (> 60), ishta 64.99 (> 60), kashta clamped to 0.
assert moon["chesta_bala"] == 36.94
assert moon["kashta_phala"] > 0.0
def test_other_planets_keep_their_paksha() -> None:
planets, result = _chart("jobs")
base = paksha_phase(planets["Sun"]["degree"], planets["Moon"]["degree"])
benefics, malefics = classify_drik_planets(planets)
for planet in ("Sun", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"):
expected = base if planet in benefics else round(60.0 - base, 2)
assert result["planets"][planet]["kala_bala"]["paksha"] == pytest.approx(expected, abs=0.011), planet
+4 -2
View File
@@ -26,8 +26,10 @@ def test_kala_paksha_stays_in_range_when_the_raw_difference_passes_180():
planets = _planets(350.0, 10.0)
for planet in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]:
paksha = calc_kala_bala_precise(planet, planets, context)["paksha"]
limit = 120.0 if planet == "Moon" else 60.0
assert 0.0 <= paksha <= limit, (planet, paksha)
# 原值: 月亮上限 120(Paksha ×2)
# 新值: 七星上限都是 60
# 原因: BUG-1557 月亮 Paksha 不再乘 2(BPHS-Santhanam 27.10–11)
assert 0.0 <= paksha <= 60.0, (planet, paksha)
# Jupiter is a natural benefic: its paksha is exactly elongation / 3 (the
# unfolded formula gave 340 / 3 = 113.33 here).
assert calc_kala_bala_precise("Jupiter", planets, context)["paksha"] == round(20.0 / 3.0, 2)
+6 -1
View File
@@ -72,7 +72,10 @@ def test_precise_kala_preserves_archived_comparison_with_corrected_hora() -> Non
# BUG-1275: Ayana reads tropical = sidereal + ayanamsa. The fixed sidereal
# longitudes of _planets() were captured in the old mean-ayanamsa frame; with the
# true ayanamsa the Moon's Ayana moves 26.09 -> 26.08 (Kala -0.01).
delta = 52.17 if planet == "Moon" else -60.0 if planet == "Venus" else 0.0
# 原值: 月亮 delta 52.17(月亮 Paksha ×2 = 21.33)
# 新值: 月亮 delta 41.51(Paksha 10.66,不乘 2;PyJHora 仍乘 2,差 10.66)
# 原因: BUG-1557 采用 BPHS-Santhanam 27.10–11 + 27.18(月亮 Paksha 不乘 2,Chesta = Paksha)
delta = 41.51 if planet == "Moon" else -60.0 if planet == "Venus" else 0.0
assert abs(calc_kala_bala_precise(planet, planets, context)["total"] - expected - delta) < 0.001
@@ -83,6 +86,8 @@ def test_precise_chesta_uses_classical_bounded_variant() -> None:
result = {planet: calc_chesta_bala_precise(planet, planets, kala[planet], context) for planet in planets}
assert result["Sun"] == kala["Sun"]["ayana"]
assert result["Moon"] == kala["Moon"]["paksha"]
# BUG-1557: the Moon's Paksha is P (waxing, 32 degrees / 3), not 2P, so Chesta is P too.
assert result["Moon"] == 10.66
for planet in ("Mars", "Mercury", "Jupiter", "Venus", "Saturn"):
assert 0.0 <= result[planet] <= 60.0
vedastro = {"Mars": 21.7377, "Mercury": 47.5107, "Jupiter": 46.0549, "Venus": 30.8469, "Saturn": 39.4390}
+4
View File
@@ -95,9 +95,13 @@ def test_birth_data_request_returns_precise_shadbala(api_base) -> None:
assert payload["success"] is True
result = payload["result"]
# The birth moment switches Kala and Chesta to the Swiss Ephemeris context.
# 原值: method_variants 只有 kala、chesta
# 新值: 加 moon_paksha(具名口径)
# 原因: BUG-1557 月亮 Paksha 口径绑定 BPHS-Santhanam 27.10–11 + 27.18
assert result["method_variants"] == {
"kala": "bphs_local_solar_events_ahargana_declination",
"chesta": "bphs_bounded_surya_mean_motion_seeghrochcha",
"moon_paksha": "bphs_santhanam_27_10_11_chesta_27_18",
}
assert sorted(result["ranking"]) == sorted(SEVEN)
for planet in SEVEN:
+13 -2
View File
@@ -20,14 +20,22 @@ def test_vp_jain_published_component_benchmark_is_fully_classified() -> None:
# 原因: TASK-upstream-sync4-20261002 T3(上游 0afa2780)平运动连续计时、短弧中点后,
# Chesta 火星 19.25→21.08、木星 11.23→8.86、土星 6.78→4.34 进入 ±1 Virupa;
# 金星 27.23→30.03 离开(公布值 28.18);水星 18.08→27.14 仍差 1.62。
assert report["summary"]["within_tolerance_count"] == 36
assert report["summary"]["method_variant_count"] == 6
# 原值: within_tolerance 36 / method_variant 6
# 新值: within_tolerance 35 / method_variant 7
# 原因: BUG-1557 月亮 Paksha 不再乘 2(BPHS-Santhanam 27.10–11 + 27.18),
# 月亮 Kala 205.96→151.58(公布值 205.85,按 Raman ×2),离开容差;
# 月亮 Chesta 108.76→54.38(公布值 0)仍是 luminary_chesta_policy。
assert report["summary"]["within_tolerance_count"] == 35
assert report["summary"]["method_variant_count"] == 7
def test_vp_jain_benchmark_keeps_known_method_variants_explicit() -> None:
rows = build_report()["rows"]
variants = {(row["component"], row["planet"]): row for row in rows if row["status"] != "within_tolerance"}
# 原值: 非匹配集里没有 ("kala", "Moon")
# 新值: 加 ("kala", "Moon");月亮 Kala + Chesta = 151.58 + 54.38 = 205.96,仍与公布 205.85 + 0 差 0.11
# 原因: BUG-1557 月亮 Paksha 从 Kala ×2 改为 Kala P + Chesta P,总分里同为 2P
assert set(variants) == {
("sthana", "Sun"),
("sthana", "Mercury"),
@@ -35,8 +43,11 @@ def test_vp_jain_benchmark_keeps_known_method_variants_explicit() -> None:
("chesta", "Moon"),
("chesta", "Mercury"),
("chesta", "Venus"),
("kala", "Moon"),
}
# 原值: chesta 非匹配集 {Sun, Moon, Mars, Mercury, Jupiter, Saturn}
# 新值: {Sun, Moon, Mercury, Venus}(原因同上:T3 Chesta 修正后火/木/土落入容差、金星跳出)
assert variants[("sthana", "Sun")]["variant"] == "moolatrikona_degree_range_vs_whole_sign"
assert variants[("chesta", "Moon")]["variant"] == "luminary_chesta_policy"
# BUG-1557: fixture Moon Kala carries the doubled Paksha; the engine counts P in Kala + P as Chesta.
assert variants[("kala", "Moon")]["variant"] == "moon_paksha_convention"