diff --git a/CHANGELOG.md b/CHANGELOG.md index d9f4e5f9..0f6be48c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ # 印度占星 Skill 更新日志 +## v6.0.23-full-reading-regression(2026-06-04)—— full-reading 残余错误清零 + +> **目标**:修复 v6.0.22 后 full-reading 抽查中遗留的 4 个旧模块接入错误,使完整链路输出 `errors=0`。 + +### 变更内容 + +- `scripts/jyotish_engine.py`: + - 新增 full-reading 内部 `_build_whole_sign_houses()` 兼容适配器,将 `compute_chart_data()` 的 `house_1...house_12` 结构转换为旧附加模块期望的 `1..12` / `"1".."12"` / `Hn_Lord` 混合结构。 + - 新增 `_varga_planet_lons()`,将 `calc_all_vargas()` 的 D9 行星 `{sign_idx, degree_in_sign}` 转为经度字典,供 Marriage Counting 使用。 + - 修复 full-reading 中 Tithi Lord / Pancha Pakshi 对 `planet_lons` 的错误数字索引访问,改为按 `'Sun'` / `'Moon'` 键访问。 + - 修复 Marriage Counting 对 D9 数据结构的误判,不再要求不存在的 `d9_data['planets']`。 +- `scripts/yogas_doshas.py`:修复 summary 变量名 `total_yoga_count` → `total_yogas_count`。 +- `scripts/tithi_lord.py`:兼容 `{planet_name: data}` 行星字典,Tithi Lord 现在能正确读取 sign/house/status。 +- `scripts/marriage_counting.py`:修正 Parivartana 判断,行星落入自己掌管的星座不再误判为行星交换。 + +### 回归验证 + +- `py_compile` 通过:`yogas_doshas.py` / `tithi_lord.py` / `pancha_pakshi.py` / `marriage_counting.py` / `jyotish_engine.py`。 +- `audit_capabilities.py --mode validate` 通过:44 techniques(missing=0, partial=18, covered=26)。 +- `full-reading` 实盘抽查:45 modules computed,`errors=0`,`status=complete`。 +- `diff --check` 通过。 + ## v6.0.22-nakshatra-advanced(2026-06-04)—— Nakshatra Advanced 星宿进阶实现 > **目标**:补齐 Nakshatra Advanced 缺口,将星宿层从静态详情扩展为 Tara Bala + Chandra Bala + Nakshatra Dasha + Transit Overlay 的完整计算层。 diff --git a/SKILL.md b/SKILL.md index b3a8a6ba..f5eca688 100644 --- a/SKILL.md +++ b/SKILL.md @@ -10,7 +10,7 @@ description: 印度占星(Jyotish)专业解盘与推运系统。核心能力 > **严格路由**:`references/strict-workflow-router.md`(⭐涉及事业/婚恋/财务/应期/技法验证时必须优先读取) > **覆盖矩阵**:`references/technique-capability-matrix.md`(⭐判断技法 covered/partial/missing 时必须参考) > **机器注册表**:`references/technique_registry.json` + `scripts/audit_capabilities.py`(⭐用于自动审计与CI门禁) -> **版本**:v6.0.22-nakshatra-advanced | **详细变更**:`CHANGELOG.md` +> **版本**:v6.0.23-full-reading-regression | **详细变更**:`CHANGELOG.md` --- @@ -301,9 +301,9 @@ $PYTHON $SCRIPT <子命令> [参数] --- -**版本**:v6.0.22-nakshatra-advanced +**版本**:v6.0.23-full-reading-regression **创建日期**:2026-04-20 -**最后更新**:2026-06-04(v6.0.22 新增 Nakshatra Advanced:Chandra Bala、Nakshatra Dasha、Transit Overlay) +**最后更新**:2026-06-04(v6.0.23 修复 full-reading 残余模块接入错误,实盘抽查 errors=0) --- diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index 30c61ab6..dde5bae6 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -3168,6 +3168,44 @@ def cmd_full_reading(args): import time t0 = time.time() + def _build_whole_sign_houses(asc_index, planets_data): + """Build a compatibility house map for add-on modules. + + compute_chart_data() exposes Placidus/equal-style cusp keys (house_1...), + while several v6.0.14-16 add-on modules expect 1..12 keys plus Hn_Lord. + This adapter keeps those modules wired without changing their public API. + """ + house_map = {} + for house_num in range(1, 13): + sign_idx = (asc_index + house_num - 1) % 12 + sign_name = SIGNS[sign_idx] + house_map[house_num] = { + 'sign': sign_name, + 'lord': SIGN_LORDS.get(sign_name, ''), + 'planets': [], + 'strength': 'Neutral', + } + house_map[str(house_num)] = house_map[house_num] + house_map[f'H{house_num}_Lord'] = house_map[house_num]['lord'] + for planet_name, planet_data in planets_data.items(): + if isinstance(planet_data, dict): + house_num = planet_data.get('house') + if isinstance(house_num, int) and house_num in house_map: + house_map[house_num]['planets'].append(planet_name) + return house_map + + def _varga_planet_lons(varga_chart): + """Convert calc_all_vargas() planet sign/degree data to longitude dict.""" + lons = {} + if not isinstance(varga_chart, dict): + return lons + for planet_name, planet_data in varga_chart.items(): + if planet_name.startswith('_') or planet_name == 'Ascendant': + continue + if isinstance(planet_data, dict) and 'sign_idx' in planet_data: + lons[planet_name] = planet_data['sign_idx'] * 30 + planet_data.get('degree_in_sign', 0) + return lons + report = { 'version': '4.4.0-full-reading', 'birth_info': { @@ -3195,6 +3233,8 @@ def cmd_full_reading(args): asc_sign = chart.get('ascendant', {}).get('sign', 'Unknown') planet_lons = {pn: pd.get('degree_raw', pd['degree']) for pn, pd in planets.items() if isinstance(pd, dict) and 'degree' in pd} planet_degs = {pn: pd.get('degree_in_sign_raw', pd.get('degree_in_sign', pd['degree'] % 30)) for pn, pd in planets.items() if isinstance(pd, dict) and 'degree' in pd} + houses = _build_whole_sign_houses(asc_idx, planets) + report['modules']['house_map'] = houses planet_sign_indices = {} for pn, pd in planets.items(): if isinstance(pd, dict) and 'sign' in pd: @@ -3498,8 +3538,8 @@ def cmd_full_reading(args): try: # Tithi Lord(出生 Tithi + Lord 分析) from tithi_lord import calc_tithi_lord_full - sun_deg = planet_lons[0] - moon_deg = planet_lons[1] + sun_deg = planet_lons.get('Sun', 0) + moon_deg = planet_lons.get('Moon', 0) tithi_result = calc_tithi_lord_full(sun_deg, moon_deg, planets, houses) report['modules']['tithi_lord'] = tithi_result except Exception as e: @@ -3512,7 +3552,7 @@ def cmd_full_reading(args): if 'moon_nakshatra' in dir() or 'moon_nak' in locals(): pass # 动态获取 # 从 planets 数据推算 Nakshatra(Moon 的度数为基准) - moon_deg = planet_lons[1] + moon_deg = planet_lons.get('Moon', 0) nak_num = int(moon_deg / 13.3333333) + 1 if nak_num > 27: nak_num = 27 @@ -3549,10 +3589,11 @@ def cmd_full_reading(args): d1_house7_lord = houses.get('7', {}).get('lord', '') if isinstance(houses.get('7'), dict) else '' if d1_house7_lord and 'varga_full' in report['modules']: d9_data = report['modules']['varga_full'].get('D9_Navamsa', {}) - if d9_data.get('planets'): + d9_planet_lons = _varga_planet_lons(d9_data) + if d9_planet_lons: mc_result = marriage_counting_full_analysis( - d1_house7_lord, planet_lons, d9_data['planets'], - houses, d9_data.get('houses') + d1_house7_lord, planet_lons, d9_planet_lons, + houses, None ) report['modules']['marriage_counting'] = mc_result except Exception as e: diff --git a/scripts/marriage_counting.py b/scripts/marriage_counting.py index 5704d252..4d95ab29 100644 --- a/scripts/marriage_counting.py +++ b/scripts/marriage_counting.py @@ -135,7 +135,11 @@ def _check_parivartana( SIGN_LORDS = ['Mars','Venus','Mercury','Moon','Sun','Mercury', 'Venus','Mars','Jupiter','Saturn','Saturn','Jupiter'] host = SIGN_LORDS[lord_sign] # lord 落入星座的主星 - + + # 落在自己掌管的星座不是 Parivartana(行星交换),只是 own-sign 状态。 + if host == lord: + return {'has_parivartana': False, 'reason': f'{lord} 位于自己掌管的星座,不构成 Parivartana'} + if host not in d1_planet_lons: return {'has_parivartana': False, 'reason': f'{host} 位置未知'} diff --git a/scripts/tithi_lord.py b/scripts/tithi_lord.py index c4d65ed1..dccc8530 100644 --- a/scripts/tithi_lord.py +++ b/scripts/tithi_lord.py @@ -95,13 +95,18 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None): lord_house = None lord_dignity = None - # 从 planets 字典里找 Tithi Lord 的数据 - # planets 格式:{0: {sign, house, dignity,...}, 1: {...}, ...} + # 从 planets 字典里找 Tithi Lord 的数据。 + # 兼容两种格式:{0: {...}, 1: {...}} 或 {'Sun': {...}, 'Moon': {...}} + lord_data = None if lord_idx in planets: lord_data = planets[lord_idx] + elif lord_name in planets: + lord_data = planets[lord_name] + + if isinstance(lord_data, dict): lord_sign = lord_data.get("sign") lord_house = lord_data.get("house") - lord_dignity = lord_data.get("dignity") + lord_dignity = lord_data.get("dignity") or lord_data.get("status") result["tithi_lord_sign"] = lord_sign result["tithi_lord_house"] = lord_house diff --git a/scripts/yogas_doshas.py b/scripts/yogas_doshas.py index fbe6e54c..9e3802a8 100644 --- a/scripts/yogas_doshas.py +++ b/scripts/yogas_doshas.py @@ -614,7 +614,7 @@ def calc_all_yogas_doshas(planets_data: Dict, houses: Dict, ]) results['summary'] = ( - f"Yogas共{total_yoga_count}个;" + f"Yogas共{total_yogas_count}个;" f"Doshas: Mangal={'有' if results['mangal_dosha']['has_dosha'] else '无'}" f"/Kaal Sarp={'有' if results['kaal_sarp_dosha']['has_dosha'] else '无'}" f"/Pitra={'有' if results['pitra_dosha']['has_dosha'] else '无'}"