From ac6f4ed85f852f7860a26d669668843f04df7e9e Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Sun, 28 Jun 2026 14:41:45 +0800 Subject: [PATCH] Add career adjudicator A10 AmK Karakamsha bridge --- ...hnique_adjudicator_roi_queue_2026_06_28.md | 64 ++++++++++ mcp_server.py | 116 ++++++++++++++++++ tests/test_mcp_strict_workflow_career.py | 65 ++++++++++ 3 files changed, 245 insertions(+) create mode 100644 docs/research/advanced_technique_adjudicator_roi_queue_2026_06_28.md create mode 100644 tests/test_mcp_strict_workflow_career.py diff --git a/docs/research/advanced_technique_adjudicator_roi_queue_2026_06_28.md b/docs/research/advanced_technique_adjudicator_roi_queue_2026_06_28.md new file mode 100644 index 00000000..54c8e0bd --- /dev/null +++ b/docs/research/advanced_technique_adjudicator_roi_queue_2026_06_28.md @@ -0,0 +1,64 @@ +# Advanced Technique Adjudicator ROI Queue - 2026-06-28 + +## Audit Basis + +The capability registry validates 89 techniques. A stricter static pass over +advanced Vedic/Jyotish techniques found 76 high-value advanced techniques, of +which roughly 22 are directly consumed by the current MCP strict workflows or +their evidence contracts. Around 54 remain useful but under-used by the +adjudicators. + +`covered` means the project can compute or expose the technique. It does not +mean the technique is already weighted in relationship, finance, career, or +event adjudication. + +## First ROI Queue + +1. `A10 / AmK / Karakamsha` into career adjudication. + - Status: implemented in this pass. + - Reason: highest value for career timing and status manifestation. +2. `Argala / Virodhargala` into career and relationship conflict handling. + - Reason: distinguishes support from obstruction. +3. `Ashtakavarga PAV / Sodhita / Kakshya` into finance and transit timing. + - Reason: already computed but not deeply weighted. +4. `Shadbala six components` into finance/career/relationship confidence caps. + - Reason: total strength exists; component-level use is still shallow. +5. `Yogini / Ashtottari / Kalachakra` as secondary dasha convergence. + - Reason: already available in full-reading but not adjudicator-weighted. +6. `D7 / D12 / D24 / D30 / D60` domain-specific varga gates. + - Reason: needed for child, family, education, crisis, and ultra-sensitive + rectification contexts. +7. `Tajika / Sahams` annual event adjudication. + - Reason: annual closure has begun but is not yet a general verdict layer. +8. `KP ruling planets / Prashna workflow` for specific yes/no event questions. + - Reason: high value but requires stricter question-time input boundaries. + +## Implemented This Pass + +Career strict workflow now requires and scores: + +- `varga_full.D10_Dasamsa` +- `special_lagnas.A10_Karma_Pada` +- `jaimini.karakas.Amatyakaraka` +- `jaimini.karakamsha` +- `dasha.current_dasha` +- `narayana_dasha.current_dasha` +- `dasa_convergence.domain_activations.career_status` + +It emits: + +- `dominant_label = "career_status"` only when hard gates are present and score + reaches the moderated threshold. +- `secondary_context` values: `a10_active`, `amk_active`, + `karakamsha_context`, and optional `external_activation_support`. + +## Verification + +- `python3 -m pytest tests/test_mcp_strict_workflow_career.py tests/test_mcp_strict_workflow_relationship.py tests/test_mcp_strict_workflow_finance.py tests/test_vedastro_service_adapter_executor.py -q` +- Result: `37 passed` + +## Boundary + +This is not a full career prediction engine. The new workflow only converts +already-computed A10/AmK/Karakamsha assets into auditable strict evidence. It +does not claim external oracle closure for career event timing. diff --git a/mcp_server.py b/mcp_server.py index 21ed10d9..164e44ef 100644 --- a/mcp_server.py +++ b/mcp_server.py @@ -574,6 +574,74 @@ def _derive_dignity_guardrail(route: str, present: Dict[str, Any]) -> Dict[str, def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[str]) -> Dict[str, Any]: + if route == "career": + score = 0 + score += 20 if present.get("d10_dasamsa") else 0 + score += 15 if present.get("a10_karma_pada") else 0 + score += 15 if present.get("amatyakaraka") else 0 + score += 10 if present.get("karakamsha") else 0 + score += 10 if present.get("vimshottari_current") else 0 + score += 10 if present.get("narayana_current") else 0 + score += _convergence_score(present.get("career_convergence")) + external_activation = present.get("external_activation") or {} + if external_activation.get("level") == "moderate": + score += 5 + if missing: + score = min(score, 35) + score = min(score, 100) + + if missing: + verdict = "insufficient_evidence" + elif score >= 80: + verdict = "high_probability_window" + elif score >= 60: + verdict = "moderate_probability_window" + elif score >= 40: + verdict = "weak_window_needs_confirmation" + else: + verdict = "insufficient_evidence" + + secondary_context: List[str] = [] + if present.get("a10_karma_pada"): + secondary_context.append("a10_active") + if present.get("amatyakaraka"): + secondary_context.append("amk_active") + if present.get("karakamsha"): + secondary_context.append("karakamsha_context") + if external_activation.get("level") == "moderate": + secondary_context.append("external_activation_support") + + hard_gate_missing = any( + key in missing for key in ( + "d10_dasamsa", + "a10_karma_pada", + "vimshottari_current", + "narayana_current", + ) + ) + dominant_label = None + if not hard_gate_missing and present.get("career_convergence") and score >= 60: + dominant_label = "career_status" + + return { + "event_family": "career", + "score": score, + "verdict": verdict, + "dominant_label": dominant_label, + "secondary_context": secondary_context, + "primary_drivers": [ + key for key in ( + "career_convergence", + "vimshottari_current", + "narayana_current", + "a10_karma_pada", + "amatyakaraka", + "karakamsha", + ) + if present.get(key) + ], + } + if route == "relationship": score = 0 score += 15 if present.get("d9_navamsa") else 0 @@ -756,6 +824,54 @@ def _collect_strict_evidence(route: str, result: Dict[str, Any]) -> Dict[str, An modules = result.get("modules", {}) if isinstance(result, dict) else {} domain_activations = _safe_get(modules, "dasa_convergence", "domain_activations") or {} + if route == "career": + required = [ + "varga_full.D10_Dasamsa", + "special_lagnas.A10_Karma_Pada", + "jaimini.karakas.Amatyakaraka", + "jaimini.karakamsha", + "dasha.current_dasha", + "narayana_dasha.current_dasha", + "dasa_convergence.domain_activations.career_status", + ] + present = { + "d10_dasamsa": _safe_get(modules, "varga_full", "D10_Dasamsa"), + "a10_karma_pada": _safe_get(modules, "special_lagnas", "A10_Karma_Pada"), + "amatyakaraka": _safe_get(modules, "jaimini", "karakas", "Amatyakaraka"), + "karakamsha": _safe_get(modules, "jaimini", "karakamsha"), + "vimshottari_current": _safe_get(modules, "dasha", "current_dasha"), + "narayana_current": _safe_get(modules, "narayana_dasha", "current_dasha"), + "career_convergence": domain_activations.get("career_status"), + } + present["external_activation"] = _derive_external_activation_support(modules, "career") + missing = [key for key, value in present.items() if key not in { + "external_activation" + } and value in (None, {}, [], "")] + convergence = present["career_convergence"] or {} + confidence_cap = "medium" + if missing: + confidence_cap = "low" + elif convergence.get("convergence_level") in {"L4", "L5"}: + confidence_cap = "medium-high" + elif convergence.get("convergence_level") == "L3": + confidence_cap = "medium" + else: + confidence_cap = "medium-low" + event_judgement = _derive_event_judgement(route, present, missing) + return { + "question_type": route, + "required_evidence": required, + "present_evidence": present, + "missing_evidence": missing, + "confidence_cap": confidence_cap, + "blocked": bool(missing), + "event_judgement": event_judgement, + "reason": ( + "Career timing requires D10 + A10/Karma Pada + AmK/Karakamsha " + "plus dual dasha and career convergence support." + ), + } + if route == "relationship": required = [ "varga_full.D9_Navamsa", diff --git a/tests/test_mcp_strict_workflow_career.py b/tests/test_mcp_strict_workflow_career.py new file mode 100644 index 00000000..91163600 --- /dev/null +++ b/tests/test_mcp_strict_workflow_career.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +"""Regression tests for MCP career event adjudication.""" + +from __future__ import annotations + +from mcp_server import _collect_strict_evidence + + +def _base_career_result() -> dict: + return { + "modules": { + "varga_full": {"D10_Dasamsa": {"summary": "career varga present"}}, + "special_lagnas": {"A10_Karma_Pada": {"sign": "Capricorn", "lord": "Saturn"}}, + "jaimini": { + "karakas": { + "Amatyakaraka": {"planet": "Mercury"}, + "Atmakaraka": {"planet": "Sun"}, + }, + "karakamsha": {"karakamsha_sign": "Leo", "karakamsha_lord": "Sun"}, + }, + "dasha": {"current_dasha": {"mahadasha": "Mercury", "antardasha": "Sun"}}, + "narayana_dasha": {"current_dasha": {"sign": "Capricorn", "lord": "Saturn"}}, + "dasa_convergence": { + "domain_activations": { + "career_status": {"convergence_level": "L2", "probability": "35-50%"} + } + }, + } + } + + +def test_career_collects_a10_amk_karakamsha_as_strict_evidence() -> None: + strict = _collect_strict_evidence("career", _base_career_result()) + + assert strict["question_type"] == "career" + assert strict["present_evidence"]["d10_dasamsa"] == {"summary": "career varga present"} + assert strict["present_evidence"]["a10_karma_pada"] == {"sign": "Capricorn", "lord": "Saturn"} + assert strict["present_evidence"]["amatyakaraka"] == {"planet": "Mercury"} + assert strict["present_evidence"]["karakamsha"] == { + "karakamsha_sign": "Leo", + "karakamsha_lord": "Sun", + } + assert strict["event_judgement"]["event_family"] == "career" + assert strict["event_judgement"]["dominant_label"] == "career_status" + assert strict["event_judgement"]["secondary_context"] == [ + "a10_active", + "amk_active", + "karakamsha_context", + ] + + +def test_career_blocks_label_when_d10_is_missing_but_preserves_jaimini_context() -> None: + result = _base_career_result() + del result["modules"]["varga_full"]["D10_Dasamsa"] + + strict = _collect_strict_evidence("career", result) + + assert "d10_dasamsa" in strict["missing_evidence"] + assert strict["blocked"] is True + assert strict["event_judgement"]["dominant_label"] is None + assert strict["event_judgement"]["secondary_context"] == [ + "a10_active", + "amk_active", + "karakamsha_context", + ]