fix(engine): pair double-transit D1+D9 targets by identity, not name digits (BUG-1061)
Every D9 target name contains the "9" of "D9", so the digit comparison never paired D1 N宫 with D9_N宫 and, for house 9, paired D1 9宫 with any D9 planet target. Targets now carry structured metadata (layer/kind/house/planet); the cross-layer loop pairs only the same house or targets that both point at the D1 house-N lord. Target names and D1/D9/CL layer results are unchanged (D1/CL golden regenerated byte-identical); 48 samples: cross entries 31 -> 38. Evidence-card golden regenerated with the capture script. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
037cd1aa1d
commit
fb543d3849
@@ -13047,6 +13047,65 @@ def _double_transit_d9_targets(asc_deg, natal, event_house, event_lord, ll_name)
|
||||
}
|
||||
|
||||
|
||||
def _double_transit_target_meta(asc_deg, natal, event_house, event_sign, event_lord, ll_name, opposite_lord):
|
||||
"""Double Transit PAC 的 D1 / D9 目标结构化元数据(BUG-1061)。
|
||||
|
||||
返回 ``{'D1': {目标名: [meta, ...]}, 'D9': {目标名: [meta, ...]}}``,目标名与
|
||||
``cmd_double_transit_pac`` 的 D1 目标表、``_double_transit_d9_targets`` 的键逐字相同;
|
||||
同一个名字可能对应多条 meta(上升主恰是第 N 宫主时 ``{星}_D9`` 两个键重合)。
|
||||
每条 meta:``layer``、``kind``、``house``、``planet``。kind 取值:
|
||||
D1 ``house`` / ``house_lord`` / ``lagna_lord`` / ``opposite_lord``;
|
||||
D9 ``house`` / ``d9_house_lord``(D9 第 N 宫主,落在其 D9 星座)/
|
||||
``lord_d9_sign``(D1 第 N 宫主的 D9 星座)/ ``lagna_lord_d9_sign``(上升主的 D9 星座)。
|
||||
"""
|
||||
d9_asc_idx = _navamsa_idx(asc_deg)
|
||||
d9_event_si = (d9_asc_idx + event_house - 1) % 12
|
||||
d9_event_sign = SIGNS[d9_event_si]
|
||||
d9_event_lord = SIGN_LORDS[d9_event_sign]
|
||||
|
||||
def d9_sign(planet):
|
||||
return SIGNS[_navamsa_idx(natal.get(planet, {}).get('degree', 0))]
|
||||
|
||||
def meta(layer, kind, house, planet=None):
|
||||
return {'layer': layer, 'kind': kind, 'house': house, 'planet': planet}
|
||||
|
||||
layers = {'D1': {}, 'D9': {}}
|
||||
for name, row in (
|
||||
(f'{event_house}宫({event_sign})', meta('D1', 'house', event_house)),
|
||||
(f'{event_lord}(宫主)', meta('D1', 'house_lord', event_house, event_lord)),
|
||||
(f'{ll_name}(LL)', meta('D1', 'lagna_lord', 1, ll_name)),
|
||||
(f'{opposite_lord}(对宫主)', meta('D1', 'opposite_lord', 7, opposite_lord)),
|
||||
(f'D9_{event_house}宫({d9_event_sign})', meta('D9', 'house', event_house)),
|
||||
(f'D9_{d9_event_lord}(宫主)', meta('D9', 'd9_house_lord', event_house, d9_event_lord)),
|
||||
(f'{event_lord}_D9({d9_sign(event_lord)})', meta('D9', 'lord_d9_sign', event_house, event_lord)),
|
||||
(f'{ll_name}_D9({d9_sign(ll_name)})', meta('D9', 'lagna_lord_d9_sign', 1, ll_name)),
|
||||
):
|
||||
layers[row['layer']].setdefault(name, []).append(row)
|
||||
return layers
|
||||
|
||||
|
||||
def _double_transit_target_identities(metas, event_house, event_lord):
|
||||
"""跨层配对用的语义身份集合;D1 与 D9 目标的集合有交集才算「同一目标」(BUG-1061)。
|
||||
|
||||
跨层条目回答的是「木星在一层、土星在另一层,是否同时激活了第 N 宫这件事的同一个
|
||||
征象点」,按 KN Rao「事件宫 / 宫主 / 宫主 D9 星座」只认两种身份,不解析展示用的目标名:
|
||||
- ``('house', N)``:D1 第 N 宫 ↔ D9 第 N 宫(kind ``house``);
|
||||
- ``('event_house_lord', N)``:落点是 D1 第 N 宫主这颗星的目标——D1 的 ``{宫主}(宫主)``
|
||||
(及恰好是同一颗星的 ``(LL)`` / ``(对宫主)``),D9 的 ``{宫主}_D9``(宫主 D9 星座),
|
||||
以及这颗星恰好也是 D9 第 N 宫主时的 ``D9_{宫主}(宫主)``。
|
||||
不配:宫位 ↔ 星体目标;上升主 / 对宫主不是第 N 宫主时(与第 N 宫无关,且同一对会在
|
||||
12 个宫的调用里重复出现);D1 第 N 宫主 ↔ 另一颗星担任的 D9 第 N 宫主(不是同一征象星,
|
||||
KN Rao 三点里也没有 D9 宫主)。
|
||||
"""
|
||||
identities = set()
|
||||
for row in metas:
|
||||
if row['kind'] == 'house':
|
||||
identities.add(('house', row['house']))
|
||||
elif row['planet'] == event_lord:
|
||||
identities.add(('event_house_lord', event_house))
|
||||
return frozenset(identities)
|
||||
|
||||
|
||||
def cmd_double_transit_pac(args):
|
||||
"""Double Transit PAC + D9 层计算"""
|
||||
# 1. 计算本命星盘
|
||||
@@ -13194,12 +13253,16 @@ def cmd_double_transit_pac(args):
|
||||
'strength': 'strong',
|
||||
})
|
||||
|
||||
# 跨层 Double Transit
|
||||
# 跨层 Double Transit:按目标的结构化身份配对,不解析目标名(BUG-1061)
|
||||
target_meta = _double_transit_target_meta(
|
||||
asc_deg, natal, event_house, event_sign, event_lord, ll_name, opposite_lord)
|
||||
d1_ids = {name: _double_transit_target_identities(rows, event_house, event_lord)
|
||||
for name, rows in target_meta['D1'].items()}
|
||||
d9_ids = {name: _double_transit_target_identities(rows, event_house, event_lord)
|
||||
for name, rows in target_meta['D9'].items()}
|
||||
for d1t in jup_d1:
|
||||
for d9t in sat_d9:
|
||||
d1_nums = ''.join(c for c in d1t if c.isdigit())
|
||||
d9_nums = ''.join(c for c in d9t if c.isdigit())
|
||||
if d1_nums == d9_nums or (event_lord in d1t and event_lord in d9t):
|
||||
if d1_ids[d1t] & d9_ids[d9t]:
|
||||
results['double_transit'].append({
|
||||
'layer': 'D1+D9', 'target': f'Jupiter(D1){d1t} + Saturn(D9){d9t}',
|
||||
'jupiter_pac': results['d1']['jupiter'][d1t],
|
||||
@@ -13208,9 +13271,7 @@ def cmd_double_transit_pac(args):
|
||||
})
|
||||
for d1t in sat_d1:
|
||||
for d9t in jup_d9:
|
||||
d1_nums = ''.join(c for c in d1t if c.isdigit())
|
||||
d9_nums = ''.join(c for c in d9t if c.isdigit())
|
||||
if d1_nums == d9_nums or (event_lord in d1t and event_lord in d9t):
|
||||
if d1_ids[d1t] & d9_ids[d9t]:
|
||||
results['double_transit'].append({
|
||||
'layer': 'D1+D9', 'target': f'Saturn(D1){d1t} + Jupiter(D9){d9t}',
|
||||
'jupiter_pac': results['d9']['jupiter'][d9t],
|
||||
|
||||
@@ -104,6 +104,8 @@ CORE_PYTEST_TARGETS = [
|
||||
"tests/test_consultation_native_layers.py",
|
||||
# BUG-1060: Double Transit PAC D9 targets use the D9 signs their labels name.
|
||||
"tests/test_double_transit_d9_targets.py",
|
||||
# BUG-1061: D1+D9 cross-layer entries pair targets by structured identity, not name digits.
|
||||
"tests/test_double_transit_cross_layer_pairing.py",
|
||||
"tests/test_relationship_event_class_evidence.py",
|
||||
"tests/test_thematic_dasha_info_source.py",
|
||||
"tests/test_report_orchestrator_marriage_timing.py",
|
||||
|
||||
Reference in New Issue
Block a user