fix(rectification): split D4/D5 stages and recast after adopt
Independent Staging Quality Gate / validate (push) Successful in 9m19s
Independent Staging Quality Gate / publish (push) Failing after 7m45s

Keep family on D12+D7 instead of mixing it into D4, score D5 on education, and show a natal recast plus technique audit after adopt without unique-minute claims.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-20 09:11:54 +08:00
parent b1b4f5fac9
commit a93a3cc1a9
40 changed files with 1195 additions and 66 deletions
+110 -1
View File
@@ -40,6 +40,105 @@ def _decimal(value: Any, default: str = "0") -> Decimal:
return Decimal(default)
_AUDIT_LABELS = {
"d1-rashi": ("D1 本命盘", "本轮已按该分钟重算本命宫位。"),
"d2-hora": ("D2 财帛分盘", "本轮已对照财帛主题。"),
"d4-chaturthamsha": ("D4 迁移分盘", "本轮已对照居所或迁移。"),
"d5-panchamsha": ("D5 成就分盘", "本轮已对照学业或被委以责任的变化。"),
"d7-saptamsha": ("D7 子女分盘", "本轮已对照子女或伴侣细节。"),
"d9-navamsa": ("D9 婚姻分盘", "本轮已对照关系主题,未给类型标签。"),
"d10-dashamsa": ("D10 事业分盘", "本轮已对照事业主题,未给类型标签。"),
"d11-labhamsha": ("D11 收益分盘", "本轮已对照收益主题。"),
"d12-dwadashamsha": ("D12 父母分盘", "本轮已对照家人主题。"),
"d24-chaturvimshamsha": ("D24 教育分盘", "本轮已对照学业主题。"),
"d30-trimshamsha": ("D30 健康压力分盘", "本轮已对照健康压力主题。"),
"vimshottari-dasha": ("Vimshottari", "本轮已对照主限。"),
"narayana-dasha": ("Narayana", "本轮已对照分盘大运。"),
"gochara": ("Gochara", "本轮已做受控行运辅助对照。"),
"ashtakavarga": ("Ashtakavarga", "本轮已做 Ashtakavarga 辅助对照。"),
"shadbala": ("Shadbala", "本轮已做已核验的 Shadbala 分量辅助对照。"),
"arudha-pada": ("Arudha Pada", "本轮已做 Arudha 辅助对照。"),
"functional-benefic-malefic": ("功能吉凶星", "本轮已叠加本命功能吉凶星。"),
}
def natal_recast_copy(time: str, lagna: str) -> dict[str, Any]:
return {
"time": time[:5],
"lagna": lagna,
"user_meaning": (
f"本命宫位已按 {time[:5]} 重算(上升 {lagna})。"
"下面是本轮实际执行的技法,不能当作唯一分钟确认。"
),
"unique_minute_claim": False,
"confirmation_allowed": False,
}
def _executed_public_methods(built: dict[str, Any]) -> list[str]:
methods: set[str] = set()
for contributions in (built.get("matrix") or {}).values():
if not isinstance(contributions, dict):
continue
for cell in contributions.values():
if not isinstance(cell, dict):
continue
for layer in cell.get("technique_layers") or []:
if layer in _AUDIT_LABELS:
methods.add(str(layer))
for rule in cell.get("rule_ids") or []:
text = str(rule)
if text.startswith("vim_"):
methods.add("vimshottari-dasha")
elif text.startswith("narayana_"):
methods.add("narayana-dasha")
elif "functional_benefic" in text or "functional_malefic" in text:
methods.add("functional-benefic-malefic")
elif text.startswith("gochara") or "controlled_transit" in text:
methods.add("gochara")
elif "ashtakavarga" in text:
methods.add("ashtakavarga")
elif "shadbala" in text:
methods.add("shadbala")
elif "arudha" in text:
methods.add("arudha-pada")
return [key for key in _AUDIT_LABELS if key in methods]
def build_technique_audit(
built: dict[str, Any],
*,
house_table: dict[str, Any] | None,
) -> list[dict[str, str]]:
executed = set(_executed_public_methods(built))
if house_table:
executed.add("d1-rashi")
rows: list[dict[str, str]] = []
for method in _AUDIT_LABELS:
if method not in executed:
continue
label, note = _AUDIT_LABELS[method]
rows.append({"technique": label, "status": "executed", "note": note})
rows.append({
"technique": "KP 宫头",
"status": "blocked",
"note": "KP 宫头本轮未计算。",
})
rows.extend((
{
"technique": "VedAstro 分钟级校验",
"status": "blocked",
"note": "官方分钟级校验尚未评估。",
},
{
"technique": "唯一分钟确认",
"status": "blocked",
"note": "采用不等于确认唯一分钟。",
},
))
return rows
def _quantized_score(row: CandidateScoreRow) -> Decimal:
return _decimal(row.get("score")).quantize(SCORE_QUANTUM, rounding=ROUND_HALF_UP)
@@ -263,12 +362,22 @@ def build_decision_receipt(
"exact_confirmation": exact_confirmation,
},
}
house_table = compact_house_table_from_contexts(
house_tables_by_time: dict[str, dict[str, Any]] = {}
for decision in candidate_decisions:
table = compact_house_table_from_contexts(built.get("static_contexts"), decision.get("time"))
if table:
house_tables_by_time[table["time"]] = table
house_table = house_tables_by_time.get(representative["time"] if representative else "") or compact_house_table_from_contexts(
built.get("static_contexts"),
representative["time"] if representative else None,
)
if house_table:
receipt["house_table"] = house_table
recast = natal_recast_copy(house_table["time"], house_table["lagna"])
receipt["natal_recast"] = recast
if house_tables_by_time:
receipt["house_tables_by_time"] = house_tables_by_time
receipt["technique_audit_table"] = build_technique_audit(built, house_table=house_table)
receipt.update({
"window_scan": packet["window_scan"],
"event_dasha_ledger": packet["event_dasha_ledger"],