feat(functional): adopt upstream BPHS ch.34 profile v2; fix Pancha Mahapurusha self-conjunction; yoga engine reads the same functional roles

Ported verbatim from the upstream skill repo (yinduzhanxing e9beae6b) with
product authorization 2026-10-02: scripts/functional_benefics.py,
scripts/pancha_mahapurusha.py, references/functional-role-profile.md; only
the two functional-role methods of scripts/yoga_engine.py (our file diverged).
v5 77-case rectification eval: 5 cells up (to +7.8pp), one cell -1.3pp (one
case); product accepted. Rectification memoization golden still to be
regenerated (scores change with the grouping).

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-02 10:57:14 +08:00
co-authored by Claude Opus 5.5
parent f85794661b
commit 57782aea8a
5 changed files with 117 additions and 60 deletions
+13 -30
View File
@@ -391,38 +391,21 @@ class YogaContext:
# --- Functional Malefic / Benefic(基于月亮盈亏和宫主关系) ---
def functional_malefics(self) -> List[str]:
"""
Return functional malefics for this chart.
Rules (per PyJHora/B.V. Raman):
- Lords of 3, 6, 8, 11, 12 are functional malefics
- Mercury is malefic if conjunct with malefic
- Moon is malefic if waning (Krishna Paksha)
"""
fm = []
dusthana_lords = [self.lord_of_house(h) for h in [3, 6, 8, 11, 12]]
fm.extend([l for l in dusthana_lords if l])
# Mercury becomes functional malefic if conjunct with natural malefic
if 'Mercury' in self.planets:
merc_h = self.house_of('Mercury')
merc_conj_malefic = any(
m in self.planets and self.house_of(m) == merc_h
for m in ['Mars', 'Saturn', 'Rahu', 'Ketu', 'Sun']
)
if merc_conj_malefic and 'Mercury' not in fm:
fm.append('Mercury')
# Waning Moon is functional malefic
if self.is_waning_moon() and 'Moon' in self.planets and 'Moon' not in fm:
fm.append('Moon')
return list(set(fm))
"""Ownership roles only; natural nature is a separate rule predicate."""
try:
from .functional_benefics import derive_functional_benefic_malefic
except ImportError:
from functional_benefics import derive_functional_benefic_malefic
return derive_functional_benefic_malefic(self.ascendant)['functional_malefics']
def functional_benefics(self) -> List[str]:
"""Return functional benefics = all planets minus functional malefics minus natural malefics."""
fm = set(self.functional_malefics())
nm = set(MALEFICS)
return [p for p in ALL_PLANETS if p in self.planets and p not in fm and p not in nm]
"""Use the same named ownership profile as the API and report."""
try:
from .functional_benefics import derive_functional_benefic_malefic
except ImportError:
from functional_benefics import derive_functional_benefic_malefic
benefics = derive_functional_benefic_malefic(self.ascendant)['functional_benefics']
return [p for p in benefics if p in self.planets]
# --- Shashtiamsa / Vaiseshikamsa 简化评分 ---
def is_shashtiamsa_evil(self, planet: str) -> bool: