fix(marriage): counting method reports a neutral geometry index only; real Parivartana no longer crashes (BUG-1183/1184)
TASK-upstream-sync4-20261002 T1 (upstream yinduzhanxing 0afa2780 for the idea; wording is ours, in Chinese, per decision 2). _interpret_marriage_count and _marriage_recommendations no longer state relationship counts, order, quality or loyalty; the Marriage-counting evidence is always neutral and carries only geometric_index (the dead D9-quality line in the adjudication is removed). The count is computed before the Parivartana override (the old order raised UnboundLocalError) and the exchange check now tests a real exchange instead of a conjunction with the dispositor. 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:
co-authored by
Claude Opus 5.5
parent
bc9b9f89bb
commit
ba97fd5980
@@ -1815,6 +1815,26 @@ def test_thematic_report_derives_evidence_from_birth_payload() -> None:
|
||||
assert any(item['details'].get('derived') for item in result['themes']['career']['evidence'])
|
||||
|
||||
|
||||
def test_marriage_counting_evidence_is_neutral_geometry_index_only() -> None:
|
||||
# BUG-1183 (TASK-upstream-sync4-20261002 T1). Fictitious chart 1990-06-15 10:30 Beijing.
|
||||
# 原值: marriage_count ≤ 1 记 positive,details 带 marriage_count 与 d9_marriage_quality
|
||||
# 新值: 一律 neutral,details 只有 geometric_index;结论只描述几何指数
|
||||
handler = _handler()
|
||||
result = handler._compute_thematic_report({
|
||||
'theme': ['marriage'],
|
||||
'year': 1990, 'month': 6, 'day': 15, 'hour': 10, 'minute': 30,
|
||||
'lat': 39.9042, 'lon': 116.4074, 'tz': 8,
|
||||
})
|
||||
rows = [item for item in result['themes']['marriage']['evidence'] if item['technique'] == 'Marriage-counting']
|
||||
assert len(rows) == 1
|
||||
row = rows[0]
|
||||
assert row['sentiment'] == 'neutral'
|
||||
assert set(row['details']) == {'geometric_index', 'source', 'derived'}
|
||||
assert row['conclusion'].startswith(f"关系几何指数 {row['details']['geometric_index']}:")
|
||||
for banned in ('再婚', '段关系', '第一段', '终身关系', '忠诚度'):
|
||||
assert banned not in json.dumps(result['themes']['marriage'], ensure_ascii=False)
|
||||
|
||||
|
||||
def test_thematic_report_derives_relationship_strict_narrative_evidence() -> None:
|
||||
handler = _handler()
|
||||
result = handler._compute_thematic_report({
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""BUG-1183 / BUG-1184 (TASK-upstream-sync4-20261002 T1).
|
||||
|
||||
The marriage-counting method only reports a geometry index: no relationship
|
||||
count, order, quality or loyalty claim, and the same advice for every index.
|
||||
A real Parivartana no longer crashes the module, and a conjunction with the
|
||||
dispositor is not mistaken for one.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
SCRIPTS = os.path.join(os.path.dirname(__file__), '..', 'scripts')
|
||||
if SCRIPTS not in sys.path:
|
||||
sys.path.insert(0, SCRIPTS)
|
||||
|
||||
from marriage_counting import marriage_counting_full_analysis # noqa: E402
|
||||
|
||||
BANNED = re.compile(r'再婚|段关系|第一段|第二段|终身关系|忠诚度|一次|两段|多段|婚姻/认真关系数量')
|
||||
|
||||
|
||||
def _text(result) -> str:
|
||||
return '\n'.join([
|
||||
str(result.get('interpretation') or ''),
|
||||
*[str(item) for item in result.get('recommendations') or []],
|
||||
str(result.get('note') or ''),
|
||||
])
|
||||
|
||||
|
||||
def test_every_index_is_described_as_geometry_without_event_claims() -> None:
|
||||
advice = set()
|
||||
for d9_sign in range(12):
|
||||
result = marriage_counting_full_analysis('Venus', {'Venus': 15.0}, {'Venus': d9_sign * 30 + 10.0})
|
||||
index = d9_sign + 1
|
||||
assert result['geometric_index'] == index
|
||||
assert result['marriage_count'] == index # compatibility field, same value
|
||||
assert result['interpretation'].startswith(f'关系几何指数 {index}:')
|
||||
assert '不代表婚姻或关系的次数' in result['interpretation']
|
||||
assert not BANNED.search(_text(result)), _text(result)
|
||||
advice.add(tuple(result['recommendations']))
|
||||
# 原值: 指数 1 / 2 / ≥3 给三套不同建议(含「第一段关系由吉星主导,质量较好」)
|
||||
# 新值: 所有指数同一套中性说明
|
||||
assert len(advice) == 1
|
||||
|
||||
|
||||
def test_same_and_opposite_sign_are_described_without_quality() -> None:
|
||||
same = marriage_counting_full_analysis('Venus', {'Venus': 15.0}, {'Venus': 10.0})
|
||||
assert 'D1 与 D9 两个参照点落在同一星座。' in same['interpretation']
|
||||
opposite = marriage_counting_full_analysis('Venus', {'Venus': 15.0}, {'Venus': 190.0})
|
||||
assert 'D1 与 D9 两个参照点落在相对的星座。' in opposite['interpretation']
|
||||
|
||||
|
||||
def test_real_parivartana_does_not_crash_and_conjunction_is_not_exchange() -> None:
|
||||
# Venus (7th lord) in Aries, Mars in Libra: a true exchange.
|
||||
exchanged = marriage_counting_full_analysis(
|
||||
'Venus', {'Venus': 15.0, 'Mars': 185.0}, {'Venus': 160.0}, {'7': {}})
|
||||
assert 'error' not in exchanged
|
||||
assert exchanged['parivartana']['has_parivartana'] is True
|
||||
# Counted from Libra (the exchanged sign) to Virgo: 12.
|
||||
assert exchanged['geometric_index'] == 12
|
||||
|
||||
# Venus and Mars both in Aries: a conjunction with the dispositor, not an exchange.
|
||||
conjunct = marriage_counting_full_analysis(
|
||||
'Venus', {'Venus': 15.0, 'Mars': 20.0}, {'Venus': 160.0}, {'7': {}})
|
||||
assert 'error' not in conjunct
|
||||
assert conjunct['parivartana']['has_parivartana'] is False
|
||||
assert conjunct['geometric_index'] == 6
|
||||
Reference in New Issue
Block a user