fix(solar-return): return instant in the solver's frame, annual chart keeps seconds (BUG-1220)
Independent Staging Quality Gate / validate (push) Successful in 20m3s
Independent Staging Quality Gate / publish (push) Successful in 4m2s

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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
This commit is contained in:
Jesse_Chen
2026-10-03 22:10:20 +08:00
co-authored by Claude Opus 5.5
parent d0b783bd05
commit 01929baea6
7 changed files with 200 additions and 9 deletions
+16 -8
View File
@@ -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: