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
+19 -10
View File
@@ -164,17 +164,18 @@ def context_time(context: dict[str, Any]) -> str | None:
def cluster_contexts_by_signature(
contexts: Sequence[dict[str, Any]],
) -> list[dict[str, Any]]:
buckets: dict[tuple[int | None, ...], list[dict[str, Any]]] = {}
buckets: dict[tuple[Any, ...], list[dict[str, Any]]] = {}
for context in contexts:
if not isinstance(context, dict):
continue
time = context_time(context)
if not time:
continue
buckets.setdefault(feature_signature(context), []).append(context)
buckets.setdefault((context.get("segment_index", 0), *feature_signature(context)), []).append(context)
clusters: list[dict[str, Any]] = []
for signature, members in buckets.items():
ordered = sorted(members, key=lambda item: _clock(str(context_time(item))))
for key, members in buckets.items():
signature = key[1:]
ordered = sorted(members, key=lambda item: item.get("window_index", _clock(str(context_time(item)))))
times = [str(context_time(item)) for item in ordered]
clusters.append({
"signature": signature,
@@ -184,7 +185,7 @@ def cluster_contexts_by_signature(
"representative_time": times[len(times) // 2],
"representative": ordered[len(ordered) // 2],
})
clusters.sort(key=lambda item: _clock(item["representative_time"]))
clusters.sort(key=lambda item: item["representative"].get("window_index", _clock(item["representative_time"])))
return clusters
@@ -271,7 +272,9 @@ def cap_clusters_by_adjacent_merge(
best_index = index
left = work[best_index]
right = work[best_index + 1]
merged_times = sorted(set(left["times"] + right["times"]), key=_clock)
contexts = list(left.get("contexts") or []) + list(right.get("contexts") or [])
order = {context_time(row): row.get("window_index", _clock(str(context_time(row)))) for row in contexts}
merged_times = sorted(set(left["times"] + right["times"]), key=lambda clock: order.get(clock, _clock(clock)))
work[best_index] = {
"signature": left.get("signature"),
"signature_key": f"{left.get('signature_key')}+{right.get('signature_key')}",
@@ -296,7 +299,8 @@ def select_signature_representatives(
context for context in (static_contexts or [])
if isinstance(context, dict) and context_time(context) in by_time
]
if len(contexts) >= 2:
order = {context_time(row): row.get("window_index", _clock(str(context_time(row)))) for row in contexts}
if contexts:
clusters = cluster_contexts_by_signature(contexts)
else:
clusters = _adjacent_score_clusters(list(by_time.values()))
@@ -306,17 +310,22 @@ def select_signature_representatives(
members = [by_time[time] for time in cluster["times"] if time in by_time]
if not members:
continue
best = max(members, key=lambda row: (float(row.get("score") or 0), str(row.get("time"))))
best = max(members, key=lambda row: (float(row.get("score") or 0), order.get(row.get("time"), _clock(str(row.get("time"))))))
positions = [{key: context[key] for key in ("time", "candidate_date", "window_index", "window_offset_minutes", "segment_index")}
for context in cluster.get("contexts", []) if "window_index" in context]
representative_position = next((row for row in positions if row["time"] == best["time"]), {})
representatives.append({
**best,
**representative_position,
"cluster_times": [time for time in cluster["times"] if time in by_time],
**({"cluster_positions": positions} if positions else {}),
})
representatives.sort(key=lambda row: (-float(row.get("score") or 0), str(row.get("time"))))
representatives.sort(key=lambda row: (-float(row.get("score") or 0), order.get(row.get("time"), _clock(str(row.get("time"))))))
return representatives or list(rows)[:1]
def _adjacent_score_clusters(rows: Sequence[dict[str, Any]]) -> list[dict[str, Any]]:
ordered = sorted(rows, key=lambda row: _clock(str(_hhmm(row.get("time")))))
ordered = sorted(rows, key=lambda row: row.get("window_index", _clock(str(_hhmm(row.get("time"))))))
groups: list[list[dict[str, Any]]] = []
for row in ordered:
current = groups[-1] if groups else None