Files
Jyotisha/scripts/shadbala_display.py
T
ClaudeandClaude Opus 5.5 5d64f71b81 fix: astrologer round-5 rulings 2/3/4/5/10/13 (BUG-1746..1752)
- Functional default = PVR Table 30 (functional_profile=pvr_table_30); the former
  product table is bphs_exception_profile, scored only when named (rectification
  names it, scores unchanged). profile_divergence shows both roles side by side;
  movable-lagna Moon by the table's paksha note; dual-lordship note; prior rulings
  BUG-1570/1590/#166 Q4 checked against Table 30.
- Shadbala: six open items labelled parameter_sensitive; every option combination
  computed; only planets whose pass/fail flips get minimum_check=parameter_sensitive.
- Vimshottari AD/PD rows carry parent_period_start / visible_period_start; the
  consult card cuts the balance MD from its full parent and clips at birth.
- KP DBA: full first parent, clipped at birth (no balance rescale).
- Mudda: balance fields + balance_method (angle default, time comparison apart),
  nominal_year_days, her crossing wording; Harsha combined blocked reason lists items.
- D30 _meta describes the unequal parts (as her r40).
- Golden recaptured with TTL=0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-08 11:57:22 +08:00

115 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""How a Shadbala strength is shown (astrologer rulings 2026-10-03 甲13, BUG-1208).
First whether the planet meets the BPHS minimum (BPHS ch. 27 vv. 32-33, the
`shadbala.MIN_REQUIRED` table), then the site's own band (150/125/100/75/50 % of
that minimum -> 极强…极弱), labelled as the site's band. `shadbala.py` is in the
frozen rectification identity, so the fields are added here, at display time,
from values the engine already returns; nothing is recomputed.
"""
from __future__ import annotations
from typing import Any, Dict, Optional
LEVEL_SOURCE = 'site_band'
SITE_BAND_SUFFIX = '(网站分档)'
SITE_BAND_SUFFIX_EN = ' (site band)'
MEETS_ZH = '达到 BPHS 最低要求'
MISSES_ZH = '未达到 BPHS 最低要求'
MEETS_EN = 'meets the BPHS minimum'
MISSES_EN = 'below the BPHS minimum'
def _number(value: Any) -> Optional[float]:
return float(value) if isinstance(value, (int, float)) and not isinstance(value, bool) else None
def minimum_fields(rupas: Any, min_required: Any, band: Any) -> Dict[str, Any]:
"""`min_required`, `meets_minimum`, `minimum_check`, band label and source."""
total = _number(rupas)
minimum = _number(min_required)
meets = None if total is None or minimum is None else total >= minimum
fields: Dict[str, Any] = {
'min_required': minimum,
'meets_minimum': meets,
'minimum_check': None if meets is None else (MEETS_ZH if meets else MISSES_ZH),
'level_source': LEVEL_SOURCE,
}
if band not in (None, ''):
fields['level'] = f'{band}{SITE_BAND_SUFFIX}'
return fields
PARAMETER_SENSITIVE = 'parameter_sensitive'
def row_fields(row: Dict[str, Any]) -> Dict[str, Any]:
"""Display fields for one `shadbala.calc_shadbala` planet row.
占星师 2026-11-08 第五轮裁定 4: when `shadbala_service.sensitivity` found that the open
parameter choices flip the planet's pass/fail, `minimum_check` is
`parameter_sensitive` (the default verdict stays in `minimum_check_default`)
and the open questions that flip it are listed.
"""
fields = minimum_fields(row.get('total_rupas', row.get('rupas')), row.get('min_required'), row.get('strength_level'))
sensitivity = row.get('parameter_sensitivity') if isinstance(row.get('parameter_sensitivity'), dict) else {}
if row.get('minimum_check_status') == PARAMETER_SENSITIVE and fields.get('minimum_check'):
fields['minimum_check_default'] = fields['minimum_check']
fields['minimum_check'] = PARAMETER_SENSITIVE
fields['minimum_open_questions'] = list(sensitivity.get('open_questions') or [])
elif row.get('minimum_check_status'):
fields['minimum_check_status'] = row['minimum_check_status']
return fields
BAND_EN = {'极强': 'very strong', '强': 'strong', '充足': 'adequate', '略弱': 'slightly weak', '弱': 'weak', '极弱': 'very weak'}
def band_text(band: Any, language: str = 'zh') -> Optional[str]:
if band in (None, ''):
return None
if language == 'en':
return f"{BAND_EN.get(str(band), str(band))}{SITE_BAND_SUFFIX_EN}"
return f'{band}{SITE_BAND_SUFFIX}'
def check_text(meets: Optional[bool], language: str = 'zh') -> str:
if meets is None:
return '-'
if language == 'en':
return MEETS_EN if meets else MISSES_EN
return MEETS_ZH if meets else MISSES_ZH
SENSITIVE_ZH = 'parameter_sensitive(是否达到 BPHS 最低要求取决于未定 Shadbala 参数,不据此下好坏结论)'
SENSITIVE_EN = 'parameter_sensitive (whether the BPHS minimum is met depends on open Shadbala parameters; no good/bad conclusion)'
def row_check_text(row: Dict[str, Any], language: str = 'zh') -> str:
"""`check_text` for a whole row: parameter_sensitive wins over the default verdict (第五轮裁定 4)."""
if isinstance(row, dict) and row.get('minimum_check_status') == PARAMETER_SENSITIVE:
return SENSITIVE_EN if language == 'en' else SENSITIVE_ZH
return check_text(row_fields(row)['meets_minimum'] if isinstance(row, dict) else None, language)
REQUIRED_STRENGTH_SEMANTICS = 'deprecated_alias_of_required_strength_pct_not_ishta_phala'
def attach_required_strength_alias(result: Any) -> Any:
"""Add `required_strength_pct` beside `ishta_bala_pct` on every planet row, in place.
产品 2026-11-07 同步占星师交接分支 99076dad:`ishta_bala_pct` 是总 Rupa ÷ BPHS 最低
要求 × 100(达标比),不是 Ishta Phala。她在 `shadbala.calc_shadbala` 里加了明确名
`required_strength_pct` 和别名说明 `ishta_bala_pct_semantics`;本仓 `shadbala.py`
在冻结身份里(BUG-1699 测试),所以同名字段在这里补,值照抄、不重算。
"""
planets = result.get('planets') if isinstance(result, dict) else None
if not isinstance(planets, dict):
return result
for row in planets.values():
if isinstance(row, dict) and _number(row.get('ishta_bala_pct')) is not None:
row.setdefault('required_strength_pct', row['ishta_bala_pct'])
row.setdefault('ishta_bala_pct_semantics', REQUIRED_STRENGTH_SEMANTICS)
return result