Files
Jyotisha/tests/test_bilingual_synastry_delivery.py
T
jesse-uxGrok (agent loop)Cursor
e8793bb0d2 fix(synastry): fill section evidence and stop the English job from sticking
The review found empty sections and an English job that stayed running. Take evidence from reader briefs, retry one section, and settle before marking the report ready.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-19 12:55:17 +08:00

211 lines
12 KiB
Python

from __future__ import annotations
import importlib.util
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
MODULE_PATH = ROOT / "skills" / "jyotish-full-synastry-reading" / "scripts" / "validate_bilingual_synastry_delivery.py"
spec = importlib.util.spec_from_file_location("bilingual_synastry_delivery", MODULE_PATH)
module = importlib.util.module_from_spec(spec)
assert spec and spec.loader
spec.loader.exec_module(module)
def _full_chinese_report() -> str:
headings = ["结论总纲", "各自带入关系的需求", "情绪安全与相处感受", "吸引与亲密", "沟通、冲突与修复", "关系如何推进", "共同生活的收益与压力", "能不能稳定走下去", "关系应期"]
prose = "双方需要清楚说明节奏、边界、现实安排与实际互动;任何判断都需由两人的现实经验验证,不能由单一配置替代。"
sections = []
for heading in headings:
suffix = "D9 婚姻分盘用于检验长期承诺的结构,不能代替本命互动。" if heading == "能不能稳定走下去" else ""
sections.append(f"{heading}\n{(prose * 5) + suffix}")
return "\n".join(sections)
def _full_english_report() -> str:
headings = [
"Relationship Thesis", "What Each Person Brings", "Emotional Safety and Lived Experience",
"Attraction and Closeness", "Communication, Conflict and Repair",
"How the Relationship Progresses", "Shared Life: Gains and Pressures",
"Can It Stay Steady?", "Relationship Weather",
]
prose = "Each conclusion remains conditional on both charts, actual interaction, practical circumstances, and repeated real-world observation by both people. "
sections = []
for heading in headings:
suffix = "Navamsa (D9) qualifies long-term commitment and does not replace lived natal interaction. " if heading == "Can It Stay Steady?" else ""
sections.append(f"{heading}\n{(prose * 8) + suffix}")
return "\n".join(sections)
def test_receipt_requires_independent_full_report_shapes_without_forced_term_dumping():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
}
chinese = _full_chinese_report()
english = _full_english_report()
receipt = module.build_delivery_receipt(dossier, chinese, english)
assert receipt["status"] == "passed"
assert receipt["composition"]["english"] == "direct_from_structured_dossier_not_translated_from_chinese"
assert not any(receipt["supplementary_method_terms"]["english"].values())
def test_receipt_rejects_incomplete_or_chinese_english_delivery():
receipt = module.build_delivery_receipt({"delivery_readiness": "blocked"}, "结论总纲", "结论总纲")
assert receipt["status"] == "review_required"
def test_receipt_allows_primary_jyotish_terms_but_hides_supplementary_method_names():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
}
chinese = _full_chinese_report() + "\nD9 与 UL 的结论在此一致"
english = _full_english_report() + "\nNavamsa Upapada Darakaraka Vimshottari Narayana"
assert module.build_delivery_receipt(dossier, chinese, english)["status"] == "passed"
assert module.build_delivery_receipt(dossier, chinese, english + "\nWestern synastry")["status"] == "review_required"
assert module.build_delivery_receipt(dossier, chinese, english + "\nexecution_receipt")["status"] == "review_required"
assert module.build_delivery_receipt(dossier, chinese, english + "\nreader_section_brief")["status"] == "review_required"
def test_receipt_rejects_heading_only_or_fated_language():
dossier = {"schema": "jyotish.full_synastry_dossier.v1", "delivery_readiness": "ready_for_narrative", "source_map": [], "execution_receipt": {"pair_execution_tasks": []}}
assert module.build_delivery_receipt(dossier, "结论总纲", "Relationship Thesis")["reader_depth"]["status"] == "review_required"
assert module.build_delivery_receipt(dossier, _full_chinese_report() + "灵魂伴侣", _full_english_report())["status"] == "review_required"
def test_receipt_rejects_analyst_led_not_x_but_y_opening():
dossier = {"schema": "jyotish.full_synastry_dossier.v1", "delivery_readiness": "ready_for_narrative", "source_map": [], "execution_receipt": {"pair_execution_tasks": []}}
chinese = _full_chinese_report().replace("结论总纲", "结论总纲\n这段关系的核心,不是有没有吸引,而是能否落实承诺。", 1)
receipt = module.build_delivery_receipt(dossier, chinese, _full_english_report())
assert receipt["opening_quality"]["status"] == "review_required"
assert receipt["status"] == "review_required"
def test_receipt_requires_warm_reciprocal_opening_when_affection_evidence_is_executed():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
"mutual_affection_activation": {"status": "executed"},
}
cold_chinese = _full_chinese_report()
cold_english = _full_english_report()
cold = module.build_delivery_receipt(dossier, cold_chinese, cold_english)
assert cold["opening_affection_coverage"]["required_in_opening"] is True
assert cold["status"] == "review_required"
chinese = cold_chinese.replace(
"结论总纲\n", "结论总纲\nA 会在 B 的稳定回应里感到被重视与安心,B 也会在 A 的投入中感到被珍惜。\n", 1,
)
english = cold_english.replace(
"Relationship Thesis\n", "Relationship Thesis\nA feels valued and safe in B's steady response, while B feels cherished by A's investment.\n", 1,
)
receipt = module.build_delivery_receipt(dossier, chinese, english)
assert receipt["opening_affection_coverage"]["chinese_terms"]
assert receipt["opening_affection_coverage"]["english_terms"]
assert receipt["attraction_reciprocity_coverage"]["status"] == "review_required"
def test_receipt_rejects_long_report_with_empty_reader_sections():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
}
headings_zh = "\n".join(["结论总纲", "各自带入关系的需求", "情绪安全与相处感受", "吸引与亲密", "沟通、冲突与修复", "关系如何推进", "共同生活的收益与压力", "能不能稳定走下去", "关系应期"])
headings_en = "\n".join(["Relationship Thesis", "What Each Person Brings", "Emotional Safety and Lived Experience", "Attraction and Closeness", "Communication, Conflict and Repair", "How the Relationship Progresses", "Shared Life: Gains and Pressures", "Can It Stay Steady?", "Relationship Weather"])
receipt = module.build_delivery_receipt(
dossier,
headings_zh + "\n" + "双方需要核对实际互动与现实安排。" * 140,
headings_en + "\n" + "Both people need to verify practical interaction and real circumstances before drawing conclusions. " * 180,
)
assert receipt["reader_depth"]["status"] == "passed"
assert receipt["section_depth_coverage"]["status"] == "review_required"
assert receipt["status"] == "review_required"
def test_section_depth_recognizes_markdown_and_numbered_headings():
chinese = "## 一、结论总纲\n" + "双方需要把现实互动说清。" * 20
english = "## I. Relationship Thesis\n" + "Both people need clear real-world interaction before conclusions. " * 20
assert module._section_bodies(chinese, ("结论总纲",))["结论总纲"]
assert module._section_bodies(english, ("Relationship Thesis",))["Relationship Thesis"]
def test_receipt_requires_warmth_and_space_in_attraction_section_when_evidence_exists():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
"mutual_affection_activation": {"status": "executed"},
}
chinese = _full_chinese_report().replace(
"结论总纲\n", "结论总纲\nA 会在 B 的稳定回应里感到被重视与安心,B 也会在 A 的投入中感到被珍惜。\n", 1,
)
english = _full_english_report().replace(
"Relationship Thesis\n", "Relationship Thesis\nA feels valued and safe in B's steady response, while B feels cherished by A's investment.\n", 1,
)
cold_attraction = module.build_delivery_receipt(dossier, chinese, english)
assert cold_attraction["attraction_reciprocity_coverage"]["status"] == "review_required"
chinese = chinese.replace("吸引与亲密\n", "吸引与亲密\n双方在被珍惜时更愿意靠近,也要为彼此保留空间,避免压力累积。\n", 1)
english = english.replace("Attraction and Closeness\n", "Attraction and Closeness\nBoth feel warmer and closer when valued, while each needs space so pressure does not accumulate.\n", 1)
receipt = module.build_delivery_receipt(dossier, chinese, english)
assert receipt["attraction_reciprocity_coverage"]["status"] == "passed"
assert receipt["status"] == "passed"
def test_receipt_requires_d9_narrative_when_native_d9_pair_evidence_executed():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
"pair_interaction_evidence": {"d9_interaction_evidence": {"status": "executed"}},
}
receipt = module.build_delivery_receipt(dossier, _full_chinese_report(), _full_english_report())
assert receipt["status"] == "passed"
assert receipt["d9_narrative_coverage"]["required_in_narrative"] is True
without_d9 = _full_chinese_report().replace("D9 婚姻分盘用于检验长期承诺的结构,不能代替本命互动。", "")
assert module.build_delivery_receipt(dossier, without_d9, _full_english_report())["status"] == "review_required"
def test_single_language_receipt_accepts_an_independent_chinese_delivery():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
}
receipt = module.build_single_language_delivery_receipt(
dossier, _full_chinese_report(), "zh",
)
assert receipt["status"] == "passed"
assert receipt["schema"] == module.SINGLE_LANGUAGE_SCHEMA
assert receipt["composition"] == "direct_from_structured_dossier"
def test_single_language_receipt_keeps_affection_and_section_gates():
dossier = {
"schema": "jyotish.full_synastry_dossier.v1",
"delivery_readiness": "ready_for_narrative",
"source_map": [],
"execution_receipt": {"pair_execution_tasks": []},
"mutual_affection_activation": {"status": "executed"},
}
receipt = module.build_single_language_delivery_receipt(dossier, _full_chinese_report(), "zh")
assert receipt["status"] == "review_required"
warm = _full_chinese_report().replace(
"结论总纲\n", "结论总纲\n双方在稳定回应中感到被重视与珍惜,也能安心靠近。\n", 1,
).replace(
"吸引与亲密\n", "吸引与亲密\n彼此被珍惜时更愿意靠近,也需保留空间和边界,避免压力累积。\n", 1,
)
assert module.build_single_language_delivery_receipt(dossier, warm, "zh")["status"] == "passed"