fix(kp): feed sub-lord analysis unrounded cusps, degrees and time (BUG-1543, upstream 26d5a52d)
cmd_kp handed calc_kp_analysis the cusps from calculate_bhava_boundaries (rounded to 4 decimals), degree_in_sign (4 decimals) and the chart's display julian_day (6 decimals). KP star, sub and sub-sub boundaries are cut on raw longitude, so a body or cusp sitting on a boundary could land one cell off. The fix recomputes the JD from the civil instant with the compute_chart_data formula, uses calculate_cusps directly, and uses degree_raw % 30. Only the KP part of 26d5a52d is ported. Its Vivaha Saham day/night change and Yoga status pass-through are left for a separate decision. Test ported from upstream tests/test_kp_unrounded_inputs.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
This commit is contained in:
@@ -21240,3 +21240,20 @@
|
||||
- 关联记录:BUG-1541、BUG-1220(年盘保留秒)。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/upstream-skill-sync-20261104`,待合并。
|
||||
|
||||
## BUG-1543 | KP 子主星与宫头用的是显示用的四舍五入值
|
||||
|
||||
- 状态:resolved(代码 + 回归测试;待部署)
|
||||
- 首次发现 / 最近更新:2026-11-04(上游同步第十轮核对上游 `26d5a52d`)/ 2026-11-04
|
||||
- 影响面:`scripts/jyotish_engine.py` `cmd_kp`(命令 `kp`、`/api/kp` 一类入口)。KP 在商业覆盖层仍是 `reference_only`。
|
||||
- 现象:行星落在星主 / 子主 / 子子主分界附近、或宫头附近时,KP 表可能差一格。
|
||||
- 触发条件:行星度数或宫头离 KP 分界小于约 0.0001 度;出生时间带秒。
|
||||
- 根因:`cmd_kp` 把 `calculate_bhava_boundaries()` 返回的宫头(保留 4 位小数)、行星的 `degree_in_sign`(保留 4 位小数)和星盘结果里的 `julian_day`(保留 6 位小数,约 0.09 秒)交给 KP 分析,KP 分界是按原始经度切的。上游同一缺陷,10-16 修复,第九轮没核对。
|
||||
- 修复:按出生时刻重算儒略日(与 `compute_chart_data` 同一公式,含秒);宫头改用 `calculate_cusps()` 原值;行星度数用 `degree_raw % 30`,没有原值时才退回显示值。
|
||||
- 验证:新测试 `tests/test_upstream_sync10_kp_unrounded_inputs.py`(移植上游 `tests/test_kp_unrounded_inputs.py`):儒略日、宫头、行星度数都是原值;改前失败、改后通过。`test_kp_system.py`、`test_kp_cusp_house_assignment.py`、`test_kp_monthly_report_packet.py` 5 条通过、2 条跳过;公开名人盘实跑 `cmd_kp` 正常返回。
|
||||
- 影响输出:只有贴着分界的行星或宫头会换一格,其余逐字节相同。不涉及冻结身份文件。
|
||||
- 未搬:同一上游提交里的 Vivaha Saham 昼夜公式与 Yoga 燃烧状态透传,见本轮进度记录。
|
||||
- 防复发:上述测试;显示用的取整值不进计算。
|
||||
- 关联记录:BUG-1383(KP 边界,第八轮)、BUG-1541、BUG-1542。
|
||||
- 复发自:无
|
||||
- 修复版本:分支 `codex/upstream-skill-sync-20261104`,待合并。
|
||||
|
||||
@@ -13749,6 +13749,12 @@ def cmd_kp(args):
|
||||
_apply_ayanamsa(requested_report_ayanamsa)
|
||||
return {"error": "swisseph未安装"}
|
||||
|
||||
# The chart's julian_day is rounded for display. KP cusp and sub-lord
|
||||
# boundaries use the civil instant itself, seconds included (upstream
|
||||
# 26d5a52d, BUG-1543). Same formula as compute_chart_data.
|
||||
jd = swe.julday(args.year, args.month, args.day,
|
||||
_birth_hour_decimal(args.hour, args.minute, _arg_second(args)) - args.tz)
|
||||
|
||||
asc_sign = chart.get("ascendant", {}).get("sign", "Aries")
|
||||
planets = chart.get("planets", {})
|
||||
planet_lons = {
|
||||
@@ -13762,7 +13768,8 @@ def cmd_kp(args):
|
||||
from bhava_chalit import BhavaChalitCalculator
|
||||
kp_house_calculator = BhavaChalitCalculator()
|
||||
asc_lon = chart.get('ascendant', {}).get('degree_raw', chart.get('ascendant', {}).get('degree', 0.0))
|
||||
boundaries = kp_house_calculator.calculate_bhava_boundaries(
|
||||
# Unrounded cusps; calculate_bhava_boundaries rounds them to 4 decimals.
|
||||
raw_cusps = kp_house_calculator.calculate_cusps(
|
||||
float(asc_lon), 0.0, 'placidus', jd, args.lat, args.lon,
|
||||
)
|
||||
bhava_chart = kp_house_calculator.get_bhava_chalit_chart(
|
||||
@@ -13776,16 +13783,19 @@ def cmd_kp(args):
|
||||
for pname, pdata in planets.items():
|
||||
if isinstance(pdata, dict) and 'sign' in pdata:
|
||||
bhava_row = bhava_planets.get(pname) if isinstance(bhava_planets.get(pname), dict) else {}
|
||||
raw_lon = planet_lons.get(pname)
|
||||
planet_positions[pname] = {
|
||||
'sign': pdata['sign'],
|
||||
'degree': pdata.get('degree_in_sign', pdata.get('degree', 0) % 30),
|
||||
# degree_in_sign is rounded to 4 decimals for display.
|
||||
'degree': (float(raw_lon) % 30 if raw_lon is not None
|
||||
else pdata.get('degree_in_sign', pdata.get('degree', 0) % 30)),
|
||||
'house': bhava_row.get('bhava_house', pdata.get('house', 1)),
|
||||
}
|
||||
|
||||
result = calc_kp_analysis(
|
||||
planet_positions,
|
||||
asc_sign,
|
||||
house_cusps=boundaries.get('cusps'),
|
||||
house_cusps=raw_cusps,
|
||||
house_occupancy_basis='cusp_to_cusp',
|
||||
)
|
||||
moon_lon = planets.get('Moon', {}).get('degree_raw', planets.get('Moon', {}).get('degree', 0.0)) if isinstance(planets.get('Moon'), dict) else 0.0
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
"""KP must not reuse display-rounded time, cusps or planet degrees (BUG-1543).
|
||||
|
||||
Ported from upstream yinduzhanxing 26d5a52d tests/test_kp_unrounded_inputs.py
|
||||
(sync 10). Synthetic chart only.
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
sys.path.insert(0, str(ROOT / 'scripts'))
|
||||
import jyotish_engine as engine # noqa: E402
|
||||
from bhava_chalit import BhavaChalitCalculator # noqa: E402
|
||||
|
||||
|
||||
def test_kp_passes_raw_time_cusps_and_longitudes(monkeypatch):
|
||||
args = SimpleNamespace(year=2000, month=1, day=2, hour=3, minute=4, second=5,
|
||||
lat=20., lon=75., tz=5.5, ayanamsa='raman')
|
||||
chart = {'ascendant': {'sign': 'Aries', 'degree_raw': 12.123456789},
|
||||
'planets': {'Sun': {'sign': 'Aries', 'degree_raw': 1.234567891, 'degree_in_sign': 1.2346},
|
||||
'Moon': {'sign': 'Taurus', 'degree_raw': 42.987654321, 'degree_in_sign': 12.9877}}}
|
||||
raw_cusps = [12.123456789 + 30 * i for i in range(12)]
|
||||
seen = {}
|
||||
monkeypatch.setattr(engine, '_compute_chart_from_args', lambda a: (chart, 0, 2451545., 23.))
|
||||
|
||||
def cusps(self, asc, mc, hs, jd, lat, lon):
|
||||
seen['jd'] = jd
|
||||
return raw_cusps
|
||||
|
||||
monkeypatch.setattr(BhavaChalitCalculator, 'calculate_cusps', cusps)
|
||||
monkeypatch.setattr(BhavaChalitCalculator, 'get_bhava_chalit_chart',
|
||||
lambda *a, **k: {'planets': {'Sun': {'bhava_house': 12}, 'Moon': {'bhava_house': 2}}})
|
||||
|
||||
def analyze(planets, asc, **kwargs):
|
||||
seen['planets'] = planets
|
||||
seen.update(kwargs)
|
||||
return {}
|
||||
|
||||
monkeypatch.setattr(engine, 'calc_kp_analysis', analyze)
|
||||
monkeypatch.setattr(engine, 'attach_calculation_profile', lambda result, args: result)
|
||||
monkeypatch.setattr(engine, '_build_response_envelope', lambda command, result, **k: result)
|
||||
engine.cmd_kp(args)
|
||||
expected = engine.swe.julday(2000, 1, 2, 3 + 4 / 60 + 5 / 3600 - 5.5)
|
||||
assert seen['jd'] == expected and seen['jd'] != round(expected, 6)
|
||||
assert seen['house_cusps'] == raw_cusps
|
||||
assert seen['planets']['Sun']['degree'] == 1.234567891
|
||||
assert seen['planets']['Moon']['degree'] == 42.987654321 % 30
|
||||
assert seen['house_occupancy_basis'] == 'cusp_to_cusp'
|
||||
Reference in New Issue
Block a user