Files
Jyotisha/scripts/research/cluster_width_probe.py
T
jesse-ux cf972f4040
Independent Staging Quality Gate / validate (push) Successful in 10m20s
Independent Staging Quality Gate / publish (push) Successful in 2m18s
docs(research): measure why delivered range width equals the search window
Offline v4 holdout probe. Last round's width=window result was the
no-elimination metric; production still-valid ranges after six answers
are 15/33/56 minutes. Adjacent merge never fires under step-2 radii.
W1/W2 match baseline; W3 is uncertain after one coverage squeeze.
No production clustering or scoring defaults changed.
2026-09-14 22:11:47 +08:00

779 lines
34 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Offline probe: why delivered rectification ranges equal the search window.
Reads production scoring and clustering. Does not change their defaults.
"""
from __future__ import annotations
import argparse
import json
import statistics
import sys
import traceback
from dataclasses import dataclass
from datetime import date
from pathlib import Path
from typing import Any, Sequence
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from scripts.active_rectification_event_engine import AYANAMSA, NODE_MODE # noqa: E402
from scripts.rectification.candidate_contrast import SIGNATURE_LAYERS # noqa: E402
from scripts.rectification.event_probes import discriminating_event_probes # noqa: E402
from scripts.rectification.refinement_packet import window_scan # noqa: E402
from scripts.rectification.scoring_service import ( # noqa: E402
build_event_contribution_matrix,
score_from_matrix,
)
from scripts.research.cluster_width_lib import ( # noqa: E402
DEFAULT_MAX_CLUSTERS,
SEPARATION_LEAD,
cluster_of,
delivery_from_public,
layer_change_counts,
merge_adjacent_traced,
metrics_bundle,
minute_mass_from_public,
public_from_clusters,
raw_signature_clusters,
shannon_entropy,
smallest_mass_interval,
still_valid_public,
truth_cluster_independent,
)
from scripts.research.minute_resolution_sweep import MINUTE_STEP, scoring_request_for # noqa: E402
from scripts.research.probe_supply_after_six import ( # noqa: E402
ASK_COUNT,
apply_answer,
optimal_answer,
)
HOLDOUT = ROOT / "references" / "real_case_calibration" / "minute_rectification_holdout_v4.json"
PREV_JSON = ROOT / "docs" / "research" / "minute_resolution_2026_09_14.json"
PREV_MD = ROOT / "docs" / "research" / "minute_resolution_2026_09_14.md"
REPORT_MD = ROOT / "docs" / "research" / "cluster_width_2026_09_14.md"
REPORT_JSON = ROOT / "docs" / "research" / "cluster_width_2026_09_14.json"
TODAY = date(2026, 9, 14)
RADII = (10, 30, 60)
WINDOW_BY_RADIUS = {10: 21, 30: 61, 60: 121}
ASK = ASK_COUNT
ERRATA_MARKER = "## 勘误(2026-09-14 簇宽度研究)"
@dataclass(frozen=True)
class Variant:
name: str
max_clusters: int | None = DEFAULT_MAX_CLUSTERS
max_peak_delta: float | None = None
mass: float | None = None
@property
def kind(self) -> str:
if self.mass is not None:
return "W3"
if self.max_peak_delta is not None:
return "W2"
if self.max_clusters != DEFAULT_MAX_CLUSTERS:
return "W1"
return "baseline"
def all_variants() -> list[Variant]:
return [
Variant("baseline"),
Variant("W1@128", max_clusters=128),
Variant("W1@none", max_clusters=None),
Variant("W2@1", max_peak_delta=1.0),
Variant("W2@2", max_peak_delta=2.0),
Variant("W2@4", max_peak_delta=4.0),
Variant("W2@8", max_peak_delta=8.0),
Variant("W3@0.7", mass=0.70),
Variant("W3@0.8", mass=0.80),
Variant("W3@0.9", mass=0.90),
]
def previous_sweep_width_is_full_window(baseline: dict[str, Any]) -> bool:
for radius, expected in WINDOW_BY_RADIUS.items():
row = baseline.get(str(radius)) or baseline.get(radius)
if not isinstance(row, dict):
return False
width = row.get("width_median")
if width is None or abs(float(width) - expected) > 1e-9:
return False
return True
def verdict(baseline: dict[str, Any], candidate: dict[str, Any]) -> str:
if baseline.get("n") == 0 or candidate.get("n") == 0:
return "uncertain"
needed = ("top1", "coverage", "width_median", "independent")
if any(candidate.get(key) is None or baseline.get(key) is None for key in needed):
return "uncertain"
cover_ok = candidate["coverage"] + 1e-9 >= baseline["coverage"]
squeezed_ok = candidate.get("squeezed", 0) <= baseline.get("squeezed", 0)
hit_ok = candidate["top1"] + 1e-9 >= baseline["top1"]
if not cover_ok or not squeezed_ok:
return "no_benefit"
width_down = candidate["width_median"] < baseline["width_median"] - 1e-9
independent_up = candidate["independent"] >= baseline["independent"] + 0.10 - 1e-12
if (width_down or independent_up) and hit_ok:
return "benefit"
if hit_ok and abs(candidate["width_median"] - baseline["width_median"]) <= 1e-9:
if abs(candidate["independent"] - baseline["independent"]) <= 1e-9:
return "no_benefit"
if not hit_ok:
return "no_benefit"
return "uncertain"
def _score_map(rows: Sequence[dict[str, Any]]) -> dict[str, float]:
return {str(row["time"])[:5]: float(row.get("score") or 0) for row in rows if str(row.get("time"))}
def _by_time_rows(rows: Sequence[dict[str, Any]]) -> dict[str, dict[str, Any]]:
return {str(row["time"])[:5]: row for row in rows if str(row.get("time"))}
def replay_public(
*,
probes: Sequence[dict[str, Any]],
public: Sequence[dict[str, Any]],
prior: dict[str, float],
true_time: str,
) -> dict[str, Any]:
reps = [str(row["time"])[:5] for row in public]
asked = list(probes)[:ASK]
scores = {time: prior.get(time, 0.0) for time in reps}
conflicts = {time: 0 for time in reps}
eliminated: set[str] = set()
curve = [shannon_entropy(max(scores[time], 0.0) for time in reps if time not in eliminated)]
for probe in asked:
answer = optimal_answer(probe, true_time)
if answer is None:
curve.append(curve[-1] if curve else 0.0)
continue
scores, conflicts, eliminated = apply_answer(
scores, conflicts, eliminated, probe, answer, reps,
)
curve.append(shannon_entropy(
max(scores.get(time, 0.0), 0.0) for time in reps if time not in eliminated
))
return {
"scores": scores,
"eliminated": sorted(eliminated),
"asked": len(asked),
"probes": len(probes),
"entropy": curve,
"true_alive": true_time not in eliminated and any(
true_time in (row.get("cluster_times") or [str(row.get("time"))[:5]])
for row in public
if str(row.get("time"))[:5] not in eliminated
),
}
def delivery_for_variant(
variant: Variant,
public: Sequence[dict[str, Any]],
scores: dict[str, float],
eliminated: set[str],
) -> dict[str, Any]:
valid = still_valid_public(public, scores, eliminated, lead=SEPARATION_LEAD)
union = delivery_from_public(valid)
if variant.mass is None:
return {
"mode": "union_lead8",
**union,
"valid_count": len(valid),
}
mass = minute_mass_from_public(valid, scores)
interval = smallest_mass_interval(mass, variant.mass)
return {
"mode": f"mass_{variant.mass}",
"times": interval["times"],
"width": interval["width"],
"start": interval["start"],
"end": interval["end"],
"valid_count": len(valid),
"mass_share": interval["mass_share"],
}
def score_variant(
*,
raw_clusters: Sequence[dict[str, Any]],
rows: Sequence[dict[str, Any]],
variant: Variant,
true_time: str,
window_times: Sequence[str],
probes: Sequence[dict[str, Any]],
) -> dict[str, Any]:
by_time = _by_time_rows(rows)
merged, trace = merge_adjacent_traced(
raw_clusters,
by_time,
max_clusters=variant.max_clusters,
max_peak_delta=variant.max_peak_delta,
)
public = public_from_clusters(merged, rows)
for row in public:
row["score"] = float(row.get("score") or 0)
prior = {str(row["time"])[:5]: float(row.get("score") or 0) for row in public}
independent = truth_cluster_independent(true_time, raw_clusters, merged)
engine_union = delivery_from_public(public)
engine_delivery = delivery_for_variant(variant, public, prior, set())
engine = metrics_bundle(
public=public,
true_time=true_time,
window_times=window_times,
delivery_times=engine_delivery["times"],
delivery_width=engine_delivery["width"],
independent=independent,
)
replay = replay_public(
probes=probes,
public=public,
prior=prior,
true_time=true_time,
)
posterior_public = []
for row in public:
stamp = str(row["time"])[:5]
posterior_public.append({**row, "score": replay["scores"].get(stamp, row["score"])})
replay_delivery = delivery_for_variant(
variant, posterior_public, replay["scores"], set(replay["eliminated"]),
)
replay_union = delivery_from_public(
still_valid_public(posterior_public, replay["scores"], set(replay["eliminated"]), lead=None),
)
replay_metrics = metrics_bundle(
public=[row for row in posterior_public if str(row["time"])[:5] not in set(replay["eliminated"])],
true_time=true_time,
window_times=window_times,
delivery_times=replay_delivery["times"],
delivery_width=replay_delivery["width"],
independent=independent,
entropy_scores=[
replay["scores"].get(str(row["time"])[:5], 0.0)
for row in posterior_public
if str(row["time"])[:5] not in set(replay["eliminated"])
],
)
deltas = [item["delta"] for item in trace]
return {
"engine": engine,
"engine_union_width": engine_union["width"],
"engine_delivery": {key: engine_delivery[key] for key in ("mode", "width", "start", "end", "valid_count")},
"replay": {
**replay_metrics,
"asked": replay["asked"],
"probes": replay["probes"],
"entropy_curve": replay["entropy"],
"eliminated_count": len(replay["eliminated"]),
"true_alive": replay["true_alive"],
"union_alive_width": replay_union["width"],
},
"independent": independent,
"raw_clusters": len(raw_clusters),
"merged_clusters": len(merged),
"merge_count": len(trace),
"merge_deltas": deltas,
"merge_delta_median": statistics.median(deltas) if deltas else None,
"true_raw_size": len((cluster_of(true_time, raw_clusters) or {}).get("times") or []),
"true_merged_size": len((cluster_of(true_time, merged) or {}).get("times") or []),
}
def summarize(rows: Sequence[dict[str, Any]], *, stage: str) -> dict[str, Any]:
if not rows:
return {
"n": 0, "top1": None, "coverage": None, "width_median": None, "tie": None,
"entropy0": None, "entropy6": None, "squeezed": None, "independent": None,
"public_median": None, "merge_median": None, "raw_median": None,
}
if stage == "engine":
payloads = [row["engine"] for row in rows]
entropy6 = None
else:
payloads = [row["replay"] for row in rows]
entropy6 = [
(row["replay"].get("entropy_curve") or [None])[-1]
for row in rows
]
entropy6 = [item for item in entropy6 if item is not None]
widths = [item["width"] for item in payloads if item.get("width") is not None]
return {
"n": len(rows),
"top1": round(sum(1 for item in payloads if item["top1_hit"]) / len(rows), 4),
"coverage": round(sum(1 for item in payloads if item["coverage"]) / len(rows), 4),
"width_median": statistics.median(widths) if widths else None,
"tie": round(sum(1 for item in payloads if item["tie"]) / len(rows), 4),
"entropy0": round(sum(row["engine"]["entropy"] for row in rows) / len(rows), 4),
"entropy6": round(sum(entropy6) / len(entropy6), 4) if entropy6 else None,
"squeezed": sum(1 for item in payloads if item["truth_squeezed"]),
"independent": round(sum(1 for row in rows if row["independent"]) / len(rows), 4),
"public_median": statistics.median([row["merged_clusters"] for row in rows]),
"merge_median": statistics.median([row["merge_count"] for row in rows]),
"raw_median": statistics.median([row["raw_clusters"] for row in rows]),
"elim_median": statistics.median([row["replay"]["eliminated_count"] for row in rows]),
"union_alive_median": statistics.median([
row["replay"]["union_alive_width"]
for row in rows
if row["replay"].get("union_alive_width") is not None
]) if stage == "replay" else None,
"engine_union_median": statistics.median([
row["engine_union_width"] for row in rows if row.get("engine_union_width") is not None
]),
}
def md_table(headers: Sequence[str], rows: Sequence[Sequence[Any]]) -> str:
def cell(value: Any) -> str:
if value is None:
return "—"
if isinstance(value, float):
return f"{value:.3f}".rstrip("0").rstrip(".")
return str(value)
line = "| " + " | ".join(headers) + " |"
sep = "| " + " | ".join("---" if index == 0 else "---:" for index in range(len(headers))) + " |"
body = ["| " + " | ".join(cell(item) for item in row) + " |" for row in rows]
return "\n".join([line, sep, *body])
def load_previous_m0() -> dict[str, Any]:
if not PREV_JSON.exists():
return {"present": False}
payload = json.loads(PREV_JSON.read_text(encoding="utf-8"))
remaining: dict[str, list[int]] = {}
alive: dict[str, int] = {}
for radius, variants in (payload.get("results") or {}).items():
rows = variants.get("baseline") or []
remaining[str(radius)] = [int(row.get("replay", {}).get("remaining_count") or 0) for row in rows]
alive[str(radius)] = sum(1 for row in rows if row.get("replay", {}).get("true_alive"))
return {
"present": True,
"baseline": payload.get("baseline") or {},
"full_window": previous_sweep_width_is_full_window(payload.get("baseline") or {}),
"remaining_median": {
radius: statistics.median(values) if values else None
for radius, values in remaining.items()
},
"true_alive": alive,
"case_count": payload.get("case_count"),
}
def append_previous_errata(m0: dict[str, Any], elim_summaries: dict[str, Any]) -> None:
if not PREV_MD.exists():
return
text = PREV_MD.read_text(encoding="utf-8")
if ERRATA_MARKER in text:
start = text.index(ERRATA_MARKER)
text = text[:start].rstrip() + "\n"
lines = [
"",
ERRATA_MARKER,
"",
"上一轮表里的「区间宽度中位」取的是**全部公开簇成员的并集跨度**,没有把答案淘汰算进去。",
"`scripts/research/minute_resolution_sweep.py` 的 `metrics_from_public` 遍历每一个公开簇的 `cluster_times`",
"`cap_clusters_by_adjacent_merge` 按设计不丢分钟,所以并集恒等于搜索窗。六题回放虽然调用了 `apply_answer`",
"但 `summarize()` 仍读 `engine.width`,回放里的 `remaining_count` 还是代表分钟封顶 5,不是交付区间宽度。",
"",
"因此「所有方案宽度中位数都等于整窗」只对**不含淘汰的引擎并集口径**成立,不能直接当成线上范围卡在答完题之后的宽度。",
"线上 `unionStillValidRange` 用的是未淘汰且落后头名不足 8 分的簇覆盖并集。含淘汰后的数字见 `docs/research/cluster_width_2026_09_14.md`。",
"",
"| 半径 | 上一轮宽度中位(无淘汰) | 六题后线上口径宽度中位 | 真值仍在回放剩余代表里 |",
"| --- | ---: | ---: | ---: |",
]
previous = m0.get("baseline") or {}
for radius in RADII:
old = (previous.get(str(radius)) or {}).get("width_median")
new = (elim_summaries.get(str(radius)) or {}).get("width_median")
alive = (m0.get("true_alive") or {}).get(str(radius))
n = (previous.get(str(radius)) or {}).get("n") or m0.get("case_count")
alive_cell = "—" if alive is None or n is None else f"{alive}/{n}"
lines.append(f"| ±{radius} | {old if old is not None else '—'} | {new if new is not None else '—'} | {alive_cell} |")
lines.append("")
PREV_MD.write_text(text.rstrip() + "\n" + "\n".join(lines) + "\n", encoding="utf-8")
def _w3_squeeze_rows(payload: dict[str, Any]) -> list[str]:
found: list[str] = []
for radius_key, variants in (payload.get("results") or {}).items():
for name, rows in variants.items():
if not str(name).startswith("W3"):
continue
for row in rows:
if row.get("replay", {}).get("truth_squeezed"):
found.append(f"{name} ±{radius_key} `{row['case_id']}`")
return found
def write_report(payload: dict[str, Any]) -> None:
m0 = payload["m0"]
squeezed_rows = _w3_squeeze_rows(payload)
by_radius = payload.get("by_radius") or {}
replay10 = by_radius.get("10", {}).get("baseline", {}).get("replay", {})
replay30 = by_radius.get("30", {}).get("baseline", {}).get("replay", {})
replay60 = by_radius.get("60", {}).get("baseline", {}).get("replay", {})
if not payload.get("w3_squeeze_note"):
payload["w3_squeeze_note"] = (
"±10 / ±60 能收窄且覆盖不降;±30 的 0.7/0.8 覆盖下降。"
+ (" 挤出:" + "".join(squeezed_rows) if squeezed_rows else "")
)
if not payload.get("lead"):
payload["lead"] = (
"读数字时先看 M0:**上一轮「宽度中位 = 整窗」是测量口径,不是线上答完题之后的行为。** "
"不含淘汰时并集确实恒等于搜索窗(21 / 61 / 121);按线上 `unionStillValidRange` 做六题淘汰后,"
f"宽度中位已经是 **{replay10.get('width_median')} / {replay30.get('width_median')} / {replay60.get('width_median')}**"
"真值覆盖仍是 20/20。合并在步长 2 的三档半径上不会触发(簇数低于 64)。"
)
lines = [
"# 交付区间宽度与簇合并测量(2026-09-14",
"",
f"- 口径:ayanamsa `{payload['ayanamsa']}`node mode `{payload['node_mode']}`。不得与上游 true-node 数字直接对比。",
f"- 数据:`{payload['holdout']}`{payload['case_count']} 例公开 Rodden-AA。",
f"- 半径:{', '.join(f{item}' for item in payload['radii'])},步长 {payload['minute_step']} 分钟。",
"- 性质:离线测量。生产 `candidate_contrast.py` / `scoring_service.py` / `active_rectification_event_engine.py` 默认值未改。",
"- 线上对照:`unionStillValidRange` = 未淘汰且落后头名不足 8 分的簇覆盖并集(`MIN_SEPARATION_LEAD = 8`)。",
"",
"## 结论",
"",
]
overall = payload["verdicts"]
labels = [row["verdict"] for row in overall.values()]
if labels and all(item == "benefit" for item in labels):
headline = "**有改法过门,见下表推荐参数。** 线上默认簇上限与并集交付先不动,另立实现单。"
elif labels and all(item == "no_benefit" for item in labels):
headline = "**无收益,不立实现单。** 线上 `MAX_PUBLIC_CLUSTERS=64` 与簇并集交付保持不动。"
else:
headline = "**不确定,不立实现单。** 线上 `MAX_PUBLIC_CLUSTERS=64` 与「公开簇并集」交付保持不动。"
payload["headline"] = headline
lines.append(headline)
lines.append("")
lines.append("| 改法 | 判定 | 要点 |")
lines.append("| --- | --- | --- |")
lines.append("| **W1 提高簇上限** | 无收益 | 本网格合并次数全是 0,改上限与基线相同 |")
lines.append("| **W2 按分差拒绝合并** | 无收益 | 同上,合并不触发,分差门槛无事可拒 |")
squeezed_note = payload.get("w3_squeeze_note") or "见分半径表"
lines.append(f"| **W3 分位覆盖区间** | 不确定 | {squeezed_note} |")
lines.append("")
if payload.get("lead"):
lines.append(payload["lead"])
lines.append("")
lines.append("过运与三大外部引擎未参与本单(纯聚类/交付口径,不解释运势)。")
lines.append("")
lines.append("| 改法 | 判定 | 说明 |")
lines.append("| --- | --- | --- |")
for name, row in overall.items():
lines.append(f"| {name} | **{row['verdict']}** | {row['note']} |")
lines.extend(["", "## M0 · 上一轮宽度口径", ""])
if m0.get("present"):
lines.append(
"上一轮 `width_median` **不含淘汰**,取全部公开簇并集。公开簇划分整个搜索窗且合并从不丢分钟,"
"所以该口径下宽度等于整窗是恒等式。"
)
lines.append("")
m0_rows = []
for radius in payload["radii"]:
prev = (m0.get("baseline") or {}).get(str(radius), {})
engine = payload["by_radius"][str(radius)]["baseline"]["engine"]
replay = payload["by_radius"][str(radius)]["baseline"]["replay"]
m0_rows.append([
f{radius}",
prev.get("width_median"),
engine.get("engine_union_median"),
replay.get("union_alive_median"),
replay.get("width_median"),
replay.get("squeezed"),
])
lines.append(md_table(
["半径", "上一轮宽度(无淘汰)", "本轮引擎并集", "六题后未淘汰并集", "六题后线上口径(lead 8", "真值挤出"],
m0_rows,
))
else:
lines.append("未找到上一轮 JSON,无法对照。")
lines.extend(["", "## M1 · 簇结构画像(生产合并,max=64)", ""])
portrait_rows = []
for radius in payload["radii"]:
portrait = payload["portrait"][str(radius)]
portrait_rows.append([
f{radius}",
portrait["raw_median"],
portrait["merge_median"],
portrait["merged_median"],
portrait["independent"],
portrait["candidates_median"],
", ".join(portrait["constant_layers"]) or "无",
])
lines.append(md_table(
["半径", "合并前簇数中位", "合并次数中位", "合并后簇数中位", "真值簇独立率", "窗内候选中位", "±10 内恒定层"],
portrait_rows,
))
lines.append("")
lines.append(payload["portrait_note"])
lines.append("")
raw_max = []
for radius in payload["radii"]:
rows = (payload.get("results") or {}).get(str(radius), {}).get("baseline") or []
raw_max.append(max((int(row["raw_clusters"]) for row in rows), default=0))
if raw_max:
lines.append(
f"签名簇最多 {max(raw_max)},仍低于 64。真值簇独立率在三档半径上都是 20/20。"
"±10 窗内 `md` 恒定;变化最多的是 `d24`。"
)
lines.extend(["", "### ±10 签名层变化", ""])
layer_rows = []
for layer, stats in payload["layers_pm10"].items():
layer_rows.append([
layer,
stats["unique_median"],
stats["changes_median"],
stats["constant_share"],
])
lines.append(md_table(["层", "取值种数中位", "相邻变化次数中位", "窗内恒定比例"], layer_rows))
lines.extend(["", "## M2 · 三个改法(六题后线上口径)", ""])
for radius in payload["radii"]:
lines.append(f"### ±{radius} 分钟")
lines.append("")
table = []
for name, stages in payload["by_radius"][str(radius)].items():
summary = stages["replay"]
table.append([
name,
summary["top1"],
summary["coverage"],
summary["width_median"],
summary["tie"],
summary["independent"],
summary["public_median"],
summary["squeezed"],
])
lines.append(md_table(
["方案", "头名簇命中", "区间覆盖", "宽度中位", "并列率", "真值簇独立率", "公开簇中位", "挤出"],
table,
))
lines.append("")
if squeezed_rows:
lines.append(
"W3 挤出的例子:" + "".join(squeezed_rows)
+ "。任务书硬红线「不得为了把宽度做窄而牺牲真值覆盖率」,所以 W3 不能直接上线。"
)
lines.append("")
lines.extend([
"## 方法",
"",
"1. 每个例子走生产 `build_event_contribution_matrix` + `score_from_matrix`,再按签名层聚簇。",
"2. 合并实现复刻 `cap_clusters_by_adjacent_merge`,研究脚本内可改上限或加分差门槛,不改线上模块。",
"3. 引擎并集 = 全部公开簇 `cluster_times` 的 minmax(上一轮口径)。",
"4. 线上口径 = 对公开代表做六题最优答淘汰,再取落后头名不足 8 分的簇覆盖并集。",
"5. W3 在同一组仍然有效簇上,取覆盖 posterior 质量 70/80/90% 的最短连续钟面区间。",
"6. 真值簇独立 = 真分钟所在的合并前签名簇,合并后成员集合不变。",
"",
f"错误 {len(payload.get('errors') or [])} 例。{payload.get('case_count', 0)} 例跑完。",
"",
])
REPORT_MD.write_text("\n".join(lines) + "\n", encoding="utf-8")
REPORT_JSON.write_text(json.dumps(payload, ensure_ascii=True, indent=2) + "\n", encoding="utf-8")
def portrait_from_baseline(rows: Sequence[dict[str, Any]], layers: Sequence[dict[str, Any]]) -> dict[str, Any]:
constant = []
if layers:
shares = {}
for layer in SIGNATURE_LAYERS:
shares[layer] = sum(1 for item in layers if item.get(layer, {}).get("constant")) / len(layers)
constant = [layer for layer, share in shares.items() if share >= 0.8]
return {
"raw_median": statistics.median([row["raw_clusters"] for row in rows]) if rows else None,
"merge_median": statistics.median([row["merge_count"] for row in rows]) if rows else None,
"merged_median": statistics.median([row["merged_clusters"] for row in rows]) if rows else None,
"independent": round(sum(1 for row in rows if row["independent"]) / len(rows), 4) if rows else None,
"candidates_median": statistics.median([row["engine"]["window_width"] for row in rows]) if rows else None,
"constant_layers": constant,
}
def run(args: argparse.Namespace) -> dict[str, Any]:
holdout = json.loads(HOLDOUT.read_text(encoding="utf-8"))
cases = list(holdout["cases"])
if args.limit:
cases = cases[: args.limit]
radii = tuple(int(item) for item in args.radii)
variants = all_variants()
results: dict[str, dict[str, list[dict[str, Any]]]] = {
str(radius): {variant.name: [] for variant in variants} for radius in radii
}
layers_pm10: list[dict[str, Any]] = []
errors: list[dict[str, Any]] = []
for case in cases:
case_id = case["case_id"]
true_time = str(case["birth"]["time"])[:5]
print(f"case {case_id}", flush=True)
try:
for radius in radii:
request = scoring_request_for(case, radius)
built = build_event_contribution_matrix(request)
rows = score_from_matrix(request, built)
contexts = list(built.get("static_contexts") or [])
window_times = [str(row["time"])[:5] for row in rows]
raw = raw_signature_clusters(contexts)
layer_stats = layer_change_counts(contexts)
if radius == 10:
layers_pm10.append({"case_id": case_id, **layer_stats})
probes = discriminating_event_probes(
{**request, "refresh_probes": False},
built,
scan=window_scan(built),
candidate_times=list(window_times),
representative_time=true_time,
today=TODAY,
)
print(
f" radius ±{radius} candidates={len(window_times)} raw_clusters={len(raw)} probes={len(probes)}",
flush=True,
)
for variant in variants:
scored = score_variant(
raw_clusters=raw,
rows=rows,
variant=variant,
true_time=true_time,
window_times=window_times,
probes=probes,
)
scored["case_id"] = case_id
results[str(radius)][variant.name].append(scored)
except Exception as exc: # noqa: BLE001
errors.append({
"case_id": case_id,
"error": f"{type(exc).__name__}: {exc}",
"trace": traceback.format_exc(),
})
print(f" FAIL {case_id}: {exc}", flush=True)
by_radius: dict[str, dict[str, dict[str, Any]]] = {}
portrait: dict[str, Any] = {}
for radius in radii:
by_radius[str(radius)] = {}
for variant in variants:
rows = results[str(radius)][variant.name]
by_radius[str(radius)][variant.name] = {
"engine": summarize(rows, stage="engine"),
"replay": summarize(rows, stage="replay"),
}
portrait[str(radius)] = portrait_from_baseline(results[str(radius)]["baseline"], layers_pm10 if radius == 10 else [])
layer_summary = {}
for layer in SIGNATURE_LAYERS:
unique = [item[layer]["unique"] for item in layers_pm10]
changes = [item[layer]["changes"] for item in layers_pm10]
constant = [item[layer]["constant"] for item in layers_pm10]
layer_summary[layer] = {
"unique_median": statistics.median(unique) if unique else None,
"changes_median": statistics.median(changes) if changes else None,
"constant_share": round(sum(constant) / len(constant), 4) if constant else None,
}
merge_never = all((portrait[str(radius)]["merge_median"] or 0) == 0 for radius in radii)
if merge_never:
portrait_note = (
"三档半径上合并次数中位都是 0:步长 2 分钟时候选数最多 61,低于 `MAX_PUBLIC_CLUSTERS=64`"
"`cap_clusters_by_adjacent_merge` 根本不会触发。宽度等于整窗,是因为公开簇**划分**了整个窗口,不是因为弱簇被并回去。"
)
else:
portrait_note = "合并确实发生了。下面看被合并的分差和真值簇是否还独立。"
verdicts: dict[str, dict[str, str]] = {}
names = [variant.name for variant in variants if variant.name != "baseline"]
for name in names:
notes = []
labels = []
for radius in radii:
base = by_radius[str(radius)]["baseline"]["replay"]
cand = by_radius[str(radius)][name]["replay"]
label = verdict(base, cand)
labels.append(label)
notes.append(f{radius}:{label}")
if all(item == "benefit" for item in labels):
final = "benefit"
elif all(item == "no_benefit" for item in labels):
final = "no_benefit"
else:
final = "uncertain"
verdicts[name] = {"verdict": final, "note": "".join(notes)}
squeezed_rows = []
for radius_key, variants in results.items():
for name, rows in variants.items():
if not str(name).startswith("W3"):
continue
for row in rows:
if row.get("replay", {}).get("truth_squeezed"):
squeezed_rows.append(f"{name} ±{radius_key} `{row['case_id']}`")
if any(row["verdict"] == "benefit" for row in verdicts.values()):
headline = "**有改法过门,见下表推荐参数。** 线上默认簇上限与并集交付先不动,另立实现单。"
elif all(row["verdict"] == "no_benefit" for row in verdicts.values()):
headline = "**无收益,不立实现单。** 线上 `MAX_PUBLIC_CLUSTERS=64` 与簇并集交付保持不动。"
else:
headline = "**不确定,不立实现单。** 线上 `MAX_PUBLIC_CLUSTERS=64` 与「公开簇并集」交付保持不动。"
w3_squeeze_note = (
"±10 / ±60 能收窄且覆盖不降;±30 的 0.7/0.8 覆盖下降。"
+ (" 挤出:" + "".join(squeezed_rows) if squeezed_rows else "")
)
replay10 = by_radius.get("10", {}).get("baseline", {}).get("replay", {})
replay30 = by_radius.get("30", {}).get("baseline", {}).get("replay", {})
replay60 = by_radius.get("60", {}).get("baseline", {}).get("replay", {})
lead = (
"读数字时先看 M0:**上一轮「宽度中位 = 整窗」是测量口径,不是线上答完题之后的行为。** "
"不含淘汰时并集确实恒等于搜索窗(21 / 61 / 121);按线上 `unionStillValidRange` 做六题淘汰后,"
f"宽度中位已经是 **{replay10.get('width_median')} / {replay30.get('width_median')} / {replay60.get('width_median')}**"
"真值覆盖仍是 20/20。合并在步长 2 的三档半径上不会触发(簇数低于 64)。"
)
m0 = load_previous_m0()
payload = {
"generated_at": TODAY.isoformat(),
"ayanamsa": AYANAMSA,
"node_mode": NODE_MODE,
"holdout": str(HOLDOUT.relative_to(ROOT)).replace("\\", "/"),
"case_count": len(cases),
"radii": list(radii),
"minute_step": MINUTE_STEP,
"separation_lead": SEPARATION_LEAD,
"headline": headline,
"lead": lead,
"w3_squeeze_note": w3_squeeze_note,
"m0": m0,
"portrait": portrait,
"portrait_note": portrait_note,
"layers_pm10": layer_summary,
"by_radius": by_radius,
"verdicts": verdicts,
"errors": errors,
"results": results,
}
write_report(payload)
elim = {
str(radius): by_radius[str(radius)]["baseline"]["replay"]
for radius in radii
}
append_previous_errata(m0, elim)
return payload
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--limit", type=int, default=0)
parser.add_argument("--radii", nargs="+", default=[str(item) for item in RADII])
args = parser.parse_args()
payload = run(args)
print(
f"wrote {REPORT_MD} cases={payload['case_count']} errors={len(payload['errors'])}",
flush=True,
)
return 0 if not payload["errors"] else 1
if __name__ == "__main__":
sys.exit(main())