fix(yoga): Neecha Bhanga lists the conditions that hold, never Raja Yoga (T8, BUG-1205)

Astrologer ruling 乙14. One condition source, yogas_doshas.calc_nicha_bhanga_raj_yoga
(conditions A-F, now also structured). New scripts/main_yoga_detectors.py turns it
into yoga_engine-shaped rows (zh + en twins) that YogaEngine.detect appends; the
four neechabhanga_* rules are reference_only (kept, renamed, not evaluated).
Card: traditional_yogas canonical 落陷取消(Neecha Bhanga) with 成立条件; compact
yoga entries keep conditions/reductions. Report: category 落陷取消, mixed group,
not raja; personal-report alias neecha_bhanga -> special.

Changed assertion (test_consultation_yoga_detection_merge): canonical name
'Neecha Bhanga Raja Yoga' -> '落陷取消(Neecha Bhanga)' (ruling 乙14).

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 11:38:52 +08:00
co-authored by Claude Opus 5.5
parent 0cf2249e6b
commit df21e591e8
10 changed files with 342 additions and 26 deletions
+15 -1
View File
@@ -16,6 +16,11 @@ import json
import os
from typing import Dict, List, Any, Optional
try: # scripts/ on sys.path
from main_yoga_detectors import main_detector_rows
except ImportError: # package import (scripts.yoga_engine)
from scripts.main_yoga_detectors import main_detector_rows
# ============================================================================
# 基础常量(自包含,避免循环导入)
# ============================================================================
@@ -717,7 +722,14 @@ class YogaEngine:
data = json.load(f)
self.schema_version = data.get("schema_version", "1.0")
self.rules = [r for r in data.get("rules", []) if r.get("enabled", True)
and r.get("id") not in RETIRED_RULE_IDS]
and r.get("id") not in RETIRED_RULE_IDS
and not r.get("reference_only")]
# `reference_only` rules stay in the registry with their source and
# logic but are never evaluated: the yoga they name has one main
# detector (scripts/main_yoga_detectors.py; astrologer rulings
# 2026-10-03), whose rows `detect` appends below.
self.reference_only_rule_ids = sorted(
r.get("id") for r in data.get("rules", []) if r.get("reference_only"))
def detect(self, planets: Dict[str, Dict], ascendant: str, context: Optional[Dict] = None) -> List[Dict]:
"""
@@ -774,6 +786,8 @@ class YogaEngine:
# ── 附加算法级 Yoga(不在 rules JSON 中) ──
results += self._detect_solar_lunar_yogas(ctx)
# ── 主检测器(同名 JSON 规则为 reference_only) ──
results += main_detector_rows(ctx.planets, ctx.ascendant)
return results