fix(report): fill the full-data edition and clear English Han
Add the interpretation pages from fields the engine already computed, project the annual tables the reader prints, and clear English Han on the four measured charts. Patyayini is not implemented. The generate button copy is unchanged. This commit stays on the feature branch and is not pushed to staging.
This commit is contained in:
@@ -82,14 +82,11 @@ def test_chinese_edition_is_untouched_by_the_english_render(rendered) -> None:
|
||||
|
||||
def test_english_edition_has_no_chinese(rendered) -> None:
|
||||
_, _, en, _ = rendered
|
||||
# 原值:阅读版英文 han_leaks 为空
|
||||
# 新值:完整数据版英文若仍含汉字,必须是清理器留下的 source text retained 标记;清干净时汉字为空
|
||||
# 原因:BUG-1272。公开接口整份撤回英文,不把夹中文的英文交给用户;见 API 测试
|
||||
if HAN.search(en):
|
||||
assert "[source text retained:" in en
|
||||
else:
|
||||
assert han_leaks(en) == []
|
||||
assert not HAN.search(en)
|
||||
# 原值:有汉字就必须是 source text retained
|
||||
# 新值:英文全文汉字数为 0
|
||||
# 原因:BUG-1272。术语补齐后,这三张虚构盘不得再留下汉字
|
||||
assert re.findall(r"[㐀-鿿豈-]+", en) == []
|
||||
assert han_leaks(en) == []
|
||||
|
||||
|
||||
def test_english_edition_passes_reader_leak_patterns(rendered) -> None:
|
||||
@@ -166,16 +163,13 @@ def test_api_without_languages_is_unchanged_and_with_languages_adds_english() ->
|
||||
assert both["markdown"] == plain["markdown"]
|
||||
assert both["fact_table_packet"] == plain["fact_table_packet"]
|
||||
assert both["reader_dasha_applicability"] == plain["reader_dasha_applicability"]
|
||||
# 原值:阅读版一定带回无汉字的 markdown_en
|
||||
# 新值:英文要么整份无汉字,要么 english_unavailable=han_leak 且不带 markdown_en
|
||||
# 原因:BUG-1272,完整数据版英文清理后仍有汉字时走既有「英文暂不可用」
|
||||
if "markdown_en" in both:
|
||||
assert not HAN.search(both["markdown_en"])
|
||||
assert not HAN.search(both.get("reader_dasha_applicability_en") or "")
|
||||
assert "english_unavailable" not in both
|
||||
else:
|
||||
assert both["english_unavailable"] == "han_leak"
|
||||
assert "markdown_en" not in both
|
||||
# 原值:英文要么整份无汉字,要么 english_unavailable=han_leak 且不带 markdown_en
|
||||
# 新值:虚构日盘必须带回无汉字的 markdown_en
|
||||
# 原因:BUG-1272。这张盘英文已清零,接口应交付英文;人为泄漏仍由下一条测试撤回
|
||||
assert "markdown_en" in both
|
||||
assert not HAN.search(both["markdown_en"])
|
||||
assert not HAN.search(both.get("reader_dasha_applicability_en") or "")
|
||||
assert "english_unavailable" not in both
|
||||
zh_only = _api_response(packet, {**base_body, "languages": ["zh"]})
|
||||
assert json.dumps(zh_only, sort_keys=True, ensure_ascii=False) == json.dumps(plain, sort_keys=True, ensure_ascii=False)
|
||||
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
"""Report completion for the full-data edition (TASK-report-full-data-fix-20261008).
|
||||
|
||||
Template wording, annual field projection, the opening focus, and the two
|
||||
mistranslations. Chart numbers come from the packet. These tests do not
|
||||
calculate a new dasha or import PyJHora.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import re
|
||||
|
||||
from scripts.pl9_full_data_export import _sanitize_pl9_ai_density_markdown, render_full_data_markdown
|
||||
from scripts.pl9_interpretation_packs import (
|
||||
attach_full_data_interpretation,
|
||||
missing_field_count,
|
||||
opening_focus_block,
|
||||
section_coverage,
|
||||
)
|
||||
from scripts.pl9_reader_english import HAN
|
||||
|
||||
FORBIDDEN_ZH = (
|
||||
"再婚",
|
||||
"几段关系",
|
||||
"早夭",
|
||||
"一定会",
|
||||
"必然",
|
||||
"Neecha Bhanga Raja Yoga",
|
||||
"落陷取消王",
|
||||
"疾病诊断",
|
||||
"疾病",
|
||||
)
|
||||
FORBIDDEN_EN = (
|
||||
"divorce",
|
||||
"miscarriage",
|
||||
"infertility",
|
||||
"guarantee",
|
||||
"guaranteed",
|
||||
)
|
||||
HALF_TRANSLATED = re.compile(r"[A-Za-z]+\s*[\u4e00-\u9fff]+s")
|
||||
|
||||
|
||||
def _planet(sign: str, house: int, nakshatra: str, status: str = "Own Sign") -> dict:
|
||||
return {"sign": sign, "house": house, "status": status, "nakshatra": nakshatra}
|
||||
|
||||
|
||||
def _packet(language: str = "zh") -> dict:
|
||||
planets = {
|
||||
"Sun": _planet("Aries", 10, "Ashwini", "入旺(Exalted)"),
|
||||
"Moon": _planet("Taurus", 2, "Rohini"),
|
||||
"Mars": _planet("Capricorn", 7, "Exalted"),
|
||||
"Mercury": _planet("Pisces", 6, "Debilitated"),
|
||||
"Jupiter": _planet("Cancer", 1, "Exalted"),
|
||||
"Venus": _planet("Libra", 4, "Own Sign"),
|
||||
"Saturn": _planet("Aquarius", 8, "Own Sign"),
|
||||
"Rahu": _planet("Gemini", 12, "Ardra", ""),
|
||||
"Ketu": _planet("Sagittarius", 6, "Mula", ""),
|
||||
}
|
||||
lords = ["Mars", "Venus", "Mercury", "Moon", "Sun", "Mercury", "Venus", "Mars", "Jupiter", "Saturn", "Saturn", "Jupiter"]
|
||||
houses = {f"house_{index}": {"lord": lord, "cusp_sign": "Aries"} for index, lord in enumerate(lords, start=1)}
|
||||
timeline = []
|
||||
for lord in ("Sun", "Moon", "Mars"):
|
||||
current = lord == "Moon"
|
||||
timeline.append({
|
||||
"lord": lord,
|
||||
"start": "2000-01-01",
|
||||
"end": "2006-01-01",
|
||||
"is_current": current,
|
||||
"antardasha_timeline": [{
|
||||
"lord": "Mars",
|
||||
"start": "2001-01-01",
|
||||
"end": "2002-01-01",
|
||||
"is_current": current,
|
||||
"pratyantar_dasha_timeline": [{
|
||||
"lord": "Mercury",
|
||||
"start": "2001-02-01",
|
||||
"end": "2001-04-01",
|
||||
"is_current": current,
|
||||
}],
|
||||
}],
|
||||
})
|
||||
return {
|
||||
"report_language": language,
|
||||
"birth_info": {"name": "虚构甲" if language == "zh" else "Fictional"},
|
||||
"worksheets": {
|
||||
"d1_rasi_bhava": {"planets": planets, "houses": houses, "ascendant": {"sign": "Cancer"}},
|
||||
"strengths_and_scores": {
|
||||
"functional_benefic_malefic": {
|
||||
"functional_benefics": ["Jupiter", "Mars"],
|
||||
"functional_malefics": ["Saturn"],
|
||||
"functional_neutrals": ["Moon"],
|
||||
},
|
||||
"shadbala": {"planets": {"Sun": {"total": 1.25}}},
|
||||
},
|
||||
"timing_and_predictive_systems": {
|
||||
"dasha": {"timeline": timeline, "current_dasha": timeline[1]},
|
||||
"annual_tajika_pack": {
|
||||
"solar_return": {"status": "partial_verified", "data": {"dt_local": "2026-04-07T09:00:00"}},
|
||||
"mudda_dasha": {
|
||||
"status": "partial_verified",
|
||||
"periods": [{"lord": "Sun", "start": "2026-04-07", "end": "2026-05-07", "months": 1}],
|
||||
},
|
||||
"patyayini_dasha": {"status": "blocked", "reason": "not_in_engine"},
|
||||
"sahams": {"status": "partial_verified", "data": [{"name": "Punya", "sign": "Aries", "degree_in_sign": 1.2}]},
|
||||
"tajika_yogas": {
|
||||
"status": "partial_verified",
|
||||
"data": {"yogas": [{"name": "Ithasala", "present": True, "planets": ["Sun", "Moon"]}]},
|
||||
},
|
||||
"monthly_windows": [{
|
||||
"index": 1,
|
||||
"lord": "Sun",
|
||||
"duration_months": 1,
|
||||
"start": "2026-04-07",
|
||||
"end": "2026-05-07",
|
||||
}],
|
||||
},
|
||||
},
|
||||
"advanced_systems": {
|
||||
"yoga": {
|
||||
"detected_yogas": [{
|
||||
"name": "Gajakesari Yoga",
|
||||
"name_cn": "象鹿瑜伽",
|
||||
"category": "raja",
|
||||
"effects": ["名声可见"],
|
||||
"effects_en": ["visible reputation"],
|
||||
"planets": ["Moon", "Jupiter"],
|
||||
"combination": "Moon and Jupiter",
|
||||
}, {
|
||||
"name": "Neecha Bhanga Raja Yoga",
|
||||
"name_cn": "落陷取消王瑜伽",
|
||||
"category": "neecha_bhanga",
|
||||
"effects": ["传统条件成立"],
|
||||
"effects_en": ["the cancellation conditions hold"],
|
||||
"planets": ["Mercury"],
|
||||
}],
|
||||
},
|
||||
"yogas_doshas": {"mangal_dosha": {"has_dosha": False, "mars_house": 7, "severity": "none"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_t5_repairs_bhava_bala_and_planets_suffix() -> None:
|
||||
raw = "\n".join([
|
||||
"# 印度占星星盘报告",
|
||||
"",
|
||||
"### p31-p33 Shadbala / Bhava Bala 摘要",
|
||||
"",
|
||||
"### p32 Bhava Bala 十二宫力量",
|
||||
"",
|
||||
"### p125 Natal / KP Ruling Planets",
|
||||
"",
|
||||
"### Upagraha and Sub-Planets Points",
|
||||
"",
|
||||
"### Planetary Friendship Matrix",
|
||||
"",
|
||||
])
|
||||
text = _sanitize_pl9_ai_density_markdown(raw)
|
||||
assert "Bhava 年龄状态" not in text
|
||||
assert "六维力量 / Bhava Bala" in text
|
||||
assert "Bhava Bala 十二宫力量" in text
|
||||
assert "行星s" not in text
|
||||
assert "本命 / KP 征象星" in text
|
||||
assert HALF_TRANSLATED.search(text) is None
|
||||
assert "年龄状态" not in text.split("Graha Avastha", 1)[-1] or "Baladi" not in raw
|
||||
|
||||
|
||||
def test_templates_cover_required_sections_and_forbidden_wording() -> None:
|
||||
packet = _packet("zh")
|
||||
attach_full_data_interpretation(packet)
|
||||
focus = opening_focus_block(packet)
|
||||
assert focus.startswith("重点:")
|
||||
assert "MD" in focus and "AD" in focus and "PD" in focus
|
||||
assert "第10宫" in focus and "第2宫" in focus and "第7宫" in focus
|
||||
text = render_full_data_markdown(packet)
|
||||
for heading in ("大运解释", "行星、星宿与宫位解释", "宫主逐宫解释", "Dosha 逐项事实与解释", "瑜伽解释"):
|
||||
assert heading in text
|
||||
assert "Patyayini 没有实现" in text
|
||||
assert "Mudda 月段窗口" in text
|
||||
assert "blocked" not in text.lower()
|
||||
for phrase in FORBIDDEN_ZH:
|
||||
assert phrase not in text
|
||||
assert "落陷取消(Neecha Bhanga" in text
|
||||
assert "Raja Yoga" not in text
|
||||
assert HALF_TRANSLATED.search(text) is None
|
||||
assert "行星s" not in text
|
||||
coverage = {row["section"]: row["status"] for row in section_coverage(packet)}
|
||||
assert coverage["sthira"] == "out_of_scope"
|
||||
assert "Sthira Dasha" not in text
|
||||
assert missing_field_count(packet) <= 10
|
||||
|
||||
|
||||
def test_english_focus_and_new_sections_have_no_han() -> None:
|
||||
packet = _packet("en")
|
||||
text = render_full_data_markdown(packet)
|
||||
assert "Focus: current Maha Dasha MD" in text
|
||||
assert "AD" in text and "PD" in text
|
||||
assert "Dasha Interpretation" in text
|
||||
assert "House-lord interpretation" in text
|
||||
assert "Yoga interpretation" in text
|
||||
assert "Patyayini is not implemented" in text
|
||||
assert "Monthly mudda windows" in text
|
||||
for phrase in FORBIDDEN_EN:
|
||||
assert phrase not in text.lower()
|
||||
assert "Neecha Bhanga Raja Yoga" not in text
|
||||
assert "not a Raja Yoga" in text
|
||||
leaked = HAN.findall(text)
|
||||
assert leaked == [], leaked[:12]
|
||||
|
||||
|
||||
def test_chinese_render_stays_stable_when_english_uses_a_copy() -> None:
|
||||
packet = _packet("zh")
|
||||
before = render_full_data_markdown(copy.deepcopy(packet))
|
||||
english = copy.deepcopy(packet)
|
||||
english["report_language"] = "en"
|
||||
render_full_data_markdown(english)
|
||||
after = render_full_data_markdown(copy.deepcopy(packet))
|
||||
assert after == before
|
||||
Reference in New Issue
Block a user