From 52f85a793fbf331a3d8dcbb62e420a93629279eb Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Nov 2026 17:07:54 +0800 Subject: [PATCH] fix(annual): pass node_mode to the solar-return charts (BUG-1501) calc_solar_return_chart hard-coded the mean node for the birth and annual charts, so node_mode=true never reached the annual Rahu/Ketu. The default stays mean; cmd_solar_return and cmd_tajika now pass the request's mode. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y --- docs/BUG_HISTORY.md | 15 +++++++++++++++ scripts/cmd_solar_return.py | 1 + scripts/jyotish_engine.py | 1 + scripts/solar_return.py | 10 ++++++++-- 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 637cb5d7..ecfe7816 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -20524,3 +20524,18 @@ - 复发自:无。 - 修复版本:分支 `codex/rectification-d60-two-way-20261028`。 + +## BUG-1501 | 年盘交点口径写死为平均交点,`node_mode=true` 传不到年盘 + +- 状态:resolved(代码 + 回归测试;待部署) +- 首次发现 / 最近更新:2026-11-01 / 2026-11-01(#152 裁定「完整传递计算参数」,#153 年度数据接口) +- 影响面:`scripts/solar_return.py::calc_solar_return_chart`(出生盘与年盘两次 `compute_chart_data`)→ `solar_return_full_report`、`cmd_solar_return`、`annual_tajika_pack`(完整数据版年运章)、`jyotish_engine.cmd_tajika`。受影响的只是年盘罗睺 / 计都经度,以及用到它们的 Tripataki 和年度整宫占星;返照时刻、七曜、上升、Muntha、年主、Mudda、Sahams、Patyayini 与交点无关。 +- 现象:用户选真交点时,年盘里的罗睺 / 计都仍是平均交点;年运包的设置里写着 `node_mode: true`,数据却是 mean。 +- 触发条件:`node_mode=true` 的任何年运计算。默认 mean 的请求不受影响。 +- 根因:`calc_solar_return_chart` 调 `compute_chart_data` 时第 9 个参数写死 `'mean'`,函数没有 `node_mode` 参数;`annual_tajika_pack._args_from_payload` 已经带了 `node_mode`,但 `cmd_solar_return` 没往下传。 +- 修复:`calc_solar_return_chart` / `solar_return_full_report` 新增 `node_mode='mean'` 参数并用于两次排盘,结果带 `node_mode`;`cmd_solar_return` 和 `cmd_tajika` 的返照调用传 `getattr(args, 'node_mode', None) or 'mean'`;`/api/annual` 旧响应也传 `node_mode`(默认 mean,结果不变)。 +- 验证:`tests/test_annual_package.py::test_solar_return_node_mode_default_stays_mean`(默认仍为 mean;true 时罗睺变、返照 JD 和土星不变)与 `test_node_mode_reaches_annual_chart_monthly_charts_and_transits`。年运 / 返照相关 20 个测试文件,以及 `test_api_server_security.py`、完整数据版 8 个报告测试文件,在本机私有 venv 里全部通过。 +- 防复发:上述两条测试锁住「交点参数到达年盘」和「默认不变」。 +- 相关记录:BUG-1095、BUG-1220(同一函数的地点 / 参考系参数)。 +- 复发自:无 +- 修复版本:分支 `codex/annual-153`。 diff --git a/scripts/cmd_solar_return.py b/scripts/cmd_solar_return.py index 37e94da9..9e7b1385 100644 --- a/scripts/cmd_solar_return.py +++ b/scripts/cmd_solar_return.py @@ -44,6 +44,7 @@ def cmd_solar_return(args: Any) -> Dict[str, Any]: args.target_year, ayanamsa_name=getattr(args, 'ayanamsa', None) or DEFAULT_AYANAMSA_NAME, birth_second=int(getattr(args, 'second', 0) or 0), + node_mode=getattr(args, 'node_mode', None) or 'mean', # BUG-1501 **solar_return_location_kwargs(args), ) diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index 1fa1c27c..f573b1a5 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -14599,6 +14599,7 @@ def _tajika_annual_core(args, planet_lons, asc_si, age, mode='all'): int(args.year), int(args.month), int(args.day), int(args.hour), int(args.minute), float(args.lat), float(args.lon), float(args.tz), int(args.year) + int(age), ayanamsa_name=sr_cache['ayanamsa'], birth_second=_arg_second(args), + node_mode=getattr(args, 'node_mode', None) or 'mean', # BUG-1501 **solar_return_location_kwargs(args), ) return sr_cache['sr'] diff --git a/scripts/solar_return.py b/scripts/solar_return.py index 62d36a46..f4797d7e 100644 --- a/scripts/solar_return.py +++ b/scripts/solar_return.py @@ -320,6 +320,7 @@ def calc_solar_return_chart( return_lon: float | None = None, return_tz: float | None = None, birth_second: int = 0, + node_mode: str = 'mean', ) -> Dict: """ 计算太阳返照盘(Varshaphala)。 @@ -332,6 +333,7 @@ def calc_solar_return_chart( 参数: birth_*: 出生信息 target_year: 目标年份(计算该年太阳返照) + node_mode: 年盘罗睺 / 计都口径(mean / true),默认 mean(BUG-1501) 返回: dict: { @@ -377,7 +379,7 @@ def calc_solar_return_chart( birth_year, birth_month, birth_day, birth_hour, birth_minute, birth_lat, birth_lon, birth_tz, - 'mean', + node_mode, second=birth_second, ayanamsa_name=ayanamsa_name, ) @@ -430,7 +432,7 @@ def calc_solar_return_chart( 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', + node_mode, # BUG-1501: was always 'mean' second=sr_dt_ut.second, ayanamsa_name=ayanamsa_name, ) @@ -460,6 +462,7 @@ def calc_solar_return_chart( 'annual_location': {'latitude': annual_lat, 'longitude': annual_lon, 'utc_offset': annual_tz, 'timezone_id': local_timezone_id}, 'age': target_year - birth_year, + 'node_mode': node_mode, 'note': f'太阳返照盘 {target_year} 年(年龄 {target_year-birth_year} 岁)', } @@ -482,6 +485,7 @@ def solar_return_full_report( return_lon: float | None = None, return_tz: float | None = None, birth_second: int = 0, + node_mode: str = 'mean', ) -> Dict: """ 太阳返照盘完整报告(Varshaphala 年运分析)。 @@ -512,6 +516,7 @@ def solar_return_full_report( local_timezone_id=local_timezone_id, return_lat=return_lat, return_lon=return_lon, return_tz=return_tz, birth_second=birth_second, + node_mode=node_mode, ) if 'error' in sr: @@ -533,6 +538,7 @@ def solar_return_full_report( else: result['solar_return'] = sr['solar_return'] result['annual_location'] = dict(sr.get('annual_location') or {}) + result['node_mode'] = sr.get('node_mode', node_mode) result['sr_chart_info'] = { 'asc_sign': SIGNS[sr['asc_sign_idx']], 'asc_sign_idx': sr['asc_sign_idx'],