feat(rectification): drive questions from candidate contrast

This commit is contained in:
Jesse_Chen
2026-07-31 13:17:00 +08:00
parent fdf791953e
commit a7a11a1a7a
21 changed files with 703 additions and 42 deletions
+51 -3
View File
@@ -11,7 +11,7 @@ from scripts.active_rectification_event_engine import compute_candidate_static_c
from scripts.active_rectification_events import CandidateScoreRow
from scripts.rectification.contracts import LifeEvent, RectificationRequest
ALGORITHM_VERSION = "rectification-v5-matrix-scoring-1"
ALGORITHM_VERSION = "rectification-v5-matrix-scoring-2"
INPUT_CONTRACT_VERSION = "rectification-calculation-spec-v4"
@@ -82,6 +82,42 @@ def _cached_rows(serialized: str) -> tuple[CandidateScoreRow, ...]:
return tuple(compute_event_candidate_rows(json.loads(serialized)))
_RELATIONSHIP_SUPPORT_RULES = (
"functional_benefic_auxiliary",
"arudha_auxiliary",
"ashtakavarga_target_house_support_auxiliary",
"shadbala_sthana_drik_naisargika_support_auxiliary",
"controlled_transit_jupiter_domain_house",
)
_RELATIONSHIP_CHANGE_RULES = (
"functional_malefic_auxiliary",
"ashtakavarga_target_house_pressure_auxiliary",
"shadbala_sthana_drik_naisargika_pressure_auxiliary",
"controlled_transit_saturn_domain_house",
)
def _relationship_kind_factor(event_kind: str, rule_ids: Sequence[str]) -> float:
if event_kind not in {"relationship_start", "relationship_change"}:
return 1.0
support = sum(any(rule.endswith(marker) for marker in _RELATIONSHIP_SUPPORT_RULES) for rule in rule_ids)
change = sum(any(rule.endswith(marker) for marker in _RELATIONSHIP_CHANGE_RULES) for rule in rule_ids)
direction = support - change if event_kind == "relationship_start" else change - support
return max(0.8, min(1.2, 1 + 0.08 * direction))
def _kind_adjusted_evidence(event: LifeEvent, evidence: dict[str, Any]) -> dict[str, Any]:
if event["domain"] != "relationship":
return evidence
event_kind = event["event_kind"]
rules = list(evidence["rule_ids"])
return {
**evidence,
"rule_ids": [*rules, f"event_kind_profile:{event_kind}"],
"points": round(float(evidence["points"]) * _relationship_kind_factor(event_kind, rules), 4),
}
def build_event_contribution_matrix(
request: RectificationRequest,
row_provider: Callable[[dict[str, Any]], Sequence[CandidateScoreRow]] | None = None,
@@ -94,7 +130,14 @@ def build_event_contribution_matrix(
candidate_grid: list[str] | None = None
for event in request["events"]:
samples = sample_event_dates(event)
sample_rows = [list(provider(_legacy_request(request, event, sampled))) for sampled in samples]
sample_rows = []
for sampled in samples:
rows = list(provider(_legacy_request(request, event, sampled)))
sample_rows.append([
{**row, "score": adjusted["points"], "evidence": [adjusted]}
for row in rows
for adjusted in [_kind_adjusted_evidence(event, row["evidence"][0])]
])
grids = [[row["time"] for row in rows] for rows in sample_rows]
if any(grid != grids[0] for grid in grids[1:]) or (candidate_grid is not None and grids[0] != candidate_grid):
raise ValueError("candidate_grid_mismatch")
@@ -109,7 +152,12 @@ def build_event_contribution_matrix(
matrix[event["id"]][candidate_time] = {
"points": round(sum(points) / len(points), 4),
"rule_ids": sorted({rule for item in evidences for rule in item["rule_ids"]}),
"technique_layers": sorted({rule.split(":", 1)[0] for item in evidences for rule in item["rule_ids"]}),
"technique_layers": sorted({
rule.split(":", 1)[0]
for item in evidences
for rule in item["rule_ids"]
if not rule.startswith(("event_kind:", "event_kind_profile:"))
}),
}
winner = max(set(winners), key=winners.count)
mean = sum(matrix[event["id"]][time]["points"] for time in candidate_grid) / len(candidate_grid)