Bridge deep Ashtakavarga support into finance workflow
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# Ashtakavarga Deep Support Bridges v1
|
||||
|
||||
Date: 2026-06-28
|
||||
|
||||
## Scope
|
||||
|
||||
This pass extends finance strict adjudication beyond raw SAV house support and connects three already-computed evidence layers:
|
||||
|
||||
- `PAV / Prastara AV`
|
||||
- `Sodhita AV`
|
||||
- `Kakshya`
|
||||
|
||||
The bridge is intentionally conservative. All three layers are added as secondary support or friction context only.
|
||||
|
||||
## Contract
|
||||
|
||||
Finance strict evidence now accepts:
|
||||
|
||||
- `present_evidence.pav_finance_support`
|
||||
- `present_evidence.sodhita_finance_support`
|
||||
- `present_evidence.kakshya_finance_support`
|
||||
|
||||
These can add:
|
||||
|
||||
- `pav_finance_support`
|
||||
- `sodhita_wealth_friction`
|
||||
- `kakshya_finance_support`
|
||||
- `kakshya_finance_friction`
|
||||
|
||||
to `event_judgement.secondary_context`.
|
||||
|
||||
## Boundary
|
||||
|
||||
This v1 pass does not:
|
||||
|
||||
- directly change `dominant_label`
|
||||
- directly change `payout_label`
|
||||
- directly change score thresholds
|
||||
|
||||
The goal is to make these layers visible and auditable in the adjudication chain before we let them influence window scoring.
|
||||
|
||||
## Current Heuristics
|
||||
|
||||
- `PAV`: marks support when a planet shows multiple strong contribution sources.
|
||||
- `Sodhita`: marks friction when both 2H and 11H resolve to low purified support.
|
||||
- `Kakshya`: marks support when average degree-level strength is high and friction when it is low.
|
||||
|
||||
## Still Open
|
||||
|
||||
- route-specific score weighting
|
||||
- richer mapping from PAV contributor identity to wealth theme
|
||||
- combining Kakshya with transit timing instead of route-level average only
|
||||
- external benchmark closure against JHora/PyJHora examples
|
||||
|
||||
+106
-1
@@ -569,6 +569,93 @@ def _derive_shadbala_component_audit(planets: Any) -> Dict[str, Any]:
|
||||
return audit
|
||||
|
||||
|
||||
def _derive_pav_finance_support(ashtakavarga: Any) -> Dict[str, Any]:
|
||||
base = {
|
||||
"level": "none",
|
||||
"source": "ashtakavarga_pav_bridge_v1",
|
||||
"signals": [],
|
||||
"top_planets": [],
|
||||
}
|
||||
pav_summary = _safe_get(ashtakavarga, "pav", "pav_summary")
|
||||
if not isinstance(pav_summary, dict):
|
||||
return base
|
||||
|
||||
top_planets: List[str] = []
|
||||
for planet, source_scores in pav_summary.items():
|
||||
if not isinstance(source_scores, dict):
|
||||
continue
|
||||
high_sources = [
|
||||
source for source, bindus in source_scores.items()
|
||||
if isinstance(bindus, (int, float)) and bindus >= 5
|
||||
]
|
||||
if high_sources:
|
||||
top_planets.append(str(planet))
|
||||
|
||||
if top_planets:
|
||||
base["level"] = "supportive"
|
||||
base["signals"] = ["pav_finance_support"]
|
||||
base["top_planets"] = sorted(top_planets)
|
||||
return base
|
||||
|
||||
|
||||
def _derive_sodhita_finance_support(ashtakavarga: Any, asc_sign: Optional[str]) -> Dict[str, Any]:
|
||||
base = {
|
||||
"level": "none",
|
||||
"source": "ashtakavarga_sodhita_bridge_v1",
|
||||
"signals": [],
|
||||
"target_houses": [2, 11],
|
||||
"raw_scores": {},
|
||||
}
|
||||
assessment = _safe_get(ashtakavarga, "sodhita", "sodhita_sav", "assessment")
|
||||
asc_idx = _SIGN_TO_INDEX.get(asc_sign) if asc_sign else None
|
||||
if not isinstance(assessment, list) or asc_idx is None:
|
||||
return base
|
||||
|
||||
sign_to_score: Dict[str, float] = {}
|
||||
for row in assessment:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
sign = row.get("sign")
|
||||
score = row.get("score")
|
||||
if sign in _SIGN_TO_INDEX and isinstance(score, (int, float)):
|
||||
sign_to_score[str(sign)] = float(score)
|
||||
|
||||
raw_scores: Dict[str, Any] = {}
|
||||
numeric_scores: Dict[int, float] = {}
|
||||
for house in (2, 11):
|
||||
sign = _SIGNS[(asc_idx + house - 1) % 12]
|
||||
if sign in sign_to_score:
|
||||
numeric_scores[house] = sign_to_score[sign]
|
||||
value = sign_to_score[sign]
|
||||
raw_scores[str(house)] = int(value) if value.is_integer() else value
|
||||
|
||||
base["raw_scores"] = raw_scores
|
||||
if len(numeric_scores) == 2 and max(numeric_scores.values()) <= 19:
|
||||
base["level"] = "obstructive"
|
||||
base["signals"] = ["sodhita_wealth_friction"]
|
||||
return base
|
||||
|
||||
|
||||
def _derive_kakshya_finance_support(kakshya: Any) -> Dict[str, Any]:
|
||||
base = {
|
||||
"level": "none",
|
||||
"source": "kakshya_finance_bridge_v1",
|
||||
"signals": [],
|
||||
"average_strength": None,
|
||||
}
|
||||
avg = _safe_get(kakshya, "summary", "average_strength")
|
||||
if not isinstance(avg, (int, float)):
|
||||
return base
|
||||
base["average_strength"] = float(avg)
|
||||
if avg >= 6.5:
|
||||
base["level"] = "supportive"
|
||||
base["signals"] = ["kakshya_finance_support"]
|
||||
elif avg <= 4.5:
|
||||
base["level"] = "obstructive"
|
||||
base["signals"] = ["kakshya_finance_friction"]
|
||||
return base
|
||||
|
||||
|
||||
def _sign_to_index(sign: str) -> Optional[int]:
|
||||
try:
|
||||
return _SIGNS.index(sign)
|
||||
@@ -939,6 +1026,17 @@ def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[s
|
||||
shadbala_component_audit = present.get("shadbala_component_audit") or {}
|
||||
if shadbala_component_audit.get("status") in {"blocked", "incomplete"}:
|
||||
secondary_context.append("shadbala_component_gap")
|
||||
pav_finance_support = present.get("pav_finance_support") or {}
|
||||
if pav_finance_support.get("level") == "supportive":
|
||||
secondary_context.append("pav_finance_support")
|
||||
sodhita_finance_support = present.get("sodhita_finance_support") or {}
|
||||
if sodhita_finance_support.get("level") == "obstructive":
|
||||
secondary_context.append("sodhita_wealth_friction")
|
||||
kakshya_finance_support = present.get("kakshya_finance_support") or {}
|
||||
if kakshya_finance_support.get("level") == "supportive":
|
||||
secondary_context.append("kakshya_finance_support")
|
||||
elif kakshya_finance_support.get("level") == "obstructive":
|
||||
secondary_context.append("kakshya_finance_friction")
|
||||
if ashtakavarga_finance.get("level") == "supportive":
|
||||
secondary_context.append("ashtakavarga_wealth_support")
|
||||
elif ashtakavarga_finance.get("level") == "obstructive":
|
||||
@@ -1122,14 +1220,21 @@ def _collect_strict_evidence(route: str, result: Dict[str, Any]) -> Dict[str, An
|
||||
"wealth_promise_strength": _derive_wealth_promise_strength(modules),
|
||||
"avayogi_risk": avayogi_risk,
|
||||
}
|
||||
present["asc_sign"] = _safe_get(modules, "chart", "ascendant", "sign")
|
||||
present["shadbala_component_audit"] = _derive_shadbala_component_audit(present["shadbala"])
|
||||
present["ashtakavarga_finance_support"] = _derive_ashtakavarga_finance_support(
|
||||
present["ashtakavarga_house_scores"]
|
||||
)
|
||||
present["pav_finance_support"] = _derive_pav_finance_support(_safe_get(modules, "ashtakavarga"))
|
||||
present["sodhita_finance_support"] = _derive_sodhita_finance_support(
|
||||
_safe_get(modules, "ashtakavarga"),
|
||||
present["asc_sign"],
|
||||
)
|
||||
present["kakshya_finance_support"] = _derive_kakshya_finance_support(_safe_get(modules, "kakshya"))
|
||||
present["external_activation"] = _derive_external_activation_support(modules, "wealth")
|
||||
present["dignity_guardrail"] = _derive_dignity_guardrail(route, present)
|
||||
missing = [key for key, value in present.items() if key not in {
|
||||
"chart", "external_activation", "dignity_guardrail", "gains_convergence", "career_convergence", "avayogi_risk", "ashtakavarga_finance_support", "shadbala_component_audit"
|
||||
"chart", "external_activation", "dignity_guardrail", "gains_convergence", "career_convergence", "avayogi_risk", "ashtakavarga_finance_support", "shadbala_component_audit", "asc_sign", "pav_finance_support", "sodhita_finance_support", "kakshya_finance_support"
|
||||
} and value in (None, {}, [], "")]
|
||||
convergence_hits: List[Dict[str, Any]] = [
|
||||
item for item in [
|
||||
|
||||
@@ -314,6 +314,196 @@ def test_collect_strict_evidence_finance_accepts_complete_shadbala_components()
|
||||
assert "shadbala_component_gap" not in strict["event_judgement"]["secondary_context"]
|
||||
|
||||
|
||||
def test_collect_strict_evidence_finance_adds_pav_and_kakshya_support_as_secondary_context() -> None:
|
||||
result = {
|
||||
"modules": {
|
||||
"chart": {"ascendant": {"sign": "Aries"}},
|
||||
"varga_full": {"D2_Hora": {"summary": "ok"}, "D10_Dasamsa": {"summary": "ok"}},
|
||||
"shadbala": {
|
||||
"planets": {
|
||||
"Venus": {
|
||||
"components": {
|
||||
"sthana": 1.2,
|
||||
"dig": 0.8,
|
||||
"kala": 1.1,
|
||||
"chesta": 0.9,
|
||||
"naisargika": 0.7,
|
||||
"drik": 0.4,
|
||||
},
|
||||
"total_rupa": 5.1,
|
||||
}
|
||||
}
|
||||
},
|
||||
"ashtakavarga": {
|
||||
"house_scores": {"2": 33, "11": 35},
|
||||
"pav": {
|
||||
"pav_summary": {
|
||||
"Venus": {"Jupiter": 5, "Venus": 6, "Lagna": 5},
|
||||
"Saturn": {"Saturn": 2},
|
||||
}
|
||||
},
|
||||
},
|
||||
"kakshya": {
|
||||
"summary": {"average_strength": 6.8},
|
||||
"planets": {
|
||||
"Venus": {"kakshya_strength": 7.4},
|
||||
"Jupiter": {"kakshya_strength": 6.9},
|
||||
},
|
||||
},
|
||||
"dasha": {"current_dasha": {"mahadasha": "Venus", "antardasha": "Mercury"}},
|
||||
"narayana_dasha": {"current_dasha": {"sign": "Taurus", "lord": "Venus"}},
|
||||
"dasa_convergence": {
|
||||
"domain_activations": {
|
||||
"wealth_family": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
"gains_wishes": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
"career_status": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
}
|
||||
},
|
||||
"yogas_doshas": {
|
||||
"dhana_yogas": {
|
||||
"yogas": [{"type": "Dhana Yoga", "strength": "strong"}],
|
||||
"summary": "Dhana Yoga检测:共1个格局",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
strict = _collect_strict_evidence("finance", result)
|
||||
|
||||
assert strict["present_evidence"]["pav_finance_support"] == {
|
||||
"level": "supportive",
|
||||
"source": "ashtakavarga_pav_bridge_v1",
|
||||
"signals": ["pav_finance_support"],
|
||||
"top_planets": ["Venus"],
|
||||
}
|
||||
assert strict["present_evidence"]["kakshya_finance_support"] == {
|
||||
"level": "supportive",
|
||||
"source": "kakshya_finance_bridge_v1",
|
||||
"signals": ["kakshya_finance_support"],
|
||||
"average_strength": 6.8,
|
||||
}
|
||||
assert "pav_finance_support" in strict["event_judgement"]["secondary_context"]
|
||||
assert "kakshya_finance_support" in strict["event_judgement"]["secondary_context"]
|
||||
|
||||
|
||||
def test_collect_strict_evidence_finance_flags_sodhita_wealth_friction() -> None:
|
||||
result = {
|
||||
"modules": {
|
||||
"chart": {"ascendant": {"sign": "Aries"}},
|
||||
"varga_full": {"D2_Hora": {"summary": "ok"}, "D10_Dasamsa": {"summary": "ok"}},
|
||||
"shadbala": {
|
||||
"planets": {
|
||||
"Venus": {
|
||||
"components": {
|
||||
"sthana": 1.2,
|
||||
"dig": 0.8,
|
||||
"kala": 1.1,
|
||||
"chesta": 0.9,
|
||||
"naisargika": 0.7,
|
||||
"drik": 0.4,
|
||||
},
|
||||
"total_rupa": 5.1,
|
||||
}
|
||||
}
|
||||
},
|
||||
"ashtakavarga": {
|
||||
"house_scores": {"2": 33, "11": 35},
|
||||
"sodhita": {
|
||||
"sodhita_sav": {
|
||||
"assessment": [
|
||||
{"sign": "Taurus", "score": 18, "level": "挑战"},
|
||||
{"sign": "Aquarius", "score": 17, "level": "挑战"},
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
"dasha": {"current_dasha": {"mahadasha": "Venus", "antardasha": "Mercury"}},
|
||||
"narayana_dasha": {"current_dasha": {"sign": "Taurus", "lord": "Venus"}},
|
||||
"dasa_convergence": {
|
||||
"domain_activations": {
|
||||
"wealth_family": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
"gains_wishes": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
"career_status": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
}
|
||||
},
|
||||
"yogas_doshas": {
|
||||
"dhana_yogas": {
|
||||
"yogas": [{"type": "Dhana Yoga", "strength": "strong"}],
|
||||
"summary": "Dhana Yoga检测:共1个格局",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
strict = _collect_strict_evidence("finance", result)
|
||||
|
||||
assert strict["present_evidence"]["sodhita_finance_support"] == {
|
||||
"level": "obstructive",
|
||||
"source": "ashtakavarga_sodhita_bridge_v1",
|
||||
"signals": ["sodhita_wealth_friction"],
|
||||
"target_houses": [2, 11],
|
||||
"raw_scores": {"2": 18, "11": 17},
|
||||
}
|
||||
assert "sodhita_wealth_friction" in strict["event_judgement"]["secondary_context"]
|
||||
|
||||
|
||||
def test_collect_strict_evidence_finance_flags_kakshya_friction_as_secondary_only() -> None:
|
||||
result = {
|
||||
"modules": {
|
||||
"chart": {"ascendant": {"sign": "Aries"}},
|
||||
"varga_full": {"D2_Hora": {"summary": "ok"}, "D10_Dasamsa": {"summary": "ok"}},
|
||||
"shadbala": {
|
||||
"planets": {
|
||||
"Venus": {
|
||||
"components": {
|
||||
"sthana": 1.2,
|
||||
"dig": 0.8,
|
||||
"kala": 1.1,
|
||||
"chesta": 0.9,
|
||||
"naisargika": 0.7,
|
||||
"drik": 0.4,
|
||||
},
|
||||
"total_rupa": 5.1,
|
||||
}
|
||||
}
|
||||
},
|
||||
"ashtakavarga": {"house_scores": {"2": 33, "11": 35}},
|
||||
"kakshya": {
|
||||
"summary": {"average_strength": 4.1},
|
||||
"planets": {
|
||||
"Venus": {"kakshya_strength": 4.0},
|
||||
},
|
||||
},
|
||||
"dasha": {"current_dasha": {"mahadasha": "Venus", "antardasha": "Mercury"}},
|
||||
"narayana_dasha": {"current_dasha": {"sign": "Taurus", "lord": "Venus"}},
|
||||
"dasa_convergence": {
|
||||
"domain_activations": {
|
||||
"wealth_family": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
"gains_wishes": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
"career_status": {"convergence_level": "L1", "probability": "+15-20%"},
|
||||
}
|
||||
},
|
||||
"yogas_doshas": {
|
||||
"dhana_yogas": {
|
||||
"yogas": [{"type": "Dhana Yoga", "strength": "strong"}],
|
||||
"summary": "Dhana Yoga检测:共1个格局",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
strict = _collect_strict_evidence("finance", result)
|
||||
|
||||
assert strict["present_evidence"]["kakshya_finance_support"] == {
|
||||
"level": "obstructive",
|
||||
"source": "kakshya_finance_bridge_v1",
|
||||
"signals": ["kakshya_finance_friction"],
|
||||
"average_strength": 4.1,
|
||||
}
|
||||
assert strict["event_judgement"]["dominant_label"] == "public_wealth_status"
|
||||
assert "kakshya_finance_friction" in strict["event_judgement"]["secondary_context"]
|
||||
|
||||
|
||||
def test_collect_strict_evidence_finance_flags_low_wealth_ashtakavarga_friction() -> None:
|
||||
result = {
|
||||
"modules": {
|
||||
|
||||
Reference in New Issue
Block a user