fix(rectification): anchor candidate windows to civil dates across midnight
Independent Staging Quality Gate / validate (push) Successful in 13m27s
Independent Staging Quality Gate / publish (push) Failing after 1h0m1s

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:
jesse-ux
2026-09-21 02:55:00 +08:00
parent 3be740f84d
commit b85c4a686a
115 changed files with 106484 additions and 315 deletions
+16
View File
@@ -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,