feat(bhava-bala): reports use the formal three components; local +2/-1.5 score hidden (T4, BUG-1210)

Astrologer ruling 甲13. shadbala.calc_bhava_bala renamed calc_local_bhava_score and
removed from calc_shadbala's result (it fed the report's Bhava Bala table). New
bhava_bala.bhava_bala_from_chart (Bhavadhipati = lord's Shadbala virupas, Bhava
Dig, Bhava Drishti; equal houses as /api/bhava_bala; total and total_rupas; the
module's invented level bands not shown) drives modules.bhava_bala in the full
reading. Reader table: Bhavadhipati | Dig | Drishti | Total (Virupa) | Total
(Rupa); reference edition table and wealth/summary lines read the formal totals.
Other users of the local score: none outside shadbala.py (remedies and health
narrative read Shadbala rupas only).

Changed assertions (three columns in PROGRESS): test_shadbala_complete local-score
tests renamed; test_report_longform_gaps2 fixture rows and heading.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
Jesse_Chen
2026-10-03 12:45:58 +08:00
co-authored by Claude Opus 5.5
parent ea78804b78
commit 6feb1a4aaa
7 changed files with 160 additions and 41 deletions
+41
View File
@@ -244,3 +244,44 @@ def calc_bhava_bala(house_signs: List[str], house_degrees: List[float],
'strongest_house': max(houses, key=lambda h: h['total'])['house'],
'weakest_house': min(houses, key=lambda h: h['total'])['house'],
}
def bhava_bala_from_chart(planets: Dict, asc_sign: str, asc_degree: float, shadbala_planets: Dict) -> Dict:
"""Formal three-component Bhava Bala for one D1 chart (BUG-1210, ruling 甲13).
`planets` rows carry `sign` and a degree (`degree_in_sign`, `degree` or a
longitude); `shadbala_planets` is `shadbala.calc_shadbala(...)['planets']`,
whose `total_virupas` is each lord's Shadbala (Bhavadhipati Bala). Houses are
equal houses from the Lagna degree, as `/api/bhava_bala` uses. Totals are in
Virupas; `total_rupas` = total / 60. The `level` bands of `calc_bhava_bala`
are not a classical scale and are not displayed.
"""
if asc_sign not in SIGNS:
return {}
asc_idx = SIGNS.index(asc_sign)
house_signs = [SIGNS[(asc_idx + i) % 12] for i in range(12)]
house_degrees = [float(asc_degree) % 30 for _ in range(12)]
positions = {}
for name, row in (planets or {}).items():
if not isinstance(row, dict) or row.get('sign') not in SIGNS:
continue
degree = row.get('degree_in_sign')
if degree is None:
degree = row.get('degree', 0)
positions[name] = {'sign': row['sign'], 'degree': float(degree or 0) % 30}
virupas = {}
for name, row in (shadbala_planets or {}).items():
value = row.get('total_virupas') if isinstance(row, dict) else None
if isinstance(value, (int, float)):
virupas[name] = float(value)
if len(virupas) < 7:
return {}
result = calc_bhava_bala(house_signs, house_degrees, asc_sign, float(asc_degree) % 30, positions, virupas)
for house in result['houses']:
house['lord'] = SIGN_LORDS.get(house['sign'])
house['total_rupas'] = round(house['total'] / 60.0, 2)
house.pop('level', None)
result['method'] = 'Bhava Bala 三分量:Bhavadhipati(宫主 Shadbala)+ Bhava Dig + Bhava Drishti(jyotishganit MIT 算法,等宫)'
result['unit'] = 'virupa'
result['source'] = 'scripts/bhava_bala.py'
return result