验收 7f28bfec/d97b9e9f:tsc、lint、Python quick gate 均无新增失败,但 npm test 由基线 27 红涨到 33——6 条全是「该交付却不交付」,因为 shouldHoldForTieBreak 放宽后连 exhausted 与 closed-ceiling 收口路径也被压住(BUG-688 修复单)。 研究单接上一轮结论:五个打分改法都改不动交付区间宽度,所有方案宽度中位数等于 整个搜索窗。先查 sweep 的宽度口径是否包含淘汰,再查 cap_clusters_by_adjacent_merge 「从不丢簇」与签名层过细两条线索,量三个候选改法。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
6.1 KiB
6.1 KiB
研究单 · 为什么交付区间宽度永远等于整个搜索窗(2026-09-14)
- 基线:
origin/staging@2d2467dc。 - 分支:
codex/rectification-cluster-width-research-20260914,worktree.worktrees/rectification-cluster-width-research-20260914。 - 性质:离线测量与取证,不改线上行为。 有可行改法才另立实现单。
- 前序:
TASK-rectification-minute-resolution-research-20260914.md(结果docs/research/minute_resolution_2026_09_14.md)——五个打分改法在三档半径上都没过门,最硬的发现是所有方案(含基线)的交付区间宽度中位数都等于整个搜索窗(±10 → 21 分钟、±30 → 61、±60 → 121)。本单接着查这一条。
1. 问题
用户端最直接的痛点是"范围卡给的区间太宽、几个候选可能性差不多"。上一轮证明:调打分权重改不动宽度。所以宽度是被别的东西决定的。
两条待查线索(都在 scripts/rectification/candidate_contrast.py):
- 公开簇的并集按设计铺满窗口。
cap_clusters_by_adjacent_merge(:247)的 docstring 原文就是 "Keep the whole window. If there are too many clusters, merge adjacent weak ones."——簇超过上限时合并相邻弱簇,但从不丢弃,所以簇并集恒等于整个搜索窗。交付区间取的是"仍然有效的簇的并集",于是只要没有候选被真正淘汰,宽度就等于整窗。 - 签名层可能过细。
SIGNATURE_LAYERS = ("d1","d9","d10","d24","d4","d12","md")(:25)。若在 ±10 分钟内几乎每分钟一个签名,簇数会一直顶到上限,再靠上面的合并强行压回——等于用"合并"替代了"区分"。
还有一条必须先排除的测量口径问题:上一轮 sweep 的宽度指标是否包含淘汰?真机上范围确实会收窄(真实会话里 04:45–05:15 → 04:48–05:07 是靠 4 个候选被淘汰实现的)。如果 sweep 只做打分与回放、不做淘汰,那"宽度恒等于整窗"就是测量口径的产物,而不是线上行为。这一条不查清,后面所有结论都不成立。
2. 要量的东西
M0(前置,必做)· 先确认口径
- 读
scripts/research/minute_resolution_sweep.py与minute_resolution_lib.py,确认宽度指标的定义:是取"全部候选簇的并集"还是"未淘汰候选簇的并集";回放六题时有没有执行淘汰。 - 如果没有淘汰:在 sweep 里补上与线上一致的淘汰逻辑,重跑基线宽度,给出"含淘汰 / 不含淘汰"两组数字。
- 交付判断:若含淘汰后宽度本来就会收窄,则上一轮"宽度不变"的结论只适用于不含淘汰的口径,要在
docs/research/minute_resolution_2026_09_14.md补一条勘误(不删原文,追加说明)。
M1 · 簇结构画像
在 v4 的 20 例、三档半径上统计:
- 每例的原始签名簇数(合并前)、合并次数、合并后簇数;
- 合并掉的簇的峰值分差(被合并的两个簇分数差多少);
- 真实分钟所在的原始簇,在合并之后是否还独立存在(关键:如果真值簇被并进一个大簇,用户就永远看不到那个分钟单列);
SIGNATURE_LAYERS里每一层在 ±10 窗内的取值变化次数(找出哪些层在窄窗内是常数——例如md月宿在同日窗口内恒定,占了签名位却不提供区分)。
M2 · 三个候选改法(只量,不改线上)
| 编号 | 改法 | 关注指标 |
|---|---|---|
| W1 | 提高 MAX_PUBLIC_CLUSTERS(不合并或少合并),看真值簇是否更常独立存在;同时看卡片是否变得太长(用户一次看不过来) |
真值簇独立率、簇数中位数 |
| W2 | 合并时改按分数差而不是"相邻且弱":分差超过阈值的两簇不得合并,宁可超上限 | 真值簇独立率、被合并的分差分布 |
| W3 | 交付区间改用"仍然有效候选的分数分位覆盖"(例如覆盖 posterior 质量 80% 的最小连续区间),而不是簇并集 | 宽度中位数、真值落在区间内的比例(不得下降) |
统一指标沿用上一轮五项:真实分钟命中率、真值落在交付区间内的比例(不得下降)、区间宽度中位数、并列率、每轮熵降;另加"真值簇独立率"。
3. 交付
scripts/research/cluster_width_probe.py(新)+ 结果docs/research/cluster_width_2026_09_14.md/.json。- 口径声明与上一轮一致(ayanamsa
raman、node modemean),不得与上游 true-node 数字直接比。 - 结论只允许三种:有收益(真值覆盖率不降、宽度中位下降或真值簇独立率显著上升)→ 立实现单并给推荐参数;无收益 → 关闭写明;不确定 → 说明缺什么。
- 不得改
scripts/rectification/candidate_contrast.py的线上默认值;不得把研究脚本接进生产路径。
4. 硬红线
- Python 改动跑
.venv/bin/python scripts/run_quality_gate.py --profile quick(已知既有缺口:test_shadbala_endpoint_returns_ranked_planet_strength,时区依赖缺失,基线同样红,不计入)。 - 不得为了把宽度做窄而牺牲真值覆盖率——真实分钟被挤出交付区间是比"区间宽"严重得多的错误(
AGENTS.mdPart B B4)。 - 不得放宽置信度或确认门控。
- 不得使用真实用户资料;样本只用既有 v4 公开 AA 数据。
- 结论必须落到数字,不接受"感觉更准"。
5. 开工前置命令
git fetch origin --prune
git worktree add -b codex/rectification-cluster-width-research-20260914 \
.worktrees/rectification-cluster-width-research-20260914 origin/staging
cd .worktrees/rectification-cluster-width-research-20260914
ln -s /workspace/Jyotisha/.venv .venv
python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45
开工前读:docs/research/minute_resolution_2026_09_14.md(上一轮结论与它的适用边界)、docs/research/upstream_rectification_gap_2026_09_14.md、scripts/rectification/candidate_contrast.py 全文。
6. BUG 编号
- 研究单,不新增 BUG 编号。若立实现单,届时按当时最大号顺延。