fix(rectification): show the house table and hide the activity fold
Independent Staging Quality Gate / validate (push) Failing after 9m39s
Independent Staging Quality Gate / publish (push) Has been skipped

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-19 20:07:51 +08:00
parent 4c33329b0c
commit c8af18e90a
19 changed files with 438 additions and 100 deletions
+7
View File
@@ -11,6 +11,7 @@ from scripts.rectification.contracts import (
RectificationRequest,
is_scoreable_event,
)
from scripts.rectification.house_table import compact_house_table_from_contexts
from scripts.rectification.scoring_service import precision_weight
POLICY_VERSION = "rectification-candidate-policy-v2"
@@ -247,6 +248,12 @@ def build_decision_receipt(
"exact_confirmation": exact_confirmation,
},
}
house_table = compact_house_table_from_contexts(
built.get("static_contexts"),
representative["time"] if representative else None,
)
if house_table:
receipt["house_table"] = house_table
return receipt
+109
View File
@@ -0,0 +1,109 @@
"""Compact D1 house table for the public rectification surface.
Sign names and occupants only. Longitudes, coordinates, scores and
fingerprints stay out of this projection.
"""
from __future__ import annotations
from typing import Any
from scripts.jyotish_engine import SIGNS, SIGNS_CN
PLANET_ORDER = (
"Sun",
"Moon",
"Mars",
"Mercury",
"Jupiter",
"Venus",
"Saturn",
"Rahu",
"Ketu",
)
PLANET_ZH = {
"Sun": "太阳",
"Moon": "月亮",
"Mars": "火星",
"Mercury": "水星",
"Jupiter": "木星",
"Venus": "金星",
"Saturn": "土星",
"Rahu": "罗睺",
"Ketu": "计都",
}
def _sign_cn(sign: str | None) -> str | None:
if not isinstance(sign, str) or sign not in SIGNS_CN:
return None
return SIGNS_CN[sign]
def _house_number(value: Any, sign: str | None, asc_idx: int | None) -> int | None:
if isinstance(value, int) and 1 <= value <= 12:
return value
if not sign or sign not in SIGNS or asc_idx is None:
return None
return ((SIGNS.index(sign) - asc_idx) % 12) + 1
def compact_house_table(chart: Any, *, time: str) -> dict[str, Any] | None:
if not isinstance(chart, dict) or not isinstance(time, str):
return None
ascendant = chart.get("ascendant") if isinstance(chart.get("ascendant"), dict) else {}
lagna = _sign_cn(str(ascendant.get("sign") or "") or None)
if not lagna:
return None
try:
asc_idx = SIGNS.index(str(ascendant["sign"]))
except (KeyError, ValueError):
return None
occupants: dict[int, list[str]] = {house: [] for house in range(1, 13)}
planets = chart.get("planets") if isinstance(chart.get("planets"), dict) else {}
for name in PLANET_ORDER:
data = planets.get(name)
if not isinstance(data, dict):
continue
house = _house_number(data.get("house"), str(data.get("sign") or "") or None, asc_idx)
label = PLANET_ZH.get(name)
if house is None or not label or label in occupants[house]:
continue
occupants[house].append(label)
houses = []
for house in range(1, 13):
sign = _sign_cn(SIGNS[(asc_idx + house - 1) % 12])
if not sign:
return None
houses.append({
"house": house,
"sign": sign,
"occupants": occupants[house],
})
return {
"time": time[:5],
"lagna": lagna,
"houses": houses,
}
def compact_house_table_from_contexts(contexts: Any, time: str | None) -> dict[str, Any] | None:
if not isinstance(time, str) or not time or not isinstance(contexts, list):
return None
wanted = time[:5]
for context in contexts:
if not isinstance(context, dict):
continue
feature = context.get("feature") if isinstance(context.get("feature"), dict) else {}
feature_time = feature.get("time")
candidate_at = context.get("candidate_at")
context_time = feature_time if isinstance(feature_time, str) else None
if context_time is None and hasattr(candidate_at, "strftime"):
context_time = candidate_at.strftime("%H:%M")
if context_time != wanted:
continue
return compact_house_table(context.get("chart"), time=wanted)
return None