Enforce external-truth Yogi finance boundary
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# Git Execution Card - Finance Yogi Boundary Only
|
||||
|
||||
日期:2026-06-28
|
||||
目标:只提交 finance adjudicator 的外部真值 Yogi 边界修复,不混入其他工作树噪音。
|
||||
|
||||
## 目标文件
|
||||
|
||||
1. `mcp_server.py`
|
||||
2. `tests/test_mcp_strict_workflow_finance.py`
|
||||
3. `docs/research/wealth_adjudicator_fifth_pass_external_truth_boundary_2026_06_28.md`
|
||||
|
||||
## 执行顺序
|
||||
|
||||
### Step 1 - 确认暂存范围
|
||||
|
||||
```bash
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 reset
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 add -- \
|
||||
mcp_server.py \
|
||||
tests/test_mcp_strict_workflow_finance.py \
|
||||
docs/research/wealth_adjudicator_fifth_pass_external_truth_boundary_2026_06_28.md
|
||||
```
|
||||
|
||||
### Step 2 - 检查暂存区
|
||||
|
||||
```bash
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 diff --cached --name-only
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 diff --cached --stat
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 diff --cached --check
|
||||
```
|
||||
|
||||
预期:只看到上述 3 个文件。
|
||||
|
||||
### Step 3 - 回归验证
|
||||
|
||||
```bash
|
||||
python3 -m pytest /Users/wuyongnaren/Documents/印度占星/tests/test_mcp_strict_workflow_finance.py -q
|
||||
```
|
||||
|
||||
预期:
|
||||
|
||||
- `12 passed`
|
||||
|
||||
### Step 4 - 独立提交
|
||||
|
||||
建议提交语义:
|
||||
|
||||
```bash
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 commit -m "Enforce external-truth Yogi finance boundary"
|
||||
```
|
||||
|
||||
### Step 5 - 推送当前分支
|
||||
|
||||
```bash
|
||||
git -C /Users/wuyongnaren/Documents/印度占星 push origin codex/release-hygiene-ci
|
||||
```
|
||||
|
||||
## 禁止事项
|
||||
|
||||
这次提交不要混入:
|
||||
|
||||
- `docs/research/public_benchmark_dashboard_latest.md`
|
||||
- `references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json`
|
||||
- 任意 `patch_*.py`
|
||||
- 任意本地试验脚本
|
||||
- 未整理的 sidecar 研究包
|
||||
|
||||
## 一句话判断
|
||||
|
||||
**这是一张“只交 finance Yogi 真实性边界,不交别的”的推送卡。**
|
||||
@@ -0,0 +1,74 @@
|
||||
# Wealth Adjudicator Fifth Pass External Truth Boundary (2026-06-28)
|
||||
|
||||
## What Was Fixed
|
||||
|
||||
This pass closed a structural contradiction in the finance adjudicator:
|
||||
|
||||
- one branch of the codebase was already moving toward `external_truth.yogi_planet`
|
||||
- another branch was still internally deriving Yogi from Sun/Moon degrees and letting that influence finance promise folding
|
||||
|
||||
That violated the new high-rigor boundary.
|
||||
|
||||
## Boundary Now Enforced
|
||||
|
||||
The finance adjudicator now follows this rule:
|
||||
|
||||
1. No external `yogi_planet` -> no Yogi contribution
|
||||
2. External `yogi_planet` present -> lightweight D1 gate only
|
||||
3. Only then may Yogi enter:
|
||||
- `wealth_promise_strength.supporting_sources`
|
||||
- `source_diversity`
|
||||
- `secondary_context` as `yogi_active`
|
||||
|
||||
## Removed Risk
|
||||
|
||||
The following behavior is no longer allowed:
|
||||
|
||||
- deriving Yogi from internal Sun/Moon degrees
|
||||
- upgrading `dhana_yogas` to `dhana_yogi_hooks` without upstream truth
|
||||
- creating `yogi_support_only` from local chart math
|
||||
|
||||
## Regression Contract
|
||||
|
||||
The finance regression suite now locks these four truths:
|
||||
|
||||
1. `dhana` alone must stay `dhana_yogas` without external truth
|
||||
2. `dhana + lakshmi` must stay `dhana_lakshmi_hooks` without external truth
|
||||
3. Yogi-only local chart inputs must not produce a finance promise
|
||||
4. External truth + valid Kendra/Trikona placement may promote to `dhana_yogi_hooks`
|
||||
|
||||
## Verification
|
||||
|
||||
Command:
|
||||
|
||||
```bash
|
||||
python3 -m pytest tests/test_mcp_strict_workflow_finance.py -q
|
||||
```
|
||||
|
||||
Observed:
|
||||
|
||||
- `12 passed`
|
||||
|
||||
Manual probe confirmed:
|
||||
|
||||
- `NO_EXTERNAL` -> no Yogi source in promise folding
|
||||
- `WITH_EXTERNAL` -> `supporting_sources = ["dhana", "yogi"]`
|
||||
- `secondary_context` includes `yogi_active`
|
||||
|
||||
## Why This Matters
|
||||
|
||||
This is not just a bug fix. It restores honesty at the adjudication layer.
|
||||
|
||||
The finance engine can now say:
|
||||
|
||||
- "Yogi affected this judgement because an upstream truth source supplied it"
|
||||
|
||||
but can no longer silently smuggle Yogi into the result from local chart math.
|
||||
|
||||
## Next Step
|
||||
|
||||
Keep the same discipline for all future high-order promise hooks:
|
||||
|
||||
1. external truth first
|
||||
2. lightweight downstream gating second
|
||||
3. no hidden internal recomputation
|
||||
+43
-22
@@ -112,36 +112,56 @@ def _derive_wealth_promise_strength(modules: Dict[str, Any]) -> Optional[Dict[st
|
||||
yogas_doshas = modules.get("yogas_doshas") if isinstance(modules, dict) else {}
|
||||
dhana = yogas_doshas.get("dhana_yogas") if isinstance(yogas_doshas, dict) else {}
|
||||
yogas = dhana.get("yogas") if isinstance(dhana, dict) else None
|
||||
if not isinstance(yogas, list) or not yogas:
|
||||
|
||||
has_dhana = False
|
||||
has_lakshmi = False
|
||||
dhana_level = "weak"
|
||||
lakshmi_level = "weak"
|
||||
|
||||
sources = set()
|
||||
if isinstance(yogas, list) and yogas:
|
||||
for row in yogas:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
lvl = str(row.get("strength", "")).lower()
|
||||
row_type = str(row.get("type", "")).lower()
|
||||
if "lakshmi" in row_type:
|
||||
sources.add("lakshmi")
|
||||
has_lakshmi = True
|
||||
if lvl == "strong" or (lvl == "moderate" and lakshmi_level == "weak"):
|
||||
lakshmi_level = lvl
|
||||
elif "dhana" in row_type:
|
||||
sources.add("dhana")
|
||||
has_dhana = True
|
||||
if lvl == "strong" or (lvl == "moderate" and dhana_level == "weak"):
|
||||
dhana_level = lvl
|
||||
|
||||
if not has_dhana and not has_lakshmi:
|
||||
return None
|
||||
|
||||
strengths = []
|
||||
sources = set()
|
||||
for row in yogas:
|
||||
if not isinstance(row, dict):
|
||||
continue
|
||||
strengths.append(str(row.get("strength", "")).lower())
|
||||
row_type = str(row.get("type", "")).lower()
|
||||
if "lakshmi" in row_type:
|
||||
sources.add("lakshmi")
|
||||
elif "dhana" in row_type:
|
||||
sources.add("dhana")
|
||||
supporting_sources = sorted(sources)
|
||||
|
||||
if any(level == "strong" for level in strengths):
|
||||
level = "strong"
|
||||
elif any(level == "moderate" for level in strengths):
|
||||
level = "moderate"
|
||||
if has_dhana and has_lakshmi:
|
||||
primary_source = "dhana_lakshmi_hooks"
|
||||
elif has_dhana:
|
||||
primary_source = "dhana_yogas"
|
||||
else:
|
||||
level = "weak"
|
||||
primary_source = "lakshmi_hooks"
|
||||
|
||||
if dhana_level == "strong" or lakshmi_level == "strong":
|
||||
final_level = "strong"
|
||||
elif dhana_level == "moderate" or lakshmi_level == "moderate":
|
||||
final_level = "moderate"
|
||||
else:
|
||||
final_level = "weak"
|
||||
|
||||
supporting_sources = sorted(sources) or ["dhana"]
|
||||
primary_source = "dhana_lakshmi_hooks" if len(supporting_sources) > 1 else "dhana_yogas"
|
||||
return {
|
||||
"level": level,
|
||||
"level": final_level,
|
||||
"primary_source": primary_source,
|
||||
"supporting_sources": supporting_sources,
|
||||
"count": len(yogas),
|
||||
"count": len(yogas) if isinstance(yogas, list) else 0,
|
||||
"source_diversity": len(supporting_sources),
|
||||
"yogi_support": None,
|
||||
}
|
||||
|
||||
|
||||
@@ -405,7 +425,8 @@ def _collect_strict_evidence(route: str, result: Dict[str, Any]) -> Dict[str, An
|
||||
else:
|
||||
confidence_cap = "medium-low"
|
||||
event_judgement = _derive_event_judgement(route, present, missing)
|
||||
if yogi_promise and event_judgement.get("dominant_label") and "yogi_active" not in event_judgement.get("secondary_context", []):
|
||||
promise = present.get("wealth_promise_strength") or {}
|
||||
if yogi_promise and "yogi" in promise.get("supporting_sources", []) and event_judgement.get("dominant_label") and "yogi_active" not in event_judgement.get("secondary_context", []):
|
||||
event_judgement["secondary_context"] = event_judgement.get("secondary_context", []) + ["yogi_active"]
|
||||
return {
|
||||
"question_type": route,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mcp_server import _collect_strict_evidence, _derive_event_judgement
|
||||
from mcp_server import _collect_strict_evidence, _derive_event_judgement, _derive_wealth_promise_strength
|
||||
|
||||
|
||||
def test_finance_public_wealth_label_requires_at_least_moderate_window() -> None:
|
||||
@@ -174,6 +174,7 @@ def test_collect_strict_evidence_finance_derives_wealth_promise_from_dhana_yogas
|
||||
"count": 2,
|
||||
"source_diversity": 1,
|
||||
"supporting_sources": ["dhana"],
|
||||
"yogi_support": None,
|
||||
}
|
||||
assert strict["event_judgement"]["score"] == 100
|
||||
assert strict["event_judgement"]["verdict"] == "moderate_probability_window"
|
||||
@@ -214,9 +215,71 @@ def test_collect_strict_evidence_finance_combines_dhana_and_lakshmi_hooks() -> N
|
||||
"count": 2,
|
||||
"source_diversity": 2,
|
||||
"supporting_sources": ["dhana", "lakshmi"],
|
||||
"yogi_support": None,
|
||||
}
|
||||
|
||||
|
||||
def test_wealth_folding_dhana_does_not_self_infer_yogi_without_external_truth() -> None:
|
||||
modules = {
|
||||
"yogas_doshas": {
|
||||
"dhana_yogas": {
|
||||
"yogas": [{"type": "dhana", "strength": "strong"}]
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"ascendant": {"degree_raw": 133.0},
|
||||
"planets": {
|
||||
"Sun": {"degree_raw": 20.0},
|
||||
"Moon": {"degree_raw": 20.0},
|
||||
"Venus": {"house": 11, "sign": "Gemini"},
|
||||
}
|
||||
}
|
||||
}
|
||||
res = _derive_wealth_promise_strength(modules)
|
||||
assert res["primary_source"] == "dhana_yogas"
|
||||
assert res["source_diversity"] == 1
|
||||
assert res["supporting_sources"] == ["dhana"]
|
||||
assert res["level"] == "strong"
|
||||
assert res["yogi_support"] is None
|
||||
|
||||
|
||||
def test_wealth_folding_dhana_lakshmi_does_not_self_infer_yogi_without_external_truth() -> None:
|
||||
modules = {
|
||||
"yogas_doshas": {
|
||||
"dhana_yogas": {
|
||||
"yogas": [{"type": "dhana", "strength": "moderate"}, {"type": "lakshmi", "strength": "moderate"}]
|
||||
}
|
||||
},
|
||||
"chart": {
|
||||
"ascendant": {"degree_raw": 133.0},
|
||||
"planets": {
|
||||
"Sun": {"degree_raw": 20.0},
|
||||
"Moon": {"degree_raw": 20.0},
|
||||
"Venus": {"house": 11, "sign": "Gemini"},
|
||||
}
|
||||
}
|
||||
}
|
||||
res = _derive_wealth_promise_strength(modules)
|
||||
assert res["primary_source"] == "dhana_lakshmi_hooks"
|
||||
assert res["source_diversity"] == 2
|
||||
assert res["level"] == "moderate"
|
||||
assert res["yogi_support"] is None
|
||||
|
||||
|
||||
def test_wealth_folding_yogi_only_is_blocked_without_external_truth() -> None:
|
||||
modules = {
|
||||
"chart": {
|
||||
"ascendant": {"degree_raw": 133.0},
|
||||
"planets": {
|
||||
"Sun": {"degree_raw": 20.0},
|
||||
"Moon": {"degree_raw": 20.0},
|
||||
"Venus": {"house": 11, "sign": "Gemini"},
|
||||
}
|
||||
}
|
||||
}
|
||||
assert _derive_wealth_promise_strength(modules) is None
|
||||
|
||||
|
||||
def test_collect_strict_evidence_finance_adds_yogi_hook_only_when_external_truth_is_present() -> None:
|
||||
result = {
|
||||
"modules": {
|
||||
@@ -253,12 +316,19 @@ def test_collect_strict_evidence_finance_adds_yogi_hook_only_when_external_truth
|
||||
}
|
||||
|
||||
strict = _collect_strict_evidence("finance", result)
|
||||
assert strict["present_evidence"]["yogi_promise"] == {
|
||||
"planet": "Venus",
|
||||
"house": 10,
|
||||
"status": "入友(Friendly Sign)",
|
||||
"source": "external_yogi_planet",
|
||||
}
|
||||
assert strict["present_evidence"]["wealth_promise_strength"] == {
|
||||
"level": "moderate",
|
||||
"primary_source": "dhana_yogi_hooks",
|
||||
"count": 2,
|
||||
"source_diversity": 2,
|
||||
"supporting_sources": ["dhana", "yogi"],
|
||||
"yogi_support": None,
|
||||
}
|
||||
assert "yogi_active" in strict["event_judgement"]["secondary_context"]
|
||||
|
||||
@@ -306,5 +376,6 @@ def test_collect_strict_evidence_finance_does_not_promote_yogi_outside_kendra_tr
|
||||
"count": 1,
|
||||
"source_diversity": 1,
|
||||
"supporting_sources": ["dhana"],
|
||||
"yogi_support": None,
|
||||
}
|
||||
assert "yogi_active" not in strict["event_judgement"]["secondary_context"]
|
||||
|
||||
Reference in New Issue
Block a user