年运附表补上整宫、Tripataki 和特殊点公式轨迹。黄经沿用已算好的星盘,不改原有 Saham 数值。

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jesse-ux
2026-10-22 23:11:48 +08:00
co-authored by Grok (agent loop) Cursor
parent 6b906f85c4
commit 9b2e6aa0b4
9 changed files with 560 additions and 23 deletions
+117
View File
@@ -0,0 +1,117 @@
"""T6: whole-sign annual houses, Tripataki, and Saham traces use our longitudes."""
from __future__ import annotations
import json
from datetime import datetime
from scripts.annual_native.annual_houses import build_annual_whole_sign_houses
from scripts.annual_native.tripataki_chakra import build_tripataki_chakra
from scripts.jyotish_engine import compute_chart_data
from scripts.report_render.parity_chapters import render_parity_chapters
from scripts.tajika import calc_all_sahams
from tests.report_english_fictional import fictional_case
LIMIT = 1e-6
def _delta(left: float, right: float) -> float:
return abs(((left - right + 180.0) % 360.0) - 180.0)
def _chart():
birth = fictional_case(0)
chart, *_rest = compute_chart_data(
birth["year"], birth["month"], birth["day"], birth["hour"], birth["minute"],
birth["lat"], birth["lon"], birth["tz"],
node_mode=birth["node_mode"], second=birth["second"], ayanamsa_name=birth["ayanamsa"],
)
return birth, chart
def test_new_longitudes_match_the_chart() -> None:
_birth, chart = _chart()
houses = build_annual_whole_sign_houses(chart)
assert houses["status"] == "partial_verified"
assert houses["house_system"] == "whole_sign"
assert len(houses["houses"]) == 12
raw = {
name: float(chart["planets"][name]["degree_raw"]) % 360.0
for name in ("Sun", "Moon")
}
for name, longitude in raw.items():
assert _delta(houses["source_longitudes"][name], longitude) <= LIMIT
asc = float(chart["ascendant"]["degree_raw"])
tripataki = build_tripataki_chakra(
{name: data["degree_raw"] for name, data in chart["planets"].items() if isinstance(data, dict) and "degree_raw" in data},
asc,
)
assert tripataki["status"] == "partial_verified"
for name, longitude in raw.items():
assert _delta(tripataki["source_longitudes"][name], longitude) <= LIMIT
sun = next(row for row in tripataki["placements"] if row["body"] == "Sun")
assert _delta(sun["longitude"], raw["Sun"]) <= LIMIT
def test_saham_traces_keep_the_stored_longitude() -> None:
birth, chart = _chart()
asc = chart["ascendant"]
asc_lon = float(asc.get("lon") if isinstance(asc.get("lon"), (int, float)) else asc["degree_raw"])
planet_lons = {
name: float(data.get("degree", data["degree_raw"]))
for name, data in chart["planets"].items()
if isinstance(data, dict) and "degree" in data
}
result = calc_all_sahams(
planet_lons,
asc_lon,
datetime(birth["year"], birth["month"], birth["day"], birth["hour"], birth["minute"]),
lat=birth["lat"],
lon=birth["lon"],
tz=birth["tz"],
)
assert result.get("status") != "blocked"
traces = result["formula_traces"]
assert len(traces) >= 30
for trace in traces:
assert trace["longitude"] == result[trace["key"]]["longitude"]
without = {key: value for key, value in result.items() if key != "formula_traces"}
assert len(json.dumps(without, ensure_ascii=False, default=str)) > 800
is_day = result["daynight_evidence"]["is_daytime"]
karya = next(item for item in traces if item["key"] == "karya_saham")
first, second = (("Moon", "Mars") if is_day else ("Mars", "Moon"))
expected = round((asc_lon + planet_lons[second] - planet_lons[first]) % 360.0, 4)
assert karya["longitude"] == expected
assert karya["rule"] == f"Asc + {second} - {first}"
def test_four_sections_render_in_both_languages() -> None:
packet = {
"worksheets": {
"advanced_systems": {"sahams": {"formula_traces": [
{"name": "Punya Saham", "key": "punya_saham", "rule": "Asc + Moon - Sun", "phase": "day", "longitude": 12.5},
]}},
"timing_and_predictive_systems": {"annual_tajika_pack": {
"annual_houses": {"houses": [
{"house": 1, "sign": "Aries", "lord": "Mars", "occupants": []},
]},
"tripataki_chakra": {
"placements": [{"body": "Sun", "sign": "Leo", "degree_in_sign": 1.25, "longitude": 121.25}],
"vedha_rows": [{"target": "Sun", "available_sources": ["Moon"], "status": "partial_verified"}],
},
"sahams": {"data": {"formula_traces": [
{"name": "Vivah Saham", "key": "vivah_saham", "rule": "Asc + Venus - Mars", "phase": "night", "longitude": 40.0},
]}},
}},
}
}
chinese = render_parity_chapters(packet, "zh")
english = render_parity_chapters(packet, "en")
assert "年运整宫框架" in chinese and "无" in chinese
assert "Annual Return House Framework" in english and "None" in english
assert "Tripataki 轮盘明细" in chinese and "Tripataki Chakra Detail" in english
assert "年度特殊点公式轨迹" in chinese and "夜间" in chinese
assert "Annual Saham Formula Trace" in english and "Night" in english
assert "本命特殊点公式轨迹" in chinese and "日间" in chinese
assert "Natal Saham Formula Trace" in english and "Day" in english
assert "blocked" not in chinese.lower()