From 9d3f59a87206d4b7f6c10f94c56565bbd98089a6 Mon Sep 17 00:00:00 2001 From: jesse-ux Date: Wed, 28 Oct 2026 09:45:06 +0800 Subject: [PATCH] fix(tithi): use the source lord order (BUG-1473, upstream 33537b31) Tithi lords follow tithi_seed. No new scripts/tithi_ashtottari.py. Upstream source tests passed. Co-Authored-By: Grok (agent loop) --- scripts/tithi_lord.py | 34 +++++++++++++------ .../test_upstream_sync9_tithi_lord_source.py | 34 +++++++++++++++++++ 2 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 tests/test_upstream_sync9_tithi_lord_source.py diff --git a/scripts/tithi_lord.py b/scripts/tithi_lord.py index 2d5fd8c2..1c3da33e 100644 --- a/scripts/tithi_lord.py +++ b/scripts/tithi_lord.py @@ -8,6 +8,14 @@ Tithi(月日)是月亮与太阳的黄经差除以12°,共30个 Tithi(阴 import math +if __package__: + from .research_timing.cycles import tithi_seed +else: + try: + from research_timing.cycles import tithi_seed + except ImportError: + from scripts.research_timing.cycles import tithi_seed + # Tithi 名称(1-15 Shukla 盈,1-15 Krishna 亏) TITHI_NAMES = { 1: "Pratipad (1)", 2: "Dvitiya (2)", 3: "Tritiya (3)", 4: "Chaturthi (4)", @@ -16,15 +24,12 @@ TITHI_NAMES = { 13: "Trayodashi (13)", 14: "Chaturdashi (14)", 15: "Purnima/Amavasya (15)", } -# Tithi 守护星(Parashara 系统) -# 1=Sun, 2=Moon, 3=Mars, 4=Mercury, 5=Jupiter, 6=Venus, 7=Saturn -# Tithi 1-7: Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn -# Tithi 8-14: Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn -# Tithi 15 (Purnima/Amavasya): Sun +# PVR Integrated Approach table 3: Shukla mapping. Krishna 15 is Rahu, +# not Saturn; get_tithi_lord shares the existing thirty-day tithi_seed rule. TITHI_LORD_MAP = { 1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, - 8: 0, 9: 1, 10: 2, 11: 3, 12: 4, 13: 5, 14: 6, - 15: 0, + 8: 7, 9: 0, 10: 1, 11: 2, 12: 3, 13: 4, 14: 5, + 15: 6, } # 逆映射:行星索引 → 名称 @@ -62,11 +67,14 @@ def calc_tithi(sun_deg, moon_deg): def get_tithi_lord(tithi_num, paksha): """ 获取 Tithi 的守护星。 - Tithi 1-15 的守护星在阴阳月中是一样的(Parashara 系统)。 + PVR table 3;满月土星,新月罗睺,其余阴阳月对应一致。 """ - # Tithi 1-15 的守护星(阴阳月相同) - lord_idx = TITHI_LORD_MAP[tithi_num] - return lord_idx, PLANET_NAMES[lord_idx] + if type(tithi_num) is not int or not 1 <= tithi_num <= 15: + raise ValueError('tithi_num must be integer 1..15 within the paksha') + if paksha not in ('Shukla', 'Krishna'): + raise ValueError('paksha must be Shukla or Krishna') + name = tithi_seed(tithi_num + (15 if paksha == 'Krishna' else 0)) + return PLANET_NAMES.index(name), name def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None): @@ -122,6 +130,8 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None): 15: 'Purnima(满月/新月,能量极点)', } special_note = special_tithis.get(tithi_num) + if tithi_num == 15: + special_note = 'Purnima(满月)' if paksha == 'Shukla' else 'Amavasya(新月)' # Tithi 适忌活动表(完整版) tithi_activities = _get_tithi_activities(tithi_num, paksha) @@ -140,6 +150,7 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None): "tithi_deg_in": round(tithi_deg, 2), "tithi_lord_idx": lord_idx, "tithi_lord_name": lord_name, + "tithi_lord_source": "PVR Integrated Approach table 3, file page 24; shared thirty-tithi ruler table", "raw_diff_deg": round(raw_diff, 2), # v7.0 新增 "tithi_class": tithi_class, @@ -181,6 +192,7 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None): 4: "Tithi Lord 为木星:智慧、导师、扩张、幸运。木星强则有人生指引。", 5: "Tithi Lord 为金星:享乐、艺术、关系、舒适。金星强则生活有质量。", 6: "Tithi Lord 为土星:纪律、延迟、责任、苦行。土星强则能承受压力。", + 7: "Tithi Lord 为罗睺(PVR Table 3);应结合罗睺的本命位置与关联星综合判断。", } result["tithi_lord_interpretation"] = interpretations.get(lord_idx, "") diff --git a/tests/test_upstream_sync9_tithi_lord_source.py b/tests/test_upstream_sync9_tithi_lord_source.py new file mode 100644 index 00000000..603e6f12 --- /dev/null +++ b/tests/test_upstream_sync9_tithi_lord_source.py @@ -0,0 +1,34 @@ +import pytest + +from scripts.tithi_lord import calc_tithi_lord_full, get_tithi_lord + + +# PVR table 3, file p24. Independent explicit source expectation. +EXPECTED = ('Sun Moon Mars Mercury Jupiter Venus Saturn Rahu Sun Moon Mars Mercury Jupiter Venus Saturn ' + 'Sun Moon Mars Mercury Jupiter Venus Saturn Rahu Sun Moon Mars Mercury Jupiter Venus Rahu').split() + + +@pytest.mark.parametrize('number,lord',list(enumerate(EXPECTED,1))) +def test_all_thirty_report_rulers_and_angular_boundaries(number,lord): + at_start=calc_tithi_lord_full(0,(number-1)*12) + just_before_end=calc_tithi_lord_full(0,number*12-1e-7) + for result in (at_start,just_before_end): + assert result['tithi_absolute']==number + assert result['tithi_lord_name']==lord + + +def test_new_and_full_moon_differ_and_chart_link_follows_correct_lord(): + full=calc_tithi_lord_full(0,174) + new=calc_tithi_lord_full(0,354,{'Rahu':{'sign':'Taurus','house':2}}, {}) + assert full['tithi_lord_name']=='Saturn' + assert new['tithi_lord_name']=='Rahu' + assert full['special_note'] != new['special_note'] + assert new['tithi_lord_sign']=='Taurus' + assert new['tithi_lord_house']==2 + assert new['tithi_lord_interpretation'] + assert calc_tithi_lord_full(0,360)['tithi_absolute']==1 + + +@pytest.mark.parametrize('number,paksha',[(True,'Shukla'),(0,'Shukla'),(16,'Krishna'),(1,'unknown')]) +def test_invalid_seed_is_not_silently_accepted(number,paksha): + with pytest.raises(ValueError):get_tithi_lord(number,paksha)