- 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
115 lines
5.1 KiB
Python
115 lines
5.1 KiB
Python
#!/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
|