Files
Jyotisha/tests/test_consult_evidence_card_research.py
T
Jesse_ChenandClaude Opus 5.5 850f18605b feat(consult): the answer model reads the answer contract plus an evidence card
New frontend/src/lib/consultation-evidence-card.ts ports the research
CARD_SPECS: base section (ascendant, house signs, placements with degrees,
functional benefics/malefics with lordship, Vimshottari MD/AD/PD with dates,
Narayana md/ad/pd) plus a section per domain; values copied verbatim from
the projection or engine context, gaps listed, never filled. The tool now
returns toModelEvidenceView: status, evidence_contract (policy, blockers,
layers, limitation), claim_cards = the card, evidence_card meta (D4 line,
supplementable sections), rectification, methodology, domains; the audit
table, spectra, must_use_layers and presentation stay server-side and the
single-domain consultations copy is gone. 「本轮技法」 rows are unchanged.
Golden tests over three public AA engine captures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-27 02:54:11 +08:00

141 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Pure-function checks for the consultation evidence-card research scripts."""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts" / "research"))
from consult_evidence_card_lib import ( # noqa: E402
CARD_SPECS,
CATEGORIES,
TELEMETRY_SPEC,
account,
category_report,
cut_evidence_card,
dumps,
parse_methodology_routes,
parse_must_use_layers,
parse_registry_layers,
verbatim_check,
)
def test_category_partition_sums_exactly():
payload = {
"ascendant": {"sign": "Leo", "degree": 12.5},
"methodology": {"sections": ["checklist"]},
"western_spectrum": {"zodiac": "tropical", "natal": {"sun": "Aries"}},
"varga_spectrum": {
"formal": {"D1": {"lagna": "Leo"}},
"research_dn": {"D3": {"lagna": "Virgo"}},
"extended": {"D81": {"lagna": "Cancer"}},
},
"technique_audit_table": [
{"technique": "Functional Benefic/Malefic", "status": "executed"},
{"technique": "MEVG / Global Web Evidence", "status": "blocked"},
{"technique": "Prashna chart", "status": "not_applicable"},
{"technique": "Research D-N through D60", "status": "executed"},
{"technique": "Western natal (tropical)", "status": "executed", "system": "western"},
],
}
report = category_report(payload)
assert report["sum_error_ratio"] == 0.0
assert report["category_sum"] == report["total_chars"] == len(dumps(payload))
assert set(report["categories"]) == set(CATEGORIES)
assert report["categories"]["western"] > 0
assert report["categories"]["research"] > 0
assert report["categories"]["status"] > 0
assert report["categories"]["not_applicable"] > 0
assert report["categories"]["core"] > 0
assert sum(account(payload).values()) == len(dumps(payload))
def test_card_copies_projection_values_without_rewriting():
model = {
"question": "我和父母关系如何",
"route": "family",
"claim_cards": [
{
"category": "natal_foundation",
"evidence": {
"ascendant": {"sign": "Capricorn", "degree": 3.25},
"houses": [{"number": 4, "sign": "Aries", "lord": "Mars"}],
"planets": {"sun": {"sign": "Aquarius", "house": 2}, "moon": {"sign": "Cancer", "house": 7}},
"functional_benefic_malefic": {"functional_benefics": ["Venus"], "functional_malefics": ["Mars"]},
"varga_spectrum": {"formal": {"D12": {"lagna": "Pisces", "planets": {"moon": "Leo"}}}},
},
},
{
"category": "timing",
"evidence": {
"dasha_sub_periods": {
"current": {
"mahadasha": {"lord": "Saturn", "start": "2020-01-01", "end": "2026-12-31"},
"antardasha": {"lord": "Mercury", "start": "2024-01-01", "end": "2025-01-01"},
},
},
"narayana_dasha": {"current_dasha": {"md": {"sign": "Scorpio"}}},
},
},
],
}
cut = cut_evidence_card(model, "parents")
assert cut["card"]["domain"]["vargas"]["D12"]["lagna"] == "Pisces"
assert cut["card"]["base"]["ascendant"]["degree"] == 3.25
assert "D7" not in cut["card"]["domain"]["vargas"]
check = verbatim_check(cut["card"], {
"ascendant_sign": "Capricorn",
"d12_lagna": "Pisces",
"d12_moon": "Leo",
"vimshottari_start": "2020-01-01",
"vimshottari_end": "2026-12-31",
"moon_sign": "Cancer",
"moon_house": 7,
})
assert check["ok"] is True
assert check["checks"]["vimshottari_start"]["status"] == "match"
def test_source_parsers_keep_family_split_gap():
registry = (ROOT / "frontend/src/lib/consultation-domain-registry.ts").read_text(encoding="utf-8")
methodology = (ROOT / "frontend/src/lib/consultation-methodology.ts").read_text(encoding="utf-8")
workflow = (ROOT / "frontend/src/mastra/consultation-workflow.ts").read_text(encoding="utf-8")
layers = parse_registry_layers(registry)
routes = parse_methodology_routes(methodology)
must_use = parse_must_use_layers(workflow)
assert "D12" in layers["family"] and "D7" in layers["family"]
assert "父母" not in "".join(layers["family"])
assert routes["family"] is None
# 原值:assert "family" not in must_use(调研时前端必用层没有 family)。
# 新值:family / parents / children 都有必用层,父母、子女有独立方法学条目(无命名清单)。
# 原因:TASK-consult-evidence-card-20260927 T2 按调研结论补齐;调研快照的「缺口」已修。
assert must_use["family"] == ["Formal Vargas D1–D60", "Narayana Dasha"]
assert must_use["parents"] == must_use["children"] == must_use["family"]
assert routes["parents"] is None and routes["children"] is None
assert "D12" in layers["parents"] and "D7" in layers["children"]
assert CARD_SPECS["parents"]["vargas"] == ["D12"]
assert CARD_SPECS["children"]["vargas"] == ["D7"]
def test_telemetry_spec_stores_no_user_text():
banned = {"question text", "answer text", "birth date", "name", "email", "user id"}
assert banned <= set(TELEMETRY_SPEC["does_not_store"])
stored = {field["name"] for field in TELEMETRY_SPEC["fields"]}
assert stored == {"domain", "card_version", "card_chars", "card_token_estimate", "cited_field_ids", "feedback"}
assert "matched substring" in TELEMETRY_SPEC["does_not_store"]
def test_single_domain_wrap_source_still_matches_projector():
# 原值:assert "return { ...consultations[0], ...plan, consultations };" in source
# (调研投影脚本模仿的「单领域整包再复制进 consultations」)。
# 新值:服务端完整上下文单领域不再复制整包;模型读 toModelEvidenceView(答题契约 + 数据卡)。
# 调研脚本 project_consult_model_context.ts 仍按旧形状复现「改前」体量,作为基线快照保留。
# 原因:TASK-consult-evidence-card-20260927 T3「去掉 consultations 整包重复」。
source = (ROOT / "frontend/src/mastra/consultation-tools.ts").read_text(encoding="utf-8")
assert "return { ...consultations[0], ...plan, consultations };" not in source
assert "return { ...consultations[0], ...plan };" in source
assert "export function toModelEvidenceView(" in source