From 01929baea69afb1775ed90d4b00bb41ceeee5cd5 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sat, 3 Oct 2026 22:10:15 +0800 Subject: [PATCH] fix(solar-return): return instant in the solver's frame, annual chart keeps seconds (BUG-1220) The natal Sun target came from compute_chart_data while the solver iterates on _get_sun_lon_jd (swe sidereal flags); the frames differ by up to ~17", moving the return by up to ~7 minutes. The annual chart was also cast at the truncated minute. Ports upstream yinduzhanxing 7cc6425d / 46ed9399 (these two hunks only). PyJHora reference: 3 cases within 0.03 min. 243 public-figure annual charts: annual Lagna changes 13, year lord 11, Mudda first lord 0. v5 77 cases identical to 3c27c38e; consult goldens re-captured byte-identical. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8 --- CHANGELOG.md | 6 ++ docs/BUG_HISTORY.md | 16 ++++ docs/research/pre_work_error_ledger.md | 2 + .../PROGRESS-annual-return-frame-20261003.md | 78 ++++++++++++++++++ docs/tasks/README.md | 2 +- scripts/solar_return.py | 24 ++++-- tests/test_solar_return_frame.py | 81 +++++++++++++++++++ 7 files changed, 200 insertions(+), 9 deletions(-) create mode 100644 docs/tasks/PROGRESS-annual-return-frame-20261003.md create mode 100644 tests/test_solar_return_frame.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d466fa00..d077c1be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # 印度占星 Skill 更新日志 +## 2026-10-03 — 太阳返照时刻改准:约 5% 的年份年盘上升和年主会变 + +- 年运(Varshaphala)的太阳返照时刻以前会偏 3–7 分钟:出生太阳和求返照用的不是同一套参考系,年盘还按整分钟起。现在两者对齐并保留秒,与外部参照引擎 PyJHora 抽查 3 例相差不到 0.03 分钟(BUG-1220)。 +- 影响:9 位公开名人 2000–2026 年共 243 张年盘里,年盘上升星座变 13 张、年主变 11 张;昼夜判定与 Mudda 起运星不变。数据卡、参考版报告的年运段随之改变;旧报告内容不变。 +- 生时校正不用年盘,分数与算法版本不变。Skill 版本不变;不改数据库结构。 + ## 2026-10-03 — 占星师口径第三批:Mudda 改从出生月宿起排、年主按 Tajika 五分力量比、Rath 版 Narayana 起运宫重做(未上线) - 年内 Mudda Dasha 不再从年主起排,改按占星师定的公式:起运星 =(已满年数 + 出生月宿序号 − 2)除以 9 的余数(1 日、2 月、3 火、4 罗、5 木、6 土、7 水、8 计、0 金),余额按出生时月亮在月宿里走过的比例,年长 365.25 天。年主怎么变,月份分段都不变。数据卡和报告的年内分段都来自这个新算法;9 位公开名人里 8 位的年内第一段与原来不同(BUG-1216)。 diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index eee07bef..5b086842 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -16451,3 +16451,19 @@ - 相关记录:BUG-1214、BUG-1217。 - 复发自:无 - 修复版本:—(上游) + +## BUG-1220 | 太阳返照时刻偏 3–7 分钟:出生太阳与求解器不在同一参考系,年盘还截到整分钟 + +- 状态:resolved(分支 `codex/annual-return-frame-20261003`;待推送部署) +- 首次发现 / 最近更新:2026-10-03 / 2026-10-03 +- 来源:共享引擎复用核对 `docs/research/shared_engine_reuse_audit_2026_10_03.md` §S1;任务书 `TASK-annual-return-frame-20261003`。移植来源:上游 `yinduzhanxing` `7cc6425d`(出生太阳改在求解器参考系重算)、`46ed9399`(年盘保留秒),只取这两处。 +- 影响面:`solar_return.calc_solar_return_chart` → `solar_return_full_report`、`jyotish_engine.cmd_tajika`、全量解读 Step 9、`annual_tajika_pack`、咨询年运层(数据卡)、参考版报告年运段:年盘上升、年主、Sahams、Mudda 起点时刻。生时校正不用年盘,不受影响。 +- 现象:同一张盘同一岁差,本站返照时刻与上游、PyJHora 差几分钟(Rath 标准盘 2025 年差 6 分 16 秒)。9 位公开名人 × 2000–2026 年共 243 张年盘里,年盘上升星座错 13 张、年主错 11 张,昼夜判定 0 张受影响。 +- 触发条件:任何盘。偏差大小取决于出生时刻的章动等参考系差(约 ±17″ 以内,折合返照时刻约 ±7 分钟);年盘上升恰在星座边界附近的年份会换星座。 +- 根因:① 目标经度取 `compute_chart_data` 的出生太阳 `degree_raw`,求解器 `_find_solar_return_swe` 用 `_get_sun_lon_jd`(`swe.calc_ut` + `sidereal_flags`)逐步逼近,两套参考系对出生太阳差 15.1″(标准盘)。② 起年盘时用整点分钟调用 `compute_chart_data`,丢了秒。上游 9 月 7–8 日已修,本站引擎同步停在 `f2241463`(9 月 3 日),之后 `solar_return.py` 只按 BUG-1095 补过本地化,漏了这两处(ERR-109 同类)。 +- 修复:`calc_solar_return_chart` 中目标经度改为 `_get_sun_lon_jd(birth_jd_ut)`,拿不到才退回出生盘值;返回 `solar_return.target_sun_frame`(`swe_sidereal_flags` / `birth_chart_degree_raw`)。起年盘传 `second=sr_dt_ut.second`。上游同期加的 `position_mode` 等研究回放参数未搬;本地化保留本站实现。 +- 验证:`tests/test_solar_return_frame.py`:三例返照 JD 与 PyJHora `drik.next_solar_date` 参照值(只存数字)差 ≤ 0.5 分钟,实测 0.0 / 0.021 / 0.006 分钟;目标经度等于求解器参考系出生太阳(< 1″);年盘时刻与返照差 < 1 秒。换回旧代码这 5 条全部失败。243 张年盘前后对比、v5(三段与基线逐项相同)、快速门、前端失败名单比对见进度记录。咨询两份 golden 用真实引擎重采后逐字节不变(三张盘 2026 年的年盘上升与年主恰好不变,日期只存到天)。 +- 防复发:上述测试;同步上游太阳返照时,核对目标经度与求解器同一参考系(已补进 ERR-109)。 +- 相关记录:BUG-1095、BUG-1026~1028、ERR-109。 +- 复发自:无(ERR-109 同类漏同步) +- 修复版本:待发布 diff --git a/docs/research/pre_work_error_ledger.md b/docs/research/pre_work_error_ledger.md index c7803863..bd189d1c 100644 --- a/docs/research/pre_work_error_ledger.md +++ b/docs/research/pre_work_error_ledger.md @@ -443,6 +443,8 @@ Prevention: 前台同步路径不得进入无上限排队,超预算即 fail-fa Prevention: 引擎/上游同步类任务必须 fetch 后核对 `origin/main`,以实际 SHA 为准,并在进度和本台账写明与任务书 tip 的差异。读者版整段引入要带来源提交。不要把 `.workbuddy` 当主仓。同步太阳返照时核对返回键,而不只核对函数还在。关联 BUG-1026、BUG-1027、BUG-1028。 +2026-10-03 复发(BUG-1220):同一次同步漏了上游 `7cc6425d`(出生太阳在求解器参考系重算)与 `46ed9399`(年盘保留秒),返照时刻偏 3–7 分钟、约 5% 年份年盘上升换星座。补充:同步太阳返照时还要核对目标经度与求解器是同一参考系,并用外部引擎抽几例返照时刻对照。 + ## ERR-110 | 输出逐字节不变的引擎性能改动也会打红校正验证完整性门禁 | observed 2026-09-26 `scripts/rectification/event_probes.py`、`refinement_packet.py` 等 10 个文件在 `scripts/research/sealed_holdout_rerun.py` `PRODUCTION_FILES` 里,另有 dataset `frozen_scoring.files` 12 个遗留文件;快速门的 `tests/test_rectification_validation_integrity_gate.py` 按文件字节哈希核对冻结记录。BUG-1047 的探针大运表复用(同机 A/B 7 个场景逐字节一致,refresh 61 候选 2.33 → 1.84 s)只改了 `event_probes.py`,就让该门禁 4 条失败。 diff --git a/docs/tasks/PROGRESS-annual-return-frame-20261003.md b/docs/tasks/PROGRESS-annual-return-frame-20261003.md new file mode 100644 index 00000000..a64bcedc --- /dev/null +++ b/docs/tasks/PROGRESS-annual-return-frame-20261003.md @@ -0,0 +1,78 @@ +# PROGRESS:太阳返照时刻对齐(出生太阳同参考系 + 保留秒)— 2026-10-03 + +- 任务书:`docs/tasks/TASK-annual-return-frame-20261003.md`。执行方:Claude 直接执行(产品负责人 2026-10-03 晚确认)。 +- 分支 `codex/annual-return-frame-20261003`,工作树 `.worktrees/annual-return-frame-20261003`,基线 `origin/staging` = `3c27c38e`(第三批已合入,含 BUG-1216~1219)。 +- 上游参照:`yinduzhanxing` `7cc6425d`、`46ed9399`(只读)。 +- BUG 编号:开工时最大号 BUG-1219;本单 BUG-1220。 +- 预检:`scripts/pre_work_check.py` → `status: pass`。磁盘余 44G。 + +## 结论 + +| 任务 | 结果 | +| --- | --- | +| T1 出生太阳与求解器同参考系 | 完成。PyJHora 对照 3 例:0.000 / 0.021 / 0.006 分钟(门槛 0.5) | +| T2 年盘保留秒 | 完成。年盘时刻与返照差 < 1 秒 | +| T3 下游与 golden | 咨询两份 golden 用真实引擎重采,逐字节不变;243 张年盘对比见下 | +| T4 记录 | BUG-1220、ERR-109 复发说明、CHANGELOG、本文件、README | + +## 改动 + +- `scripts/solar_return.py:calc_solar_return_chart`: + - 目标经度 = `_get_sun_lon_jd(birth_jd_ut)`,拿不到才退回出生盘 `degree_raw`; + - `solar_return.target_sun_frame` 标明用了哪一种; + - 起年盘传 `second=sr_dt_ut.second`。 +- 新测试 `tests/test_solar_return_frame.py`(5 条)。换回旧代码时 5 条全部失败。 +- 未搬:上游 `position_mode`、`solar_return_time_offset_seconds`、`node_longitude_offset_arcseconds`、`annual_house_system_for_sahams`(研究回放参数)。 + +## PyJHora 对照(只存数字,Lahiri) + +| 例 | PyJHora 返照 JD(UT) | 本站修后 | 差(分钟) | 修前差(分钟) | +| --- | --- | --- | --- | --- | +| Rath 标准盘 2025 | 2460895.0424092 | 2460895.0424094 | 0.000 | −6.3 | +| 乔布斯 2012 | 2455983.2569387 | 2455983.2569242 | −0.021 | +7.2 | +| 齐达内 2002 | 2452449.2759534 | 2452449.2759490 | −0.006 | +6.3 | + +## 243 张年盘前后对比 + +9 位公开名人(`tests/test_pancha_mahapurusha_main_detector.py:FIGURES`)× 2000–2026 年,Lahiri,年主与 Mudda 用第三批的产品函数。 + +| 指标 | 变化 | +| --- | --- | +| 返照时刻最大偏移 | 7.2 分钟 | +| 年盘上升星座 | 13/243 | +| 昼夜判定 | 0/243 | +| 年主 | 11/243 | +| Mudda 起运星 | 0/243(第三批后与年盘无关,作为回归证据) | + +| 名人 | 年 | 时刻偏移(分钟) | 年盘上升 | 年主 | +| --- | --- | --- | --- | --- | +| 乔布斯 | 2012 | −7.2 | 金牛 → 白羊 | 金星 → 太阳 | +| 乔布斯 | 2015 | −7.2 | 摩羯 → 射手 | 金星 → 太阳 | +| 乔布斯 | 2024 | −7.2 | 双子 → 金牛 | 土星 → 金星 | +| 奥巴马 | 2009 | +3.4 | 金牛 → 双子 | 月亮 → 水星 | +| 奥巴马 | 2024 | +3.4 | 双鱼 → 白羊 | 月亮 → 土星 | +| 梦露 | 2007 | +7.1 | 白羊 → 金牛 | 月亮 → 火星 | +| 琵雅芙 | 2009 | −4.9 | 射手 → 天蝎 | 土星(不变) | +| 琵雅芙 | 2021 | −4.9 | 摩羯 → 射手 | 火星 → 木星 | +| 卡罗 | 2001 | +6.5 | 狮子 → 处女 | 水星 → 月亮 | +| 卡罗 | 2012 | +6.5 | 双子 → 巨蟹 | 土星 → 金星 | +| 小布什 | 2007 | +6.8 | 摩羯 → 水瓶 | 月亮 → 太阳 | +| 小布什 | 2023 | +6.8 | 双鱼 → 白羊 | 土星(不变) | +| 齐达内 | 2002 | −6.3 | 射手 → 天蝎 | 木星 → 金星 | + +## 验收 + +| 项 | 结果 | +| --- | --- | +| 新测试 + 年运相关定向(`test_solar_return_frame`、`test_solar_return_timezone`、`test_annual_tajika_pack`) | 26 passed | +| `test_report_english_dictionary` + Tajika / Mudda / 年主四个文件 | 208 passed | +| 快速门 Python 段 | 1047 passed、1 skipped、0 failed | +| 前端 `npm test`(Node 22.14) | 4931 个,fail 24、cancelled 0;失败名单与基线 `3c27c38e` 逐条相同 | +| v5 77 例 | 三段结果(分钟级打分、候选范围宽度、采集无效停止回放)与基线 `3c27c38e` 逐项相同,只有耗时字段不同 | +| `tsc` / lint / build | 未跑:本单没有前端源码改动,只有前端 golden 重采且逐字节不变 | +| 历史报告可打开 | 不涉及:旧报告存的是生成时结果,不重算;未改迁移与 Skill 版本 | + +## 环境缺口 + +- 名人生平回测:本机无模型凭据,未跑(本单不改提示词)。 +- 真机:部署后在 staging 打开一张年运数据卡或参考版报告,看年运段能出;数值变化只影响约 5% 的年份,不另立真机清单。 diff --git a/docs/tasks/README.md b/docs/tasks/README.md index 970435fa..d44af50c 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -416,4 +416,4 @@ | `TASK-astrologer-rulings-batch1-20261003.md` | `PROGRESS-astrologer-rulings-batch1-20261003.md` | 占星师定稿 2026-10-03 第一批(低风险批):五大人格、Kemadruma 各只留一个主检测器;Shadbala 达标在前、分档标「网站分档」;Bhava Bala 改正式三分量;罗计不设本宫、宫主链固定传统主星;8 星制 Karaka 排位按 BPHS 修正;八分法净化值进报告/卡片(过运不动);落陷取消改条件清单;Tajika 年主如实标注。乙3 Narayana、甲1、甲8/9 不在本单(BUG 从 1204 起) | 已验收,已部署 staging `e7eeb404`(Claude 补修确认门测试 `14d5c761`) | 分支 `codex/astrologer-rulings-batch1-20261003`(BUG-1204~1212;校正分数不变、未升版本) | | `TASK-astrologer-rulings-batch2-20261003.md` | `PROGRESS-astrologer-rulings-batch2-20261003.md` | 占星师第四轮:五大人格 D9 落陷只算减弱;Tajika 年主按 Panchadhikari 选法(移植上游 c7117f92);Narayana 实现 Sanjay Rath 版并用原书三张样表验收,不接打分;旧 Narayana 如实标注;Rath 版替换校正 Narayana 的 v5 试算(只研究)。产品选方案 A(BUG 从 1213 起) | 已验收,已部署 staging `503c1190`(T3 起运宫未过原书样表,按红线未接、T5 未做;Claude 补修英文对照 `dda966e6`) | 分支 `codex/astrologer-rulings-batch2-20261003`(BUG-1213~1215;校正分数不变、未升版本) | | `TASK-astrologer-rulings-batch3-20261003.md` | `PROGRESS-astrologer-rulings-batch3-20261003.md` | 占星师第五轮:Mudda 改出生月宿起排(与年主脱钩);年主改 Tajika 正式五分力量;Rath 版 Narayana 按原书 7 级强弱、计都反转、子运起点重做并以三张样表验收,过了再并列展示与 v5 试算(研究分支);土计同宫计都优先(产品选 A);上游两个 bug 记录(BUG 从 1216 起) | 已实现待验收(T1–T4 完成;T3 按修订后红线 3 通过;T5 v5 试算在研究分支,未合入) | 分支 `codex/astrologer-rulings-batch3-20261003`(未推送;BUG-1216~1219;校正分数不变、未升版本);研究分支 `codex/narayana-rath-rectification-trial-20261003`(未推送、不合入) | -| `TASK-annual-return-frame-20261003.md` | `PROGRESS-annual-return-frame-20261003.md` | 太阳返照时刻错位:出生太阳与求解器不同参考系(差 15″≈6 分钟)+ 年盘丢秒;243 张年盘里年盘上升变 13、年主变 11;搬上游 7cc6425d/46ed9399 两处,PyJHora 对照 ≤0.5 分钟;排在第三批之后(依据 `docs/research/shared_engine_reuse_audit_2026_10_03.md`) | 已确认,第三批合入后开工 | 分支 `codex/annual-return-frame-20261003` | +| `TASK-annual-return-frame-20261003.md` | `PROGRESS-annual-return-frame-20261003.md` | 太阳返照时刻错位:出生太阳与求解器不同参考系(差 15″≈6 分钟)+ 年盘丢秒;243 张年盘里年盘上升变 13、年主变 11;搬上游 7cc6425d/46ed9399 两处,PyJHora 对照 ≤0.5 分钟;排在第三批之后(依据 `docs/research/shared_engine_reuse_audit_2026_10_03.md`) | 已实现(BUG-1220),待部署核对 | 分支 `codex/annual-return-frame-20261003` | diff --git a/scripts/solar_return.py b/scripts/solar_return.py index 86cfdee1..9d83b4fc 100644 --- a/scripts/solar_return.py +++ b/scripts/solar_return.py @@ -384,6 +384,16 @@ def calc_solar_return_chart( moon_data = birth_chart.get('planets', {}).get('Moon', {}) birth_moon_lon = moon_data.get('degree_raw', moon_data.get('degree')) if isinstance(moon_data, dict) else None birth_jd_ut = birth_jd + # BUG-1220: the target longitude must come from the same frame the + # solver iterates in (`_get_sun_lon_jd`, swe sidereal flags). The chart's + # Sun differs by up to ~17" (about 7 minutes of return time). Upstream + # yinduzhanxing 7cc6425d. + solver_frame_sun = _get_sun_lon_jd(birth_jd_ut, ayanamsa_name=ayanamsa_name) + target_sun_frame = 'swe_sidereal_flags' + if solver_frame_sun is None: + target_sun_frame = 'birth_chart_degree_raw' + else: + birth_sun_lon = solver_frame_sun # Step 2: 计算太阳返照精确时刻 sr_result = find_solar_return_ut( @@ -393,6 +403,7 @@ def calc_solar_return_chart( ) if 'error' in sr_result: return {'error': sr_result['error'], 'solar_return': sr_result} + sr_result['target_sun_frame'] = target_sun_frame sr_jd_ut = sr_result['jd_ut'] sr_dt_ut = sr_result['dt_ut'] @@ -406,17 +417,14 @@ def calc_solar_return_chart( 'utc_offset': annual_tz, 'timezone_id': local_timezone_id} # Step 3: 以返照时刻计算星盘 - # compute_chart_data 接受 year/month/day/hour/minute - sr_year, sr_month, sr_day = sr_dt_ut.year, sr_dt_ut.month, sr_dt_ut.day - sr_hour = sr_dt_ut.hour + sr_dt_ut.minute / 60.0 + sr_dt_ut.second / 3600.0 - sr_hour_int = int(sr_hour) - sr_minute_int = int((sr_hour - sr_hour_int) * 60) - + # Keep the solver's seconds (BUG-1220, upstream 46ed9399): truncating + # to the minute moves the annual Ascendant by up to ~0.25 deg. sr_chart, sr_asc_idx, sr_jd, sr_ayanamsa = compute_chart_data( - sr_year, sr_month, sr_day, - sr_hour_int, sr_minute_int, + sr_dt_ut.year, sr_dt_ut.month, sr_dt_ut.day, + sr_dt_ut.hour, sr_dt_ut.minute, annual_lat, annual_lon, 0, # UT 时间,时区=0 'mean', + second=sr_dt_ut.second, ayanamsa_name=ayanamsa_name, ) if sr_chart is None: diff --git a/tests/test_solar_return_frame.py b/tests/test_solar_return_frame.py new file mode 100644 index 00000000..fc1ec5f2 --- /dev/null +++ b/tests/test_solar_return_frame.py @@ -0,0 +1,81 @@ +"""Solar-return instant in the solver's frame, annual chart with seconds (BUG-1220). + +The return is the instant the Sun regains its natal sidereal longitude. The +website took the natal Sun from ``compute_chart_data`` while +``_find_solar_return_swe`` iterates on ``_get_sun_lon_jd`` (swe sidereal +flags); the two differ by up to ~17", which moved the return by up to ~7 +minutes and changed the annual Ascendant sign in 13 of 243 public-figure +years. The annual chart was also cast at the truncated minute. Upstream +yinduzhanxing 7cc6425d / 46ed9399. + +Reference instants were computed once with PyJHora ``drik.next_solar_date`` +(Lahiri) as an external reference engine; only the resulting numbers are kept +here, PyJHora is not imported. Charts: Sanjay Rath's "standard nativity" and +two public figures from references/real_case_calibration. +""" +from __future__ import annotations + +import contextlib +import io +import sys +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[1] +SCRIPTS = ROOT / "scripts" +if str(SCRIPTS) not in sys.path: + sys.path.insert(0, str(SCRIPTS)) + +import solar_return # noqa: E402 + +try: # pragma: no cover - environment probe + import swisseph # noqa: F401 + + HAS_SWE = True +except Exception: # pragma: no cover + HAS_SWE = False + +pytestmark = pytest.mark.skipif(not HAS_SWE, reason="swisseph required") + +# (birth y, m, d, h, min, lat, lon, tz), target year, PyJHora return JD (UT) +PYJHORA_RETURNS = { + "rath_standard_nativity_2025": ((1963, 8, 7, 21, 15, 21.4667, 84.0167, 5.5), 2025, 2460895.0424092), + "steve_jobs_2012": ((1955, 2, 24, 19, 15, 37.7749, -122.4194, -8.0), 2012, 2455983.2569387), + "zinedine_zidane_2002": ((1972, 6, 23, 3, 0, 43.3, 5.4, 1.0), 2002, 2452449.2759534), +} + + +def _chart(birth, target_year): + with contextlib.redirect_stdout(io.StringIO()): + return solar_return.calc_solar_return_chart(*birth, target_year, "lahiri") + + +@pytest.mark.parametrize("case", sorted(PYJHORA_RETURNS)) +def test_return_instant_matches_the_external_reference(case: str) -> None: + birth, target_year, reference_jd = PYJHORA_RETURNS[case] + result = _chart(birth, target_year) + assert result["solar_return"]["target_sun_frame"] == "swe_sidereal_flags" + # Before BUG-1220 these were 6-7 minutes apart. + assert abs(result["solar_return"]["jd_ut"] - reference_jd) * 1440 <= 0.5 + + +def test_target_longitude_is_the_natal_sun_in_the_solver_frame() -> None: + birth, target_year, _ = PYJHORA_RETURNS["rath_standard_nativity_2025"] + with contextlib.redirect_stdout(io.StringIO()): + from jyotish_engine import compute_chart_data + natal, _asc, natal_jd, _ay = compute_chart_data(*birth, "mean", ayanamsa_name="lahiri") + solver_sun = solar_return._get_sun_lon_jd(natal_jd, ayanamsa_name="lahiri") + chart_sun = natal["planets"]["Sun"]["degree_raw"] + assert abs(chart_sun - solver_sun) * 3600 > 10 # the two frames really differ here + result = _chart(birth, target_year) + assert abs(result["solar_return"]["sun_lon"] - solver_sun) * 3600 < 1 + + +def test_annual_chart_keeps_the_seconds_of_the_return() -> None: + birth, target_year, _ = PYJHORA_RETURNS["rath_standard_nativity_2025"] + result = _chart(birth, target_year) + info = result["chart"]["birth_info"] + return_dt = result["solar_return"]["dt_ut"] + assert (info["hour"], info["minute"], info["second"]) == (return_dt.hour, return_dt.minute, return_dt.second) + assert abs(info["julian_day"] - result["solar_return"]["jd_ut"]) * 86400 < 1