Add Jaimini marriage label bridge
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# Marriage Adjudicator Jaimini Bridge v1 Audit (2026-06-28)
|
||||
|
||||
## Scope
|
||||
|
||||
This pass adds the smallest Jaimini bridge to the relationship strict workflow.
|
||||
|
||||
It fixes only `label-lift failure` for legal-marriage cases.
|
||||
|
||||
## Implemented Behavior
|
||||
|
||||
The relationship event judgement now preserves legacy fields:
|
||||
|
||||
- `score`
|
||||
- `verdict`
|
||||
- `primary_drivers`
|
||||
|
||||
and adds:
|
||||
|
||||
- `dominant_label`
|
||||
- `secondary_context`
|
||||
|
||||
## Boundary
|
||||
|
||||
v1 may lift only:
|
||||
|
||||
- `legal_marriage`
|
||||
|
||||
v1 does not lift:
|
||||
|
||||
- `relationship_formation`
|
||||
- `public_formalization`
|
||||
|
||||
## Jaimini Bridge
|
||||
|
||||
`present_evidence.jaimini_marriage_support` has:
|
||||
|
||||
- `level`: `none`, `weak`, or `moderate`
|
||||
- `signals`
|
||||
- `source`: `jaimini_bridge_v1`
|
||||
|
||||
`strong` is intentionally not available in v1.
|
||||
|
||||
## Hard Gates
|
||||
|
||||
`dominant_label = legal_marriage` requires:
|
||||
|
||||
- D9 present
|
||||
- UL present
|
||||
- Vimshottari present
|
||||
- Narayana present
|
||||
- Vivah Saham or marriage convergence present
|
||||
- moderate Jaimini support
|
||||
|
||||
If a hard gate is missing, Jaimini evidence remains context-only.
|
||||
|
||||
## Verification
|
||||
|
||||
Commands:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_relationship.py -q
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_finance.py -q
|
||||
```
|
||||
|
||||
Observed:
|
||||
|
||||
- relationship: `2 passed`
|
||||
- finance: `16 passed`
|
||||
+73
-1
@@ -372,6 +372,45 @@ def _check_external_avayogi_risk(result: Dict[str, Any]) -> Optional[Dict[str, A
|
||||
}
|
||||
|
||||
|
||||
def _derive_jaimini_marriage_support(present: Dict[str, Any]) -> Dict[str, Any]:
|
||||
signals: List[str] = []
|
||||
darakaraka = present.get("darakaraka")
|
||||
upapada_lagna = present.get("upapada_lagna")
|
||||
|
||||
if darakaraka:
|
||||
signals.append("darakaraka_active")
|
||||
|
||||
if isinstance(darakaraka, dict):
|
||||
if darakaraka.get("house") == 7 or darakaraka.get("house_from_lagna") == 7:
|
||||
signals.append("dk_7h_link")
|
||||
if darakaraka.get("ul_link") or darakaraka.get("linked_to_ul"):
|
||||
signals.append("dk_ul_link")
|
||||
|
||||
if isinstance(upapada_lagna, dict) and isinstance(darakaraka, dict):
|
||||
dk_sign = darakaraka.get("sign")
|
||||
ul_sign = upapada_lagna.get("sign")
|
||||
if dk_sign and ul_sign and dk_sign == ul_sign and "dk_ul_link" not in signals:
|
||||
signals.append("dk_ul_link")
|
||||
|
||||
if present.get("jaimini_timing_support"):
|
||||
signals.append("jaimini_dasha_support")
|
||||
|
||||
if not signals:
|
||||
level = "none"
|
||||
elif len(signals) == 1:
|
||||
level = "weak"
|
||||
elif "darakaraka_active" in signals:
|
||||
level = "moderate"
|
||||
else:
|
||||
level = "weak"
|
||||
|
||||
return {
|
||||
"level": level,
|
||||
"signals": signals,
|
||||
"source": "jaimini_bridge_v1",
|
||||
}
|
||||
|
||||
|
||||
def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[str]) -> Dict[str, Any]:
|
||||
if route == "relationship":
|
||||
score = 0
|
||||
@@ -395,10 +434,37 @@ def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[s
|
||||
verdict = "weak_window_needs_confirmation"
|
||||
else:
|
||||
verdict = "insufficient_evidence"
|
||||
jaimini_support = present.get("jaimini_marriage_support") or {}
|
||||
secondary_context: List[str] = []
|
||||
if present.get("darakaraka"):
|
||||
secondary_context.append("darakaraka_active")
|
||||
if jaimini_support.get("level") == "moderate":
|
||||
secondary_context.append("jaimini_support")
|
||||
if present.get("upapada_lagna"):
|
||||
secondary_context.append("ul_support")
|
||||
|
||||
hard_gate_missing = any(
|
||||
key in missing for key in (
|
||||
"d9_navamsa",
|
||||
"upapada_lagna",
|
||||
"vimshottari_current",
|
||||
"narayana_current",
|
||||
)
|
||||
)
|
||||
label_support_present = bool(present.get("vivah_saham") or present.get("marriage_convergence"))
|
||||
dominant_label = None
|
||||
if (
|
||||
not hard_gate_missing
|
||||
and label_support_present
|
||||
and jaimini_support.get("level") == "moderate"
|
||||
):
|
||||
dominant_label = "legal_marriage"
|
||||
return {
|
||||
"event_family": "relationship",
|
||||
"score": score,
|
||||
"verdict": verdict,
|
||||
"dominant_label": dominant_label,
|
||||
"secondary_context": secondary_context,
|
||||
"primary_drivers": [
|
||||
key for key in (
|
||||
"marriage_convergence",
|
||||
@@ -525,7 +591,13 @@ def _collect_strict_evidence(route: str, result: Dict[str, Any]) -> Dict[str, An
|
||||
"narayana_current": _safe_get(modules, "narayana_dasha", "current_dasha"),
|
||||
"marriage_convergence": domain_activations.get("marriage_partnership"),
|
||||
}
|
||||
missing = [key for key, value in present.items() if value in (None, {}, [], "")]
|
||||
present["jaimini_timing_support"] = _safe_get(modules, "jaimini", "marriage_timing_support")
|
||||
present["jaimini_marriage_support"] = _derive_jaimini_marriage_support(present)
|
||||
missing = [
|
||||
key for key, value in present.items()
|
||||
if key not in {"jaimini_marriage_support", "jaimini_timing_support"}
|
||||
and value in (None, {}, [], "")
|
||||
]
|
||||
convergence = present["marriage_convergence"] or {}
|
||||
confidence_cap = "medium"
|
||||
if missing:
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regression tests for MCP relationship event adjudication."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mcp_server import _collect_strict_evidence
|
||||
|
||||
|
||||
def _base_relationship_result() -> dict:
|
||||
return {
|
||||
"modules": {
|
||||
"varga_full": {"D9_Navamsa": {"summary": "ok"}},
|
||||
"special_lagnas": {"Upapada_Lagna": {"sign": "Libra", "lord": "Venus"}},
|
||||
"jaimini": {
|
||||
"darakaraka": {"planet": "Venus", "house": 7},
|
||||
"marriage_support": {"dk_7h_link": True},
|
||||
},
|
||||
"vivah_saham": {"sign": "Taurus", "house": 7},
|
||||
"dasha": {"current_dasha": {"mahadasha": "Venus", "antardasha": "Moon"}},
|
||||
"narayana_dasha": {"current_dasha": {"sign": "Libra", "lord": "Venus"}},
|
||||
"dasa_convergence": {
|
||||
"domain_activations": {
|
||||
"marriage_partnership": {"convergence_level": "L1", "probability": "+15-20%"}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_relationship_jaimini_bridge_lifts_legal_marriage_label() -> None:
|
||||
strict = _collect_strict_evidence("relationship", _base_relationship_result())
|
||||
|
||||
assert strict["present_evidence"]["jaimini_marriage_support"] == {
|
||||
"level": "moderate",
|
||||
"signals": ["darakaraka_active", "dk_7h_link"],
|
||||
"source": "jaimini_bridge_v1",
|
||||
}
|
||||
assert strict["event_judgement"]["dominant_label"] == "legal_marriage"
|
||||
assert strict["event_judgement"]["secondary_context"] == [
|
||||
"darakaraka_active",
|
||||
"jaimini_support",
|
||||
"ul_support",
|
||||
]
|
||||
|
||||
|
||||
def test_relationship_jaimini_bridge_stays_context_only_when_d9_missing() -> None:
|
||||
result = _base_relationship_result()
|
||||
del result["modules"]["varga_full"]["D9_Navamsa"]
|
||||
|
||||
strict = _collect_strict_evidence("relationship", result)
|
||||
|
||||
assert strict["present_evidence"]["jaimini_marriage_support"] == {
|
||||
"level": "moderate",
|
||||
"signals": ["darakaraka_active", "dk_7h_link"],
|
||||
"source": "jaimini_bridge_v1",
|
||||
}
|
||||
assert strict["event_judgement"]["dominant_label"] is None
|
||||
assert strict["event_judgement"]["secondary_context"] == [
|
||||
"darakaraka_active",
|
||||
"jaimini_support",
|
||||
"ul_support",
|
||||
]
|
||||
Reference in New Issue
Block a user