fix(transit): double-transit rows in a stable order; cross-layer tests follow the aspect fix (BUG-1185)

With the aspect count from 1 (42d1582f) the public charts get same-layer
overlaps for the first time, and the overlap / cross-layer loops iterated
Python sets, so the double_transit list order changed with PYTHONHASHSEED
(the D1/CL golden failed under seeds 1 and 2). The loops now iterate sorted
names; the golden is recaptured and passes under seeds 0/1/2/5.
tests/test_double_transit_cross_layer_pairing.py: three expectations updated
with original / new / reason (Jobs house-7 summary now leads with the D1
layer; the ninth-house non-pairing example moves to Jobs house 9; the
same-house set is recomputed).

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 14:29:28 +08:00
co-authored by Claude Opus 5.5
parent 0176cb3008
commit db5a0509da
3 changed files with 44 additions and 26 deletions
+8 -7
View File
@@ -13306,7 +13306,8 @@ def cmd_double_transit_pac(args):
# D1 层 overlap
d1_overlap = jup_d1 & sat_d1
for t in d1_overlap:
# 按名字排序:集合遍历顺序随 PYTHONHASHSEED 变,结果列表不得随之变(BUG-1185)。
for t in sorted(d1_overlap):
results['double_transit'].append({
'layer': 'D1', 'target': t,
'jupiter_pac': results['d1']['jupiter'][t],
@@ -13316,7 +13317,7 @@ def cmd_double_transit_pac(args):
# D9 层 overlap
d9_overlap = jup_d9 & sat_d9
for t in d9_overlap:
for t in sorted(d9_overlap):
results['double_transit'].append({
'layer': 'D9', 'target': t,
'jupiter_pac': results['d9']['jupiter'][t],
@@ -13326,7 +13327,7 @@ def cmd_double_transit_pac(args):
# Chandra Lagna 层 overlap
cl_overlap = jup_cl & sat_cl
for t in cl_overlap:
for t in sorted(cl_overlap):
results['double_transit'].append({
'layer': 'CL', 'target': t,
'jupiter_pac': results['cl']['jupiter'][t],
@@ -13341,8 +13342,8 @@ def cmd_double_transit_pac(args):
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:
for d1t in sorted(jup_d1):
for d9t in sorted(sat_d9):
if d1_ids[d1t] & d9_ids[d9t]:
results['double_transit'].append({
'layer': 'D1+D9', 'target': f'Jupiter(D1){d1t} + Saturn(D9){d9t}',
@@ -13350,8 +13351,8 @@ def cmd_double_transit_pac(args):
'saturn_pac': results['d9']['saturn'][d9t],
'strength': 'moderate',
})
for d1t in sat_d1:
for d9t in jup_d9:
for d1t in sorted(sat_d1):
for d9t in sorted(jup_d9):
if d1_ids[d1t] & d9_ids[d9t]:
results['double_transit'].append({
'layer': 'D1+D9', 'target': f'Saturn(D1){d1t} + Jupiter(D9){d9t}',
+8 -8
View File
@@ -1206,7 +1206,7 @@
}
],
"strength": "strong",
"target": "Venus(对宫主)"
"target": "Venus(宫主)"
},
{
"jupiter_pac": [
@@ -1228,7 +1228,7 @@
}
],
"strength": "strong",
"target": "Venus(宫主)"
"target": "Venus(对宫主)"
}
],
"stats": {
@@ -1629,12 +1629,12 @@
"type": "Position"
},
{
"desc": "合相(6.64°)",
"desc": "合相(4.07°)",
"type": "Conjunction"
}
],
"strength": "strong",
"target": "Venus(对宫主)"
"target": "5宫(Pisces)"
},
{
"jupiter_pac": [
@@ -1651,12 +1651,12 @@
"type": "Position"
},
{
"desc": "合相(4.07°)",
"desc": "合相(6.64°)",
"type": "Conjunction"
}
],
"strength": "strong",
"target": "5宫(Pisces)"
"target": "Venus(对宫主)"
}
],
"stats": {
@@ -1880,7 +1880,7 @@
}
],
"strength": "strong",
"target": "Venus(对宫主)"
"target": "Venus(宫主)"
},
{
"jupiter_pac": [
@@ -1902,7 +1902,7 @@
}
],
"strength": "strong",
"target": "Venus(宫主)"
"target": "Venus(对宫主)"
}
],
"stats": {
@@ -7,7 +7,7 @@ while D1 ``9宫`` met any ``{planet}_D9`` / ``D9_{planet}(宫主)`` target.
Real engine runs on the three public AA charts of the evidence-card research
(`consult_evidence_card_lib.load_public_charts`, raman ayanamsa, mean nodes,
reference date fixed in the library). D1 / D9 / CL layer results are unchanged
by this fix; `tests/test_double_transit_d9_targets.py` holds the D1 / CL golden.
by this fix (they moved later with BUG-1185, the aspect count from 1); `tests/test_double_transit_d9_targets.py` holds the D1 / CL golden.
"""
from __future__ import annotations
@@ -147,18 +147,28 @@ def test_seventh_house_pairs_d1_house_with_d9_house(charts) -> None:
assert "7宫(Pisces)" in result["d1"]["saturn"]
assert "D9_7宫(Cancer)" in result["d9"]["jupiter"]
assert ("Saturn", "7宫(Pisces)", "Jupiter", "D9_7宫(Cancer)") in _cross(result)
assert result["summary"].startswith("⚠️ 跨层间接")
# 原值: summary 以「⚠️ 跨层间接」开头(D1 层没有双重过运)
# 新值: 「⚠️ D1 层 Double Transit 激活…」
# 原因: BUG-1185(TASK-upstream-sync4-20261002 T2)相位改从 1 数后,木星 9 宫相位落到 D1 7 宫,
# D1 层本身已成双重过运,摘要按 D1 优先;跨层条目仍在(上一行)
assert result["summary"].startswith("⚠️ D1 层 Double Transit 激活")
def test_ninth_house_no_longer_pairs_with_an_unrelated_d9_target(charts) -> None:
"""Public chart, house 9: Mars_D9 is the lagna lord's D9 sign, not the 9th house."""
result, ctx = _public(charts, "elizabeth_taylor", 9)
assert ctx["ll_name"] == "Mars" and ctx["event_lord"] == "Moon"
# Both hits are still there; only the pairing changed.
assert "9宫(Cancer)" in result["d1"]["jupiter"]
assert "Mars_D9(Capricorn)" in result["d9"]["saturn"]
assert all(d1_target != "9宫(Cancer)" for _, d1_target, _, _ in _cross(result))
assert all(not d9_target.startswith("Mars_D9") for _, _, _, d9_target in _cross(result))
"""Public chart, house 9: Mercury_D9 is the lagna lord's D9 sign, not the 9th house.
原值: 泰勒 9 宫(木星在 D1 9宫(Cancer)、土星在 Mars_D9(Capricorn))
新值: 乔布斯 9 宫(土星在 D1 9宫(Taurus)、木星在 Mercury_D9(Cancer))
原因: BUG-1185 相位改从 1 数后泰勒那组命中不再同时出现;换成同一结构(D1 9 宫 + 命主
D9 星座、命主不是事件宫主)的另一张公开盘,断言不变。
"""
result, ctx = _public(charts, "steve_jobs", 9)
assert ctx["ll_name"] == "Mercury" and ctx["event_lord"] == "Venus"
# Both hits are there; the pairing must not join them.
assert "9宫(Taurus)" in result["d1"]["saturn"]
assert "Mercury_D9(Cancer)" in result["d9"]["jupiter"]
assert all(d1_target != "9宫(Taurus)" for _, d1_target, _, _ in _cross(result))
assert all(not d9_target.startswith("Mercury_D9") for _, _, _, d9_target in _cross(result))
def test_every_cross_entry_joins_the_same_event_significator(runs) -> None:
@@ -188,7 +198,14 @@ def test_every_same_house_hit_becomes_a_cross_entry(runs) -> None:
assert (d1_planet.title(), d1_house, d9_planet.title(), d9_house) in cross, (chart_id, house)
same_house.add((chart_id, house))
# On the library reference date these are the public-chart houses where both hits happen.
assert same_house == {("elizabeth_taylor", 6), ("elizabeth_taylor", 12), ("steve_jobs", 2), ("steve_jobs", 6), ("steve_jobs", 7)}
# 原值: {泰勒 6、12;乔布斯 2、6、7}
# 新值: 下列 10 格
# 原因: BUG-1185 相位改从 1 数(土 3/7/10、木 5/7/9 落在正确的宫),命中的宫整体平移
assert same_house == {
("barack_obama", 12), ("elizabeth_taylor", 3), ("elizabeth_taylor", 5), ("elizabeth_taylor", 7),
("elizabeth_taylor", 9), ("elizabeth_taylor", 11), ("steve_jobs", 1), ("steve_jobs", 3),
("steve_jobs", 5), ("steve_jobs", 7),
}
def test_event_lord_pairs_are_kept(runs) -> None: