diff --git a/artifacts/real_case_site_e2e_summary/real_case_website_e2e_extended_route_smoke_summary_2026_07_20.json b/artifacts/real_case_site_e2e_summary/real_case_website_e2e_extended_route_smoke_summary_2026_07_20.json new file mode 100644 index 00000000..0ff3beb1 --- /dev/null +++ b/artifacts/real_case_site_e2e_summary/real_case_website_e2e_extended_route_smoke_summary_2026_07_20.json @@ -0,0 +1,26 @@ +{ + "batch_max_items": 10, + "batch_offsets": [ + 0, + 20, + 40 + ], + "boundary": "Extended route smoke for migration/family/education/annual/health real-case E2E; product QA only.", + "captured_count": 30, + "core_status_counts": { + "ready": 30 + }, + "created_at": "2026-07-20", + "missing_route_layer_total": 0, + "production_tuning_allowed": false, + "route_counts": { + "career": 7, + "education": 1, + "family": 1, + "finance": 4, + "migration": 4, + "timing": 13 + }, + "scope": "real_case_website_e2e_extended_route_smoke_summary", + "truth_matrix_allowed": false +} diff --git a/scripts/capture_commercial_astrology_e2e_contexts.py b/scripts/capture_commercial_astrology_e2e_contexts.py index d42856ae..68aba2c4 100644 --- a/scripts/capture_commercial_astrology_e2e_contexts.py +++ b/scripts/capture_commercial_astrology_e2e_contexts.py @@ -73,24 +73,30 @@ def _capture_body_for_real_case(case: dict[str, Any], prompt: str) -> dict[str, year, month, day = [int(part) for part in birth["date"].split("-")] hour, minute = [int(part) for part in birth["time"].split(":")[:2]] theme_map = { - "timing": "career", "annual": "career", - "migration": "career", - "family": "marriage", "education": "career", + "family": "marriage", + "migration": "career", + "timing": "career", } themes = [theme_map.get(domain, domain) for domain in case["domains"]] prompt_prefix = "" - if "marriage" in case["domains"] or "family" in case["domains"]: - prompt_prefix = "婚恋 relationship marriage: " - elif "wealth" in case["domains"]: - prompt_prefix = "财富 finance wealth: " - elif "timing" in case["domains"] or "annual" in case["domains"]: - prompt_prefix = "应期 timing when: " - elif "health" in case["domains"]: + if "迁移" in prompt or "海外" in prompt: + prompt_prefix = "迁移 migration foreign abroad: " + elif "家庭" in prompt or "子女" in prompt: + prompt_prefix = "家庭 family children home: " + elif "学习" in prompt or "教育" in prompt: + prompt_prefix = "教育 education study: " + elif "年度" in prompt or "运势" in prompt: + prompt_prefix = "年度 annual yearly forecast: " + elif "健康" in prompt: prompt_prefix = "健康 health: " - elif "migration" in case["domains"]: - prompt_prefix = "迁移 foreign career: " + elif "婚恋" in prompt or "关系" in prompt: + prompt_prefix = "婚恋 relationship marriage: " + elif "财富" in prompt or "风险" in prompt: + prompt_prefix = "财富 finance wealth: " + elif "阶段" in prompt or "何时" in prompt: + prompt_prefix = "应期 timing when: " return { "year": year, "month": month, diff --git a/scripts/unified_consultation_orchestrator.py b/scripts/unified_consultation_orchestrator.py index ea5d5d7e..2289397b 100644 --- a/scripts/unified_consultation_orchestrator.py +++ b/scripts/unified_consultation_orchestrator.py @@ -87,6 +87,14 @@ class UnifiedConsultationOrchestrator: "wealth": "wealth", "career": "career", "health": "health", + "migration": "migration", + "foreign": "migration", + "education": "education", + "study": "education", + "family": "family", + "children": "family", + "annual": "annual", + "yearly": "annual", "spirituality": "spirituality", "事业": "career", "婚恋": "marriage", @@ -95,10 +103,28 @@ class UnifiedConsultationOrchestrator: "财富": "wealth", "财运": "wealth", "健康": "health", + "迁移": "migration", + "海外": "migration", + "教育": "education", + "学习": "education", + "家庭": "family", + "子女": "family", + "年度": "annual", + "流年": "annual", "灵性": "spirituality", } _DEFAULT_THEMES = ["career", "marriage", "wealth"] - _ALLOWED_THEMES = {"career", "marriage", "wealth", "health", "spirituality"} + _ALLOWED_THEMES = { + "annual", + "career", + "education", + "family", + "health", + "marriage", + "migration", + "spirituality", + "wealth", + } _ROUTE_DEFINITIONS = { "career": RouteDefinition( question_type="career", @@ -124,6 +150,30 @@ class UnifiedConsultationOrchestrator: focus_techniques=["D1", "D6", "D8", "Dasha", "Shadbala", "non-medical boundary"], display_label="health", ), + "migration": RouteDefinition( + question_type="migration", + primary_theme="migration", + focus_techniques=["D4", "D12", "12th house", "Dasha", "Narayana Dasha"], + display_label="migration", + ), + "family": RouteDefinition( + question_type="family", + primary_theme="family", + focus_techniques=["D7", "D12", "4th house", "5th house", "9th house", "Dasha"], + display_label="family", + ), + "education": RouteDefinition( + question_type="education", + primary_theme="education", + focus_techniques=["D5", "D24", "5th house", "9th house", "Dasha"], + display_label="education", + ), + "annual": RouteDefinition( + question_type="annual", + primary_theme="annual", + focus_techniques=["Annual chart boundary", "Dasha", "Transit", "Tajika candidate", "claim boundary"], + display_label="annual", + ), "timing": RouteDefinition( question_type="timing", primary_theme="career", @@ -142,6 +192,10 @@ class UnifiedConsultationOrchestrator: "relationship": ["compute_chart", "run_rectification_gate", "run_thematic_report"], "finance": ["compute_chart", "run_rectification_gate", "run_thematic_report"], "health": ["compute_chart", "run_rectification_gate", "run_thematic_report"], + "migration": ["compute_chart", "run_rectification_gate", "run_thematic_report"], + "family": ["compute_chart", "run_rectification_gate", "run_thematic_report"], + "education": ["compute_chart", "run_rectification_gate", "run_thematic_report"], + "annual": ["compute_chart", "run_rectification_gate", "run_muhurta_panchanga", "run_thematic_report"], "timing": ["compute_chart", "run_rectification_gate", "run_muhurta_panchanga", "run_thematic_report"], "general": ["compute_chart", "run_rectification_gate", "run_thematic_report"], } @@ -180,6 +234,10 @@ class UnifiedConsultationOrchestrator: "relationship": ("marriage", "married", "wedding", "relationship", "love", "spouse", "partner", "divorce", "婚恋", "婚姻", "感情", "配偶", "恋爱", "结婚", "marry"), "finance": ("money", "wealth", "finance", "investment", "property", "income", "财务", "财富", "投资", "房产", "收入"), "health": ("health", "illness", "medical", "disease", "vitality", "健康", "疾病", "病", "体力", "医疗"), + "migration": ("migration", "foreign", "abroad", "overseas", "relocation", "迁移", "海外", "出国", "搬迁", "远方"), + "family": ("family", "children", "home", "mother", "father", "家庭", "子女", "孩子", "父母", "家宅"), + "education": ("education", "study", "learning", "school", "degree", "学习", "教育", "学历", "学校", "考试"), + "annual": ("annual", "yearly", "this year", "next year", "年度", "流年", "今年", "明年", "年运"), } first_hits: list[tuple[int, str]] = [] for route_name, tokens in domain_tokens.items(): @@ -205,6 +263,14 @@ class UnifiedConsultationOrchestrator: route = self._ROUTE_DEFINITIONS["finance"] elif "health" in normalized_themes: route = self._ROUTE_DEFINITIONS["health"] + elif "migration" in normalized_themes: + route = self._ROUTE_DEFINITIONS["migration"] + elif "family" in normalized_themes: + route = self._ROUTE_DEFINITIONS["family"] + elif "education" in normalized_themes: + route = self._ROUTE_DEFINITIONS["education"] + elif "annual" in normalized_themes: + route = self._ROUTE_DEFINITIONS["annual"] else: route = self._ROUTE_DEFINITIONS["general"] diff --git a/tests/test_unified_consultation_orchestrator.py b/tests/test_unified_consultation_orchestrator.py index 28f7a157..ed009ae7 100644 --- a/tests/test_unified_consultation_orchestrator.py +++ b/tests/test_unified_consultation_orchestrator.py @@ -29,6 +29,21 @@ def test_unified_consultation_orchestrator_routes_health_questions() -> None: assert "non-medical boundary" in route["focus_techniques"] +def test_unified_consultation_orchestrator_routes_extended_product_domains() -> None: + orchestrator = UnifiedConsultationOrchestrator() + cases = [ + ("海外迁移 relocation", ["migration"], "migration", "D12"), + ("家庭子女 home children", ["family"], "family", "D7"), + ("教育学习 school degree", ["education"], "education", "D24"), + ("今年年度运势 annual forecast", ["annual"], "annual", "Tajika candidate"), + ] + for question, raw_themes, expected_route, expected_layer in cases: + themes = orchestrator.normalize_themes(raw_themes) + route = orchestrator.resolve_route(question, themes) + assert route["question_type"] == expected_route + assert expected_layer in route["focus_techniques"] + + def test_unified_consultation_orchestrator_exposes_surface_agnostic_contract() -> None: orchestrator = UnifiedConsultationOrchestrator() route = orchestrator.resolve_route("When will I marry?", ["marriage"])