婚恋评级改成证据档位,配偶星分数不再写成百分制(BUG-1318,上游 f891a2c1)

五档不再写稳定、离婚、再婚或婚前咨询,并写明这是结构指数。公开盘中英文各锁一条。配偶星证据行改成 0 到 1,不乘 100。pytest tests/test_d9_evidence_bands.py 3 通过。

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-14 00:48:25 +08:00
co-authored by Grok (agent loop)
parent 99ef1bbd12
commit d32ad7b7b1
4 changed files with 191 additions and 8 deletions
+15
View File
@@ -17720,3 +17720,18 @@
- 复发自:BUG-1306。
- 修复版本:分支 `codex/rectification-step0-entry-20261013`,尚未合入 staging。
## BUG-1318 | 婚恋评级仍写成稳定或婚前咨询,配偶星分数被写成百分制
- 状态:fixed-pending-verify
- 首次发现 / 最近更新:2026-10-14 / 2026-10-14
- 来源:issue #56。上游 `f891a2c1`。任务书 `docs/tasks/TASK-upstream-sync7-20261014.md` T1。
- 现象:D9 综合评级仍写「婚姻稳定」「强烈建议婚前咨询」。这份文字进全读导出包,模型能读到。配偶星证据行把 0 到 1 的指数写成「婚姻质量 x/100」。
- 触发条件:算出婚恋几何指数,或关系时机证据带出配偶星。
- 根因:同步第六轮按标题筛提交时,漏了 10-02 到 10-03 的这条措辞修正。分数行把 0 到 1 当成了百分制。
- 修复:五档改成证据档位,并写明这是结构指数,不预测婚姻次数、稳定、离婚、伴侣好坏,也不提示婚前咨询。中文报告用中文档位,英文报告用英文档位。证据行改成「婚姻质量指数 x(0到1)」,不乘 100。
- 验证:`tests/test_d9_evidence_bands.py` 3 通过。公开盘中英文各一条快照。配偶星行不再出现 `/100`。
- 防复发:五档文字不得含「稳定、离婚、再婚、婚前咨询、几段」;快照锁住公开盘的两句。
- 相关记录:BUG-1183。
- 复发自:无。
- 修复版本:分支 `codex/upstream-sync7-20261014`,尚未合入 staging。
+1 -1
View File
@@ -7551,7 +7551,7 @@ class JyotishAPIHandler(BaseHTTPRequestHandler, VedastroEvidenceMixin, SynastryM
evidence.append({
'label': 'Darakaraka (DK)',
'value': f"{dk_planet} · H{darakaraka.get('dk_house', '-')}",
'note': f"{darakaraka.get('core_profile') or '配偶象征星'};婚姻质量 {darakaraka.get('marriage_quality_score', '-')}/100",
'note': f"{darakaraka.get('core_profile') or '配偶象征星'};婚姻质量指数 {darakaraka.get('marriage_quality_score', '-')}(0到1)",
})
except Exception as exc:
darakaraka = {'error': str(exc), 'dk_planet': dk_planet}
+41 -7
View File
@@ -21,6 +21,23 @@ from typing import Dict, Optional, List
SIGN_CN = ['白羊座','金牛座','双子座','巨蟹座','狮子座','处女座',
'天秤座','天蝎座','射手座','摩羯座','水瓶座','双鱼座']
# D9 结构证据档位(BUG-1318)。中文给报告正文,英文键与英文短句给英文版。
# 不写婚姻稳定、离婚、再婚、段数或婚前咨询。
D9_CLAIM_BOUNDARY = (
'D9 结构证据指数,不预测婚姻次数、稳定、离婚、伴侣好坏,也不提示需要婚前咨询'
)
D9_CLAIM_BOUNDARY_EN = (
'D9 structural evidence index. It does not predict marriage count, stability, '
'divorce, or partner quality, and it does not suggest premarital counseling.'
)
D9_EVIDENCE_BANDS = (
('supportive_evidence_stronger', '支持证据较强', 'Stronger supportive evidence'),
('supportive_evidence_mixed_positive', '支持证据偏正', 'Mixed supportive evidence'),
('mixed_evidence', '证据混杂', 'Mixed evidence'),
('pressure_evidence_mixed', '压力证据偏杂', 'Mixed pressure evidence'),
('pressure_evidence_stronger', '压力证据较强', 'Stronger pressure evidence'),
)
def sign_of(lon: float) -> int:
"""从黄道经度计算星座序号 (0-11)"""
@@ -348,25 +365,42 @@ def _assess_d9_marriage_quality(
quality_points -= 1
factors.append("D9 Ketu在7宫 → 关系中的分离倾向")
# 综合评级
# 证据档位,不是婚姻结局(BUG-1318,上游 f891a2c1)。
if quality_points >= 4:
rating = "高(关系质量好,伴侣支持强,婚姻稳定)"
band = D9_EVIDENCE_BANDS[0]
elif quality_points >= 1:
rating = "中上(关系质量尚可,需经营但基础好)"
band = D9_EVIDENCE_BANDS[1]
elif quality_points >= 0:
rating = "中(关系质量一般,需用心经营)"
band = D9_EVIDENCE_BANDS[2]
elif quality_points >= -2:
rating = "中下(关系有挑战,需提前沟通和调整期望)"
band = D9_EVIDENCE_BANDS[3]
else:
rating = "低(关系质量有重大挑战,强烈建议婚前咨询)"
band = D9_EVIDENCE_BANDS[4]
return {
'quality_rating': rating,
'quality_band': band[0],
'quality_rating': band[1],
'quality_rating_en': band[2],
'quality_points': quality_points,
'factors': factors,
'claim_boundary': D9_CLAIM_BOUNDARY,
'claim_boundary_en': D9_CLAIM_BOUNDARY_EN,
}
def render_d9_evidence_report(quality: Dict, language: str = 'zh') -> str:
"""中文报告用证据档位短句;英文版用英文短句。两边都带同一条边界。"""
if not isinstance(quality, dict):
quality = {}
if language == 'en':
band = quality.get('quality_rating_en') or quality.get('quality_band') or ''
boundary = quality.get('claim_boundary_en') or D9_CLAIM_BOUNDARY_EN
return f"D9 evidence band: {band}\n{boundary}"
band = quality.get('quality_rating') or ''
boundary = quality.get('claim_boundary') or D9_CLAIM_BOUNDARY
return f"D9 证据档位:{band}\n{boundary}"
def _marriage_recommendations(base: Dict, d9_quality: Dict) -> List[str]:
"""几何指数与伴侣数量、事件断语分开(BUG-1183);不随指数大小给不同结论。"""
return [
+134
View File
@@ -0,0 +1,134 @@
"""BUG-1318: D9 marriage rating is an evidence band, not an outcome claim.
Upstream f891a2c1. The five bands must not say the relationship is stable,
ending, repeated, or in need of premarital counseling. The DK evidence line
keeps the 0-1 index and does not print a fake /100 score.
"""
from __future__ import annotations
import importlib.util
import json
import os
import re
import sys
from pathlib import Path
ROOT = os.path.join(os.path.dirname(__file__), "..")
SCRIPTS = os.path.join(ROOT, "scripts")
if SCRIPTS not in sys.path:
sys.path.insert(0, SCRIPTS)
from jyotish_engine import compute_chart_data # noqa: E402
def _api_handler():
"""Reuse the existing unbound handler helper. Do not add another forgery site."""
path = os.path.join(os.path.dirname(__file__), "test_api_server_security.py")
spec = importlib.util.spec_from_file_location("_api_security_helpers", path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module._handler()
from marriage_counting import ( # noqa: E402
D9_CLAIM_BOUNDARY,
D9_EVIDENCE_BANDS,
_assess_d9_marriage_quality,
marriage_counting_full_analysis,
render_d9_evidence_report,
)
from varga import calc_varga # noqa: E402
BANNED = re.compile(r"稳定|离婚|再婚|婚前咨询|几段")
def _quality(points_chart: dict) -> dict:
return _assess_d9_marriage_quality(points_chart, None)
def test_five_bands_have_no_outcome_claims_and_keep_the_boundary() -> None:
samples = {
"supportive_evidence_stronger": {"Venus": 331.0, "Mars": 271.0, "Jupiter": 91.0},
"supportive_evidence_mixed_positive": {"Venus": 31.0},
"mixed_evidence": {"Venus": 10.0},
"pressure_evidence_mixed": {"Venus": 151.0},
"pressure_evidence_stronger": {"Venus": 151.0, "Mars": 91.0, "Jupiter": 271.0},
}
seen = []
for key, chart in samples.items():
quality = _quality(chart)
assert quality["quality_band"] == key
assert quality["claim_boundary"] == D9_CLAIM_BOUNDARY
assert quality["claim_boundary_en"]
assert not BANNED.search(quality["quality_rating"])
assert not BANNED.search(quality["quality_rating_en"])
seen.append(quality["quality_band"])
assert seen == [band[0] for band in D9_EVIDENCE_BANDS]
def test_public_chart_report_snapshots_in_both_languages() -> None:
cases = json.loads(
Path(ROOT, "references/real_case_calibration/minute_rectification_development_v1.json").read_text(encoding="utf-8")
)["cases"]
birth = next(case for case in cases if case["case_id"] == "steve_jobs_1955_development")["birth"]
assert birth["source"]["rodden_rating"] == "AA"
year, month, day = (int(part) for part in birth["date"].split("-"))
hour, minute = (int(part) for part in birth["time"].split(":"))
chart, *_ = compute_chart_data(
year, month, day, hour, minute,
birth["latitude"], birth["longitude"], birth["timezone_offset"],
ayanamsa_name="raman",
)
longitudes = {name: row["degree_raw"] for name, row in chart["planets"].items()}
d9 = {}
for name, lon in longitudes.items():
divisional = calc_varga(lon, 9)
d9[name] = divisional["sign_idx"] * 30 + divisional["degree_in_sign"]
result = marriage_counting_full_analysis(chart["houses"]["house_7"]["lord"], longitudes, d9)
quality = result["d9_marriage_quality"]
assert quality["quality_band"] == "mixed_evidence"
assert quality["quality_points"] == 0
chinese = render_d9_evidence_report(quality, "zh")
english = render_d9_evidence_report(quality, "en")
assert chinese == (
"D9 证据档位:证据混杂\n"
"D9 结构证据指数,不预测婚姻次数、稳定、离婚、伴侣好坏,也不提示需要婚前咨询"
)
assert english == (
"D9 evidence band: Mixed evidence\n"
"D9 structural evidence index. It does not predict marriage count, stability, "
"divorce, or partner quality, and it does not suggest premarital counseling."
)
assert "/100" not in chinese
assert "/100" not in english
def test_dk_evidence_line_prints_the_zero_to_one_index() -> None:
cases = json.loads(
Path(ROOT, "references/real_case_calibration/minute_rectification_development_v1.json").read_text(encoding="utf-8")
)["cases"]
birth = next(case for case in cases if case["case_id"] == "steve_jobs_1955_development")["birth"]
year, month, day = (int(part) for part in birth["date"].split("-"))
hour, minute = (int(part) for part in birth["time"].split(":"))
chart, asc_idx, *_ = compute_chart_data(
year, month, day, hour, minute,
birth["latitude"], birth["longitude"], birth["timezone_offset"],
ayanamsa_name="raman",
)
longitudes = {name: row["degree_raw"] for name, row in chart["planets"].items()}
handler = _api_handler()
evidence = handler._compute_relationship_timing_evidence(
{},
chart["planets"],
longitudes,
asc_idx,
chart["ascendant"]["sign"],
)
notes = [row["note"] for row in evidence["evidence"] if row.get("label") == "Darakaraka (DK)"]
assert len(notes) == 1
assert "/100" not in notes[0]
assert "婚姻质量指数" in notes[0]
assert "(0到1)" in notes[0]
score = evidence["darakaraka"]["marriage_quality_score"]
assert isinstance(score, float)
assert 0.0 <= score <= 1.0
assert str(score) in notes[0]