fix(saham): add 30 degrees when the third operand misses the B-to-A arc

Upstream ce9fed15. The exception now tests C on the forward arc from B to A, in both the value and the trace. BUG-1387.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jesse-ux
2026-10-18 16:44:43 +08:00
co-authored by Grok (agent loop) Cursor
parent aa87c0f127
commit 2f8263b6ac
5 changed files with 78 additions and 13 deletions
+30 -8
View File
@@ -96,14 +96,36 @@ def _calc_formula_saham(
second = _resolve_saham_operand(formula[1], planet_lons, asc_lon, computed)
third = _resolve_saham_operand(formula[2], planet_lons, asc_lon, computed)
result = (third + (first - second)) % 360
# references/saham_rules.json: add one sign when Ascendant is not on the
# forward zodiacal arc from the first formula point to the second.
ascendant_between_points = (
first <= asc_lon <= second
if first <= second
else asc_lon >= first or asc_lon <= second
)
return result if ascendant_between_points else (result + 30.0) % 360
# PVR §28.8.1, p394: in A-B+C, C must lie on the forward arc B -> A.
third_between_points = (third - second) % 360 <= (first - second) % 360
return result if third_between_points else (result + 30.0) % 360
def _formula_saham_trace(
rule_name: str,
planet_lons: Dict[str, float],
asc_lon: float,
is_day: bool,
computed: Dict[str, float],
) -> Dict:
"""Calculate a rule-backed Saham while preserving its sensitive convention."""
rule = _SAHAM_RULES['sahams'][rule_name]
formula = rule['formula_day'] if is_day else rule['formula_night']
first = _resolve_saham_operand(formula[0], planet_lons, asc_lon, computed)
second = _resolve_saham_operand(formula[1], planet_lons, asc_lon, computed)
third = _resolve_saham_operand(formula[2], planet_lons, asc_lon, computed)
base_longitude = (third + (first - second)) % 360
third_between_points = (third - second) % 360 <= (first - second) % 360
exception_applied = not third_between_points
return {
'longitude': (base_longitude + 30.0) % 360 if exception_applied else base_longitude,
'base_longitude': base_longitude,
'rule_name': rule_name,
'formula_operands': formula,
'formula_variant': 'day' if is_day else 'night',
'zodiacal_order_exception_applied': exception_applied,
'rule_source': 'references/saham_rules.json',
}
def calc_muntha(birth_asc_idx: int, age: int) -> Dict: