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>
167 lines
7.3 KiB
Python
167 lines
7.3 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MODULE_PATH = ROOT / "skills" / "jyotish-full-synastry-reading" / "scripts" / "compose_full_synastry_delivery.py"
|
|
spec = importlib.util.spec_from_file_location("compose_full_synastry_delivery", MODULE_PATH)
|
|
module = importlib.util.module_from_spec(spec)
|
|
assert spec and spec.loader
|
|
spec.loader.exec_module(module)
|
|
|
|
|
|
def _dossier(*, affection="not_available"):
|
|
return {
|
|
"schema": "jyotish.full_synastry_dossier.v1",
|
|
"delivery_readiness": "ready_for_narrative",
|
|
"reader_section_brief": [{"section": key} for key in module.SECTION_KEYS],
|
|
"source_map": [],
|
|
"execution_receipt": {"pair_execution_tasks": []},
|
|
"mutual_affection_activation": {"status": affection},
|
|
}
|
|
|
|
|
|
def _payload(language: str):
|
|
if language == "zh":
|
|
prose = "双方需要清楚说明节奏、边界、现实安排与实际互动;任何判断都需由两人的现实经验验证,不能由单一配置替代。"
|
|
sections = {key: prose * 5 for key in module.SECTION_KEYS}
|
|
return {
|
|
"language": "zh",
|
|
"composition": module.EXPECTED_COMPOSITION,
|
|
"title": "双方的恋爱与婚姻合盘",
|
|
"sections": sections,
|
|
}
|
|
prose = "Each conclusion remains conditional on both charts, actual interaction, practical circumstances, and repeated real-world observation by both people. "
|
|
sections = {key: prose * 8 for key in module.SECTION_KEYS}
|
|
return {
|
|
"language": "en",
|
|
"composition": module.EXPECTED_COMPOSITION,
|
|
"title": "Full Love and Marriage Synastry Reading",
|
|
"sections": sections,
|
|
}
|
|
|
|
|
|
def test_compiler_requires_ready_dossier_and_independent_complete_section_payloads():
|
|
compiled = module.compile_delivery(_dossier(), _payload("zh"), _payload("en"))
|
|
assert compiled["delivery_receipt"]["status"] == "passed"
|
|
assert "## 结论总纲" in compiled["chinese_markdown"]
|
|
assert "## Relationship Thesis" in compiled["english_markdown"]
|
|
assert "reader_section_brief" not in compiled["english_markdown"]
|
|
|
|
incomplete = _payload("zh")
|
|
del incomplete["sections"]["relationship_weather"]
|
|
with pytest.raises(ValueError, match="missing=relationship_weather"):
|
|
module.compile_delivery(_dossier(), incomplete, _payload("en"))
|
|
with pytest.raises(ValueError, match="not ready_for_narrative"):
|
|
module.compile_delivery({**_dossier(), "delivery_readiness": "blocked"}, _payload("zh"), _payload("en"))
|
|
|
|
|
|
def test_compiler_requires_private_output_directory(tmp_path):
|
|
assert module._private_output_directory(str(tmp_path)) == tmp_path.resolve()
|
|
with pytest.raises(ValueError, match="outside the repository"):
|
|
module._private_output_directory(str(ROOT / "outputs"))
|
|
|
|
|
|
def test_cli_writes_only_a_passed_private_delivery(tmp_path, monkeypatch):
|
|
dossier_path = tmp_path / "dossier.json"
|
|
chinese_path = tmp_path / "chinese.json"
|
|
english_path = tmp_path / "english.json"
|
|
output_dir = tmp_path / "delivery"
|
|
dossier_path.write_text(json.dumps(_dossier()), encoding="utf-8")
|
|
chinese_path.write_text(json.dumps(_payload("zh"), ensure_ascii=False), encoding="utf-8")
|
|
english_path.write_text(json.dumps(_payload("en")), encoding="utf-8")
|
|
monkeypatch.setattr(sys, "argv", [
|
|
"compose_full_synastry_delivery.py",
|
|
"--dossier", str(dossier_path),
|
|
"--chinese-sections", str(chinese_path),
|
|
"--english-sections", str(english_path),
|
|
"--output-dir", str(output_dir),
|
|
])
|
|
|
|
assert module.main() == 0
|
|
assert (output_dir / "Chinese-Full-Synastry-Report.md").is_file()
|
|
assert (output_dir / "English-Full-Synastry-Report.md").is_file()
|
|
receipt = json.loads((output_dir / "bilingual-delivery-receipt.json").read_text(encoding="utf-8"))
|
|
assert receipt["status"] == "passed"
|
|
|
|
|
|
def test_cli_does_not_create_output_directory_when_the_gate_fails(tmp_path, monkeypatch):
|
|
dossier_path = tmp_path / "dossier.json"
|
|
chinese_path = tmp_path / "chinese.json"
|
|
english_path = tmp_path / "english.json"
|
|
output_dir = tmp_path / "failed-delivery"
|
|
dossier_path.write_text(json.dumps({**_dossier(), "delivery_readiness": "blocked"}), encoding="utf-8")
|
|
chinese_path.write_text(json.dumps(_payload("zh"), ensure_ascii=False), encoding="utf-8")
|
|
english_path.write_text(json.dumps(_payload("en")), encoding="utf-8")
|
|
monkeypatch.setattr(sys, "argv", [
|
|
"compose_full_synastry_delivery.py",
|
|
"--dossier", str(dossier_path),
|
|
"--chinese-sections", str(chinese_path),
|
|
"--english-sections", str(english_path),
|
|
"--output-dir", str(output_dir),
|
|
])
|
|
|
|
with pytest.raises(ValueError, match="not ready_for_narrative"):
|
|
module.main()
|
|
assert not output_dir.exists()
|
|
|
|
|
|
def test_cli_dry_run_validates_without_creating_a_delivery(tmp_path, monkeypatch, capsys):
|
|
dossier_path = tmp_path / "dossier.json"
|
|
chinese_path = tmp_path / "chinese.json"
|
|
english_path = tmp_path / "english.json"
|
|
output_dir = tmp_path / "dry-run-delivery"
|
|
dossier_path.write_text(json.dumps(_dossier()), encoding="utf-8")
|
|
chinese_path.write_text(json.dumps(_payload("zh"), ensure_ascii=False), encoding="utf-8")
|
|
english_path.write_text(json.dumps(_payload("en")), encoding="utf-8")
|
|
monkeypatch.setattr(sys, "argv", [
|
|
"compose_full_synastry_delivery.py",
|
|
"--dossier", str(dossier_path),
|
|
"--chinese-sections", str(chinese_path),
|
|
"--english-sections", str(english_path),
|
|
"--output-dir", str(output_dir),
|
|
"--dry-run",
|
|
])
|
|
|
|
assert module.main() == 0
|
|
assert json.loads(capsys.readouterr().out)["status"] == "would-deliver"
|
|
assert not output_dir.exists()
|
|
|
|
|
|
def test_publisher_refuses_to_overwrite_an_existing_private_delivery(tmp_path):
|
|
output_dir = tmp_path / "existing-delivery"
|
|
output_dir.mkdir()
|
|
marker = output_dir / "do-not-overwrite.txt"
|
|
marker.write_text("existing", encoding="utf-8")
|
|
compiled = module.compile_delivery(_dossier(), _payload("zh"), _payload("en"))
|
|
|
|
with pytest.raises(ValueError, match="already exists"):
|
|
module._publish_delivery_bundle(output_dir, compiled)
|
|
assert marker.read_text(encoding="utf-8") == "existing"
|
|
|
|
|
|
def test_single_language_compiler_and_cli_publish_without_a_placeholder_peer(tmp_path, monkeypatch):
|
|
compiled = module.compile_single_language_delivery(_dossier(), _payload("zh"), "zh")
|
|
assert compiled["delivery_receipt"]["status"] == "passed"
|
|
assert "## 结论总纲" in compiled["markdown"]
|
|
|
|
dossier_path = tmp_path / "dossier.json"
|
|
sections_path = tmp_path / "zh.json"
|
|
output_dir = tmp_path / "zh-delivery"
|
|
dossier_path.write_text(json.dumps(_dossier()), encoding="utf-8")
|
|
sections_path.write_text(json.dumps(_payload("zh"), ensure_ascii=False), encoding="utf-8")
|
|
monkeypatch.setattr(sys, "argv", [
|
|
"compose_full_synastry_delivery.py", "--dossier", str(dossier_path),
|
|
"--language", "zh", "--sections", str(sections_path), "--output-dir", str(output_dir),
|
|
])
|
|
assert module.main() == 0
|
|
assert (output_dir / "Chinese-Full-Synastry-Report.md").is_file()
|
|
assert (output_dir / "zh-delivery-receipt.json").is_file()
|
|
assert not (output_dir / "English-Full-Synastry-Report.md").exists()
|