fix(rectification): anchor candidate windows to civil dates across midnight
Carry explicit local date intervals instead of inferring the day from clock order. Cluster width, delivery, adoption, and reports keep the actual civil date; adopted date is stored separately from the reported birth_date. Algorithm identity is scoring-9 / spec-v5. Scoring weights, confirmation thresholds, and Skill version are unchanged. Isolated Linux final-3 gates passed; four pre-existing Python failures remain. This is not a production release.
This commit is contained in:
@@ -48,6 +48,17 @@ def _report_candidate_range(
|
||||
for row in candidate_scores
|
||||
if top_score is not None and float(row.get("score") or 0) == top_score
|
||||
]
|
||||
if "candidate_intervals" in request:
|
||||
from scripts.rectification.candidate_window import candidate_positions, enumerate_candidate_window, intervals_from_positions, interval_union_width
|
||||
positions = candidate_positions(request, enumerate_candidate_window(request))
|
||||
selected = [row for row in positions if not top_times or row["time"] in top_times]
|
||||
parts = intervals_from_positions(selected)
|
||||
return {
|
||||
"start_time": selected[0]["time"], "end_time": selected[-1]["time"],
|
||||
"candidate_intervals": [{"start_at": part["start_at"], "end_at": part["end_at"]} for part in parts],
|
||||
"representative_time": representative_time or selected[len(selected) // 2]["time"],
|
||||
"width_minutes": interval_union_width(parts), "representative_is_unique": False,
|
||||
}
|
||||
if not top_times:
|
||||
return {
|
||||
"start_time": request["start_time"],
|
||||
@@ -227,6 +238,9 @@ def score_candidates(request: RectificationRequest) -> dict[str, Any]:
|
||||
static_contexts=built.get("static_contexts") if isinstance(built.get("static_contexts"), list) else None,
|
||||
)
|
||||
decision_receipt = build_decision_receipt(request, candidate_decisions, built, diagnostic_values)
|
||||
from scripts.rectification.candidate_window import candidate_intervals
|
||||
decision_receipt.update({"candidate_window_contract": "dated-v1", "candidate_intervals": candidate_intervals(request),
|
||||
"candidate_timezone_offset": request["tz"], "candidate_timezone_id": request.get("timezone_id", "")})
|
||||
execution_ledger = build_execution_ledger(request, built, diagnostic_values, candidate_decisions)
|
||||
representative = candidate_decisions[0] if candidate_decisions else None
|
||||
representative_time = str(representative.get("time") or "")[:5] if representative else None
|
||||
@@ -495,7 +509,9 @@ def block_scan(request: RectificationRequest) -> dict[str, Any]:
|
||||
member_scores = [float(row.get("score") or 0) for row in members]
|
||||
mean = (sum(member_scores) / len(member_scores)) if member_scores else 0.0
|
||||
raw_support.append(max(mean - min_day, 0.0))
|
||||
from scripts.rectification.candidate_window import narrow_candidate_intervals
|
||||
blocks.append({
|
||||
"candidate_intervals": narrow_candidate_intervals(request, start_time, end_time),
|
||||
"period": period,
|
||||
"start_time": start_time,
|
||||
"end_time": end_time,
|
||||
|
||||
Reference in New Issue
Block a user