From 975f00f5f24af02daddfacf489e294d864cd6ae7 Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Fri, 5 Jun 2026 18:00:00 +0800 Subject: [PATCH] fix: improve context-aware yoga precision --- CHANGELOG.md | 49 ++++++++++++++++++++++++++++ SKILL.md | 8 ++--- references/yoga_rules.json | 62 +++++++++++++++++++++++++++++------- scripts/validate_logic_v2.py | 14 +++++--- scripts/yoga_engine.py | 13 ++++++-- 5 files changed, 124 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8603cbb4..7b3a60bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,54 @@ # 印度占星 Skill 更新日志 +## v6.0.37(2026-06-05)—— Context-aware Yoga 精度提升 + +> **目标**:利用 v6.0.36 已接入的 D9/Navamsa、Panchanga、Gulika/Maandi 上下文,继续修复 PyJHora/B.V. Raman 高影响 Yoga 误差,而不是回退到 D1-only 近似。 + +### 规则修复 + +- 拆分 PyJHora 中两个不同函数: + - `kaahala_yoga` → 新增 `bvr_kaahala_yoga`:4宫主与木星互为 Kendra,且上升主有力。 + - `kahala_yoga` 保留原 BVR 逻辑:4宫主与9宫主互为 Kendra,且上升主有力。 +- 新增 `bvr_kapata_yoga`,实现 PyJHora/B.V. Raman 202-204 三个 Kapata 条件,避免继续把 `kapata_yoga_*` 错映射到 `nishkapata`。 +- 修复 `bvr_mathibhramana_yoga`:补入 293 waning Moon/tithi 条件、BVR variation 1-4,包括 D9 中 Mercury/Rahu/6宫主/Mars 的组合。 +- 修复 `bvr_matrunasa_precise`:在 Moon 受凶星夹制/合相/相位基础上,补入 199 的双层 Navamsa dispositor 链落 6/8/12。 +- 修复 `bvr_nishkapata_precise`:补入第4宫为吉性星座、天然吉星、强星、以及上升主入4宫受吉星影响的 205/206 条件。 +- 修复 `bvr_bahu_puthra_precise`:补入 Rahu 在5宫且非 Saturn Navamsa,以及7宫主关联行星的 Navamsa 主落 1/2/5。 +- 调整 `bvr_rogagrastha_precise` 的弱上升主判定,贴近 PyJHora 的 sign-strength 口径。 +- 修正 `vanchana_chora_bheethi` 语义条件:Gulika 在三方不再单独触发,必须符合 PyJHora 条件组合,减少过宽 FP。 + +### 映射修复 + +- `validate_logic_v2.py` 中: + - `kaahala_yoga` 改映射到新增 `bvr_kaahala_yoga`。 + - `kahala_yoga` 显式映射到 `kahala_yoga`。 + - `kapata_yoga_202/203/204` 改映射到新增 `bvr_kapata_yoga`。 + +### 验证结果 + +- `scripts/validate_logic_v2.py`: + - Precision **85.60%**(v6.0.36 为 83.84%) + - Recall **72.38%**(v6.0.36 为 69.64%) + - F1 **78.44%**(v6.0.36 为 76.08%) + - FP:130;FN:295 +- `scripts/run_quality_gate.py --skip-yoga-logic`:通过。 + - pytest **35 passed** + - BPHS/Ashtakavarga 不变量 **18/18** + - golden case 通过 + +### 规则库状态 + +- JSON 规则总数:**475** +- 启用规则:**381** +- 当前验证报告:`references/validation_logic_report.json` + +### 后续优化点 + +- 下一轮优先处理仍在 Top 队列中的:`vanchana_chora_bheethi`、`rogagrastha`、`swaveeryaddhana`、`kaalanirdesat_puthranaasa`、`sankha`、`dehasthoulya`。 +- 建议继续把 PyJHora 的 sign-strength、natural benefics/malefics 与 aspect helper 进一步对齐,减少“同名但判定口径略不同”的残余误差。 + +--- + ## v6.0.36(2026-06-05)—— Yoga 验证数据结构升级与 D9/Panchanga/Upagraha 上下文接入 > **目标**:为继续提升 Yoga 逻辑准确率补齐验证数据层,不再把所有 B.V. Raman / PyJHora 条件硬塞进 D1-only 近似,优先让标准测试集携带 D9/Navamsa、tithi/waning Moon、Gulika/Maandi 等上下文。 diff --git a/SKILL.md b/SKILL.md index 8de3b9cb..48cf24c3 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,6 +1,6 @@ --- name: jyotish-vedic-astrology -version: 6.0.36 +version: 6.0.37 description: 印度占星(Jyotish)专业解盘与推运系统。核心能力:PDF星盘输入→严谨解盘→精确推运应期输出。触发词:印度占星、吠陀占星、Jyotish、解盘、推运、星盘分析、Dasha、Transit、Nakshatra、Yoga、出生时间矫正、PDF星盘、读取PDF、分析PDF星盘、现代解读、误判纠错、Varga分盘、综合分析、过境分析、合盘、婚姻匹配、年运盘、Prashna、Argala、Jaimini、Shadbala、Ashtakavarga、HTML报告、深度解盘。 --- @@ -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.36-yoga-context-fixtures | **详细变更**:`CHANGELOG.md` +> **版本**:v6.0.37-context-aware-yoga-precision | **详细变更**:`CHANGELOG.md` --- @@ -301,9 +301,9 @@ $PYTHON $SCRIPT <子命令> [参数] --- -**版本**:v6.0.36-yoga-context-fixtures +**版本**:v6.0.37-context-aware-yoga-precision **创建日期**:2026-04-20 -**最后更新**:2026-06-05(v6.0.36 将标准 Yoga 验证数据升级为 schema 2.0,加入 D1/D9/Panchanga/Gulika/Maandi 扩展上下文,并让 YogaEngine/validate_logic_v2 接收 context;当前 473 条 JSON 规则、379 条启用规则,D1/Rasi 逻辑验证 F1=76.08%,报告以 `references/validation_logic_report.json` 为准) +**最后更新**:2026-06-05(v6.0.37 基于 D9/Panchanga/Gulika/Maandi context 修复高影响 Yoga,拆分 PyJHora `kaahala_yoga` 与 `kahala_yoga`,新增 Kapata 高置信规则并修正多个 B.V. Raman 条件;当前 475 条 JSON 规则、381 条启用规则,D1/Rasi 逻辑验证 F1=78.44%,报告以 `references/validation_logic_report.json` 为准) --- diff --git a/references/yoga_rules.json b/references/yoga_rules.json index 51d36553..cbfc645b 100644 --- a/references/yoga_rules.json +++ b/references/yoga_rules.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "description": "Yoga 规则库 - 数据驱动架构 v1.0", - "total_rules": 473, + "total_rules": 475, "rules": [ { "id": "raja_yoga", @@ -9081,7 +9081,7 @@ "category": "health", "logic": { "type": "custom", - "expr": "\n# PyJHora BVR-11 exact D1-safe logic: (a) Lagna lord in Lagna joined by\n# dusthana lord; (b) weak Lagna lord joined by any kendra/trine lord.\nasc_lord = lord(1)\ndusthana_lords = [lord(h) for h in [6, 8, 12]]\nquad_trine_lords = [lord(h) for h in [1, 4, 5, 7, 9, 10]]\nif asc_lord not in ctx.planets:\n False\nelse:\n condition_a = house_of(asc_lord) == 1 and any(dl in ctx.planets and same_house(asc_lord, dl) for dl in dusthana_lords)\n condition_b = (not strong(asc_lord)) and any(qtl in ctx.planets and same_house(asc_lord, qtl) for qtl in quad_trine_lords)\n condition_a or condition_b\n", + "expr": "\n# PyJHora BVR-11: (a) Lagna lord in Lagna joined by dusthana lord;\n# (b) weak Lagna lord joined by any kendra/trine lord.\nasc_lord = lord(1)\ndusthana_lords = [lord(h) for h in [6, 8, 12]]\nquad_trine_lords = [lord(h) for h in [1, 4, 5, 7, 9, 10]]\nif asc_lord not in ctx.planets:\n False\nelse:\n condition_a = house_of(asc_lord) == 1 and any(dl in ctx.planets and same_house(asc_lord, dl) for dl in dusthana_lords)\n weak_by_sign = not (exalted(asc_lord) or own(asc_lord) or moola(asc_lord))\n condition_b = weak_by_sign and any(qtl in ctx.planets and same_house(asc_lord, qtl) for qtl in quad_trine_lords)\n condition_a or condition_b\n", "combo_template": "上升主在Lagna合凶宫主,或弱上升主合角/三方主" }, "effects": [ @@ -9301,8 +9301,8 @@ "category": "durbhaga", "logic": { "type": "custom", - "expr": "\n# Moon hemmed, associated, or aspected by evil planets\nif 'Moon' not in ctx.planets:\n False\nelse:\n moon_h = ctx.planets['Moon'].get('house')\n evil = {'Mars', 'Saturn', 'Rahu', 'Ketu', 'Sun'}\n h_prev = ((moon_h - 1 + 10) % 12) + 1\n h_next = ((moon_h - 1 + 1) % 12) + 1\n prev_evil = any(ctx.planets[p].get('house') == h_prev for p in evil if p in ctx.planets)\n next_evil = any(ctx.planets[p].get('house') == h_next for p in evil if p in ctx.planets)\n hemmed = prev_evil and next_evil\n associated = any(same_house('Moon', p) for p in evil if p in ctx.planets)\n aspected = any(aspect(p, 'Moon') for p in evil if p in ctx.planets)\n hemmed or associated or aspected\n", - "combo_template": "月亮受凶星影响" + "expr": "\n# PyJHora/BVR 198-199.\nif 'Moon' not in ctx.planets:\n False\nelse:\n evil = set(MALEFICS)\n moon_h = house_of('Moon')\n prev_h = ((moon_h - 2) % 12) + 1 if moon_h else None\n next_h = (moon_h % 12) + 1 if moon_h else None\n hemmed = bool(prev_h and next_h and house_has_malefic(prev_h) and house_has_malefic(next_h))\n associated = any(same_house('Moon', p) for p in evil if p in ctx.planets)\n aspected = any(aspect(p, 'Moon') for p in evil if p in ctx.planets)\n y198 = hemmed or associated or aspected\n l4 = lord(4)\n nav_lord = navamsa_dispositor(l4) if l4 else None\n final_planet = navamsa_dispositor(nav_lord) if nav_lord else None\n y199 = final_planet in ctx.planets and house_of(final_planet) in [6, 8, 12]\n y198 or y199\n", + "combo_template": "月亮受凶星夹制/合相/相位,或4宫主Navamsa链最终落6/8/12" }, "effects": [ "母亲健康不佳", @@ -9322,8 +9322,8 @@ "category": "auspicious", "logic": { "type": "custom", - "expr": "\n# 4th house occupied by benefic or exalted planet\nbenefics = {'Jupiter', 'Venus', 'Mercury', 'Moon'}\nplanets_in_4 = [p for p, info in ctx.planets.items() if info.get('house') == 4]\nhas_benefic = any(p in benefics for p in planets_in_4)\nhas_exalted = any(exal(p) for p in planets_in_4)\nhas_benefic or has_exalted\n", - "combo_template": "第4宫有吉星或旺星" + "expr": "\n# PyJHora/BVR 205-206 Nishkapata Yoga.\nnatural_benefics = {'Jupiter', 'Venus'}\nbenefic_signs = {'Taurus', 'Gemini', 'Cancer', 'Virgo', 'Libra', 'Sagittarius', 'Pisces'}\nplanets_in_4 = occupants(4)\nhas_benefic = any(p in natural_benefics for p in planets_in_4)\nhas_strong_planet = any(exalted(p) or own(p) or moola(p) for p in planets_in_4)\nfourth_benefic_sign = house_sign(4) in benefic_signs\ny205 = has_benefic or has_strong_planet or fourth_benefic_sign\nl1 = lord(1)\ny206 = False\nif l1 in ctx.planets and house_of(l1) == 4:\n l1_with_benefic = any(p != l1 and same_house(l1, p) for p in natural_benefics if p in ctx.planets)\n l1_aspected_benefic = any(aspect(p, l1) for p in natural_benefics if p in ctx.planets and p != l1)\n y206 = l1_with_benefic or l1_aspected_benefic\ny205 or y206\n", + "combo_template": "第4宫有天然吉星/强星/吉性星座,或上升主入4宫且受吉星影响" }, "effects": [ "心地善良", @@ -9343,8 +9343,8 @@ "category": "putra", "logic": { "type": "custom", - "expr": "\n# 5th lord strong and associated with benefics\nlord_5 = lord(5)\nif lord_5 not in ctx.planets:\n False\nelse:\n benefics = {'Jupiter', 'Venus', 'Mercury', 'Moon'}\n in_kendra_trikona = ctx.planets[lord_5].get('house') in [1, 4, 5, 7, 9, 10]\n associated = any(same_house(lord_5, b) for b in benefics if b in ctx.planets)\n in_kendra_trikona and associated\n", - "combo_template": "5宫主强且与吉星有关联" + "expr": "\n# PyJHora/BVR 220-221 Bahu Puthra Yoga.\n# 220: Rahu in 5th and Rahu is not in Saturn navamsa.\ny220 = house_of('Rahu') == 5 and d9_sign_of('Rahu') not in {'Capricorn', 'Aquarius'}\n# 221: lord of Navamsa occupied by a planet associated with 7th lord is in 1st/2nd/5th in Rasi.\nl7 = lord(7)\ny221 = False\nif l7 in ctx.planets:\n associated_planets = [p for p in ctx.planets if p != l7 and associated(p, l7)]\n for p in associated_planets:\n disp = navamsa_dispositor(p)\n if disp in ctx.planets and house_of(disp) in [1, 2, 5]:\n y221 = True\n break\ny220 or y221\n", + "combo_template": "Rahu在5且非土星Navamsa,或7宫主关联行星的Navamsa主落1/2/5" }, "effects": [ "子女众多", @@ -11627,8 +11627,8 @@ "category": "special", "logic": { "type": "custom", - "expr": "\n# PyJHora 291/292/294 D1-safe variants. Variant 293 needs tithi/waning Moon\n# and remains unavailable from static planet_positions_60 data.\njm = 'Jupiter' in ctx.planets and 'Mars' in ctx.planets and house_of('Jupiter') == 1 and house_of('Mars') == 7\nsm = 'Saturn' in ctx.planets and 'Mars' in ctx.planets and house_of('Saturn') == 1 and house_of('Mars') in [5, 7, 9]\nmoon_mercury = False\nif 'Moon' in ctx.planets and 'Mercury' in ctx.planets:\n moon_mercury = kendra(house_of('Moon')) and kendra(house_of('Mercury')) and any(p != 'Moon' and aspect(p, 'Moon') for p in ctx.planets) and any(p != 'Mercury' and aspect(p, 'Mercury') for p in ctx.planets)\njm or sm or moon_mercury\n", - "combo_template": "木火1/7、土升火5/7/9,或月水角宫并受相位" + "expr": "\n# PyJHora/BVR 291-294 plus BVR variations.\njm = 'Jupiter' in ctx.planets and 'Mars' in ctx.planets and house_of('Jupiter') == 1 and house_of('Mars') == 7\nsm = 'Saturn' in ctx.planets and 'Mars' in ctx.planets and house_of('Saturn') == 1 and house_of('Mars') in [5, 7, 9]\nsaturn_waning = 'Saturn' in ctx.planets and house_of('Saturn') == 12 and is_waning_moon()\nmoon_mercury = False\nif 'Moon' in ctx.planets and 'Mercury' in ctx.planets:\n moon_mercury = kendra(house_of('Moon')) and kendra(house_of('Mercury')) and any(p != 'Moon' and aspect(p, 'Moon') for p in ctx.planets) and any(p != 'Mercury' and aspect(p, 'Mercury') for p in ctx.planets)\nl6 = lord(6)\nvariation_1 = house_of('Rahu') == 6 and aspect('Ketu', 'Rahu')\nvariation_2 = l6 in ctx.planets and same_house(l6, 'Mars')\nvariation_3 = 'Mercury' in ctx.planets and same_house('Mercury', 'Mars') and same_house('Mercury', 'Sun')\nd9_l6 = d9_lord_of_house(6)\nvariation_4 = d9_house_of('Mercury') == 6 and d9_house_of('Rahu') == 6 and d9_l6 in ctx.planets and same_house(d9_l6, 'Mars')\njm or sm or saturn_waning or moon_mercury or variation_1 or variation_2 or variation_3 or variation_4\n", + "combo_template": "木火1/7、土升火5/7/9、土12宫逢亏月,或BVR精神扰动变体" }, "effects": [ "Mental disturbance, confusion, erratic behavior" @@ -13765,7 +13765,47 @@ "strength": "中", "enabled": true, "source_reference": "BVR-36: Malika Yoga starting from 5th house" + }, + { + "id": "bvr_kaahala_yoga", + "name": "Kaahala Yoga", + "name_cn": "勇气格局(Kaahala)", + "source": "B.V. Raman / PyJHora", + "bvr_id": "BVR-15-alt", + "category": "auspicious", + "logic": { + "type": "custom", + "expr": "\n# PyJHora kaahala_yoga: 4th lord and Jupiter in mutual quadrants; Lagna lord strong.\nl1 = lord(1)\nl4 = lord(4)\nif l1 not in ctx.planets or l4 not in ctx.planets or 'Jupiter' not in ctx.planets:\n False\nelse:\n l1_strong = strong(l1)\n mutual_kendra = offset(house_of(l4), house_of('Jupiter')) in [0, 3, 6, 9]\n l1_strong and mutual_kendra\n", + "combo_template": "4宫主与木星互为Kendra,且上升主有力" + }, + "effects": [ + "Courage, initiative, status and practical drive" + ], + "strength": "moderate", + "enabled": true, + "draft": false, + "evidence_note": "v6.0.37: split from kahala_yoga; aligned to PyJHora kaahala_yoga() definition." + }, + { + "id": "bvr_kapata_yoga", + "name": "Kapata Yoga", + "name_cn": "欺诈瑜伽", + "source": "B.V. Raman / PyJHora", + "bvr_id": "BVR-202-204", + "category": "durbhaga", + "logic": { + "type": "custom", + "expr": "\n# PyJHora/BVR 202-204 Kapata Yoga.\nevil = set(MALEFICS)\nl4 = lord(4)\nl10 = lord(10)\nmaandi_h = maandi_house()\nif l4 not in ctx.planets or l10 not in ctx.planets:\n False\nelse:\n # 202: 4th joined by a malefic; 4th lord joined/aspected/hemmed by malefics.\n malefic_in_4 = any(house_of(m) == 4 for m in evil if m in ctx.planets)\n l4_h = house_of(l4)\n l4_joined_malefic = any(m != l4 and same_house(l4, m) for m in evil if m in ctx.planets)\n l4_aspected_malefic = any(aspect(m, l4) for m in evil if m in ctx.planets)\n prev_h = ((l4_h - 2) % 12) + 1 if l4_h else None\n next_h = (l4_h % 12) + 1 if l4_h else None\n l4_hemmed = bool(prev_h and next_h and house_has_malefic(prev_h) and house_has_malefic(next_h))\n yoga202 = malefic_in_4 and (l4_joined_malefic or l4_aspected_malefic or l4_hemmed)\n # 203: Saturn, Mars, Rahu in 4th; malefic 10th lord aspected by malefics.\n yoga203 = all(house_of(p) == 4 for p in ['Saturn', 'Mars', 'Rahu']) and l10 in evil and any(aspect(m, l10) for m in evil if m in ctx.planets and m != l10)\n # 204: 4th lord joins Saturn, Mandi, Rahu and is aspected by malefics.\n yoga204 = bool(maandi_h and house_of(l4) == house_of('Saturn') == house_of('Rahu') == maandi_h and any(aspect(m, l4) for m in evil if m in ctx.planets and m != l4))\n yoga202 or yoga203 or yoga204\n", + "combo_template": "4宫/4宫主受凶星、Rahu、Maandi/Mandi 等严重影响" + }, + "effects": [ + "Deception, distrust, household/family complications" + ], + "strength": "moderate", + "enabled": true, + "draft": false, + "evidence_note": "v6.0.37: high-confidence PyJHora Kapata 202-204 implementation." } ], - "total_enabled_rules": 379 + "total_enabled_rules": 381 } \ No newline at end of file diff --git a/scripts/validate_logic_v2.py b/scripts/validate_logic_v2.py index 56cde7de..869e1eb3 100644 --- a/scripts/validate_logic_v2.py +++ b/scripts/validate_logic_v2.py @@ -78,9 +78,10 @@ PYJHORA_VARIANTS = { # Vahana variants 'vahana_yoga_209': 'bvr_vahana_yoga', 'vahana_yoga_210': 'bvr_vahana_yoga', - # Kapata -> Nishkapata - 'kapata_yoga_202': 'bvr_nishkapata_precise', - 'kapata_yoga_204': 'bvr_nishkapata_precise', + # Kapata family + 'kapata_yoga_202': 'bvr_kapata_yoga', + 'kapata_yoga_203': 'bvr_kapata_yoga', + 'kapata_yoga_204': 'bvr_kapata_yoga', 'pisacha_grastha_yoga': 'bvr_pisacha_grastha_yoga', 'kaalanirdesat_puthranaasa_yoga_229': 'bvr_kaalanirdesat_puthranaasa_yoga', 'dwadasa_sahodara_yoga': 'bvr_dwadasa_sahodara_yoga', @@ -95,8 +96,11 @@ PYJHORA_VARIANTS = { 'sula_yoga': 'bvr_soola_yoga', # Kedara 'kedara_yoga': 'bvr_kedaara_yoga', - # Kaahala/Kahala - 'kaahala_yoga': 'kahala_yoga', + # Kaahala/Kahala are distinct PyJHora functions: + # - kaahala_yoga: L4 and Jupiter in mutual quadrants + strong L1 + # - kahala_yoga: L4 and L9 in mutual kendras + strong L1 + 'kaahala_yoga': 'bvr_kaahala_yoga', + 'kahala_yoga': 'kahala_yoga', # Direct mappings for common yogas 'vosi_yoga': 'bvr_vosi_precise', 'sunaphaa_yoga': 'bvr_sunaphaa_precise', diff --git a/scripts/yoga_engine.py b/scripts/yoga_engine.py index 0667d7c8..f04087ae 100644 --- a/scripts/yoga_engine.py +++ b/scripts/yoga_engine.py @@ -1327,12 +1327,21 @@ class YogaEngine: if ctype == "malefic_in_lagna_or_gulika_in_trine_OR_gulika_with_kendra_trine_lord_OR_l1_with_rahu_sat_ket": l1 = house_lord(1) gh = ctx.upagraha_house("gulika") + # PyJHora: condition 3 stands alone; condition 1 requires BOTH malefic in Lagna AND Gulika in trine. + l1_with_rahu_sat_ket = l1 and any(ctx.house_of(l1) == ctx.house_of(p) for p in ["Rahu", "Saturn", "Ketu"] if p in ctx.planets and p != l1) + if l1_with_rahu_sat_ket: + return success() + if gh is None: + return [] + malefic_in_lagna = any(ctx.house_of(p) == 1 for p in MALEFICS if p in ctx.planets) gulika_in_trine = gh in (1, 5, 9) + if malefic_in_lagna and gulika_in_trine: + return success() kendra_trine_lords = {house_lord(h) for h in (1, 4, 5, 7, 9, 10)} - gulika_with_kendra_trine_lord = gh is not None and any( + gulika_with_kendra_trine_lord = any( lord and lord in ctx.planets and ctx.house_of(lord) == gh for lord in kendra_trine_lords ) - return success() if any(ctx.house_of(p) == 1 for p in MALEFICS if p in ctx.planets) or gulika_in_trine or gulika_with_kendra_trine_lord or (l1 and any(related(l1, p) for p in ["Rahu", "Saturn", "Ketu"] if p in ctx.planets)) else [] + return success() if gulika_with_kendra_trine_lord else [] if ctype == "same_lord_for_1st_and_4th": return success() if house_lord(1) == house_lord(4) else [] if ctype == "1st_and_4th_lords_are_natural_or_temporal_friends":