Files
Jyotisha/docs/research/rectification_offline_research_2026_09_26.md
T
Jesse_ChenandClaude Opus 5.5 0f5442cea2 research(rectification): offline R1/R2/R3 — answer-flip tolerance, V1/V2 rerun, dasha shift arithmetic
- R1: flipping 1 answer keeps truth in range 98-100% but cuts head hit by
  a third or more; 2 flips squeeze truth out in 7-10% of ±30/±60 replays
  (two flips = 8 points = SEPARATION_LEAD).
- R2: weights do apply (research scorer == production at V0); V1/V2 are
  identity at ±30/±60 by construction and leave six-question metrics
  unchanged at ±10 -> no_benefit (measured). Supplementary V1n does not
  pass the gate.
- R3: boundary shift is ~3.8 days/minute (1.3-5.9), not 1.1; the 45-day
  gate is ~8-34 minutes. The _representative_pairs hypothesis is refuted
  (all-pairs adds no dated probes); the bottleneck is monthly evaluation.
  New finding recorded as BUG-1048 (investigating): _boundary_windows
  year-straddle exemption and positional zip misalignment bypass the gate.
- Dated errata appended (no deletions) to the 09-14/09-16 briefs and
  research docs; README board row -> 待验收. No production code, scoring,
  thresholds, gates or Skill changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-26 14:47:48 +08:00

20 KiB
Raw Blame History

生时校正三项离线研究(2026-09-26)

  • 任务书:docs/tasks/TASK-rectification-offline-research-20260926.md;进度:docs/tasks/PROGRESS-rectification-offline-research-20260926.md
  • 分支:codex/rectification-offline-research-20260926,测量在 origin/staging @ 7ddce2c9 上完成(引擎代码与任务书基线 abb05b67 相同),提交已变基到 7203d94e(其间只新增 fewer_probes_card_replay.py 与文档,引擎与打分代码未变)。
  • 性质:离线测量。不改线上代码、打分、阈值、出题闸门、Skill。 研究脚本读引擎内部函数,个别测量在一次调用内临时替换模块属性,调用结束立即恢复,脚本末尾断言已恢复。
  • 数据:references/real_case_calibration/minute_rectification_holdout_v4.json,20 例公开 Rodden-AA 名人。R3a 只用随机虚构时刻。这是开放集回放,不是盲测,下面的数字不是准确率。
  • 口径:ayanamsa raman,node mode mean,步长 2 分钟,半径 ±10 / ±30 / ±60。交付区间 = 未淘汰、且落后头名不足 8 分的簇的并集(线上 unionStillValidRange)。六题回放沿用 09-14 研究:同一份六道题,不随作答重新出题。
  • 同机 A/B:R1、R3a 在 PYTHONHASHSEED 不同的两次运行下 JSON 逐字节一致;R2、R3c 换 PYTHONHASHSEED 复跑,汇总与已存 JSON 完全一致(见进度记录)。不与其他机器的浮点结果比对(BUG-985)。

结论

项 一句话结论 是否建议立实现单
R1 答错容错 答错 1 题,真值几乎都还在区间里(98–100%),但头名命中降三到四成。答错 2 题,±30 / ±60 上约 7–10% 的回放会把真值挤出区间,半数以上的例子至少有一种两题组合会挤出。原因是两道反答正好造成 8 分差,等于淘汰线 不立实现单。给产品一条口径:区间变窄不等于更准(±10 反答后宽度反而从 15 收到 11)
R2 V1/V2 分盘配权 权重确实生效了:研究计分器在 V0 与线上逐分相同。V1/V2 在 ±30 / ±60 上按定义就是恒等,0 个候选分数变化。在 ±10 上改了约 3/4 候选的分数(最多 0.4–0.6 分),六题后指标与基线完全相同。判定由 not_measured 改为 no_benefit(已实测) 不立实现单。补充的 V1n(按敏感度归一化重新分配权重)头名 +1/+1/+2 例,但宽度没降,±60 宽度 56→73,不过门
R3 算术改正 1 分钟对应大运边界位移中位 3.8 天,不是 1.1 天(p10 1.6、p90 5.0,范围 1.3–5.9),按出生星宿主星分两档。45 天闸门对应 8–34 分钟(中位 12,p10–p90 为 9–29),不是 40 分钟。_representative_pairs 推断被推翻:改成全部两两配对后,带日期的题一道都没多。真正的卡点在逐月评估:只有 3%(刷新阶段 0.4%)的边界月份能让代表候选分到两边 不立实现单。另记一个新发现:_boundary_windows 有两处绕过闸门的漏洞(跨 1 月 1 日豁免、按位置 zip 错位),记为 BUG-1048 investigating,是否修要等产品决定

R1 · 答错 1–2 题的容错

方法。 每例每个半径用线上 G0 闸门出题,取前六题。按真值给出最优是 / 否,再从能作答的题里随机选 1 题或 2 题反过来答(固定种子 20260926,按例、半径、题数、重复序号生成随机数,每格重复 30 次)。另外对所有组合穷举一遍作对照。能作答的题少于 k 的例子不进该格;所以每格另列「同一批例子不答错」的基线。

复跑:python3 scripts/research/answer_flip_tolerance.py(约 1 分钟)→ docs/research/answer_flip_tolerance_2026_09_26.json

半径 答错题数 例数 回放次数 真值在区间 头名命中 宽度中位(分钟) 至少一次挤出真值的例子 同批例子不答错:命中 / 宽度
±10 0 20 20 1.000 0.80 15 0 —
±10 1 16 480 1.000 0.58 13 0 0.94 / 12
±10 2 15 450 0.996 0.40 11 1 0.93 / 11
±30 0 20 20 1.000 0.55 33 0 —
±30 1 18 540 0.989 0.33 35 1 0.61 / 32
±30 2 18 540 0.926 0.08 33 9 0.61 / 32
±60 0 20 20 1.000 0.40 56 0 —
±60 1 18 540 0.981 0.24 73 2 0.44 / 54
±60 2 18 540 0.898 0.06 71 12 0.44 / 54

穷举对照(每例所有 1 题 / 2 题组合):真值在区间 ±10 1.000 / 0.990,±30 0.991 / 0.919,±60 0.981 / 0.907;头名 ±10 0.66 / 0.43,±30 0.33 / 0.09,±60 0.23 / 0.06。随机抽样与穷举一致。

不答错的基线与 09-14 精度闸门研究的 G0 完全一致(0.80 / 0.55 / 0.40;15 / 33 / 56;20/20),说明回放链路没有漂移。

读法。

  1. 真值从未被淘汰。 强冲突淘汰要 3 次;答错 2 题最多给真值 2 次冲突。
  2. 挤出真值靠的是 8 分线。 一道反答让真值 −2、另一侧 +2,相对差 4 分;两道反答正好 8 分,等于 SEPARATION_LEAD = 8。所以 k=2 开始挤出真值,k=1 只有真值原本就贴线的例子才会被挤出。
  3. ±10 上答错反而让区间更窄(15 → 13 → 11),头名却从 0.94 掉到 0.40。窄是因为错误答案把一个假头名推高了,不是因为更准。产品口径:不要把「范围变窄」讲成「更确定了」。
  4. 回放的六道题不随作答重出,这一点对答对和答错两边都一样。真人答错后,后续题目可能被带偏,实际影响可能更大,本回放测不到。

是否建议立实现单:不建议。 容错与淘汰线(8 分、3 次冲突)是同一组常数,要改就会同时影响答对时的宽度,需要另立研究。可选方向(均未测):答题之间出现矛盾时放宽交付并集;在交付卡上允许「改一道答案」。


R2 · V1/V2 分盘敏感度配权重跑

背景。 09-14 精度闸门研究的 M1b 里,V1/V2 与 V0 数字完全一样。BUG-692 把判定改成 not_measured,文中怀疑「权重没真正打上」。本轮先证明权重有没有生效,再重跑。

复跑:python3 scripts/research/varga_sensitivity_rerun.py(约 16 分钟)→ docs/research/varga_sensitivity_rerun_2026_09_26.json

第一步:权重是否改了分数

半径 研究计分器 V0 vs 线上 V1 vs V0:分数变化的候选 V1 最大分差 V1 头名变化例 V2 vs V0:分数变化的候选 V2 最大分差 V2 头名变化例 V2 丢掉某领域分盘的例子
±10 0 / 220 不同 168 / 220(17 例) 0.428 0 159 / 220(17 例) 0.625 1 12
±30 0 / 620 不同 0 / 620 0 0 0 / 620 0 0 0
±60 0 / 1220 不同 0 / 1220 0 0 0 / 1220 0 0 0

V1 系数 min(窗宽 / 分盘换一次上升的分钟数, 1):

窗宽 D2 D3 D5 其余 8 张(D4/D7/D9/D10/D11/D12/D24/D30)
20 分钟(±10) 0.33 0.50 0.83 1.00
60 分钟(±30) 1.00 1.00 1.00 1.00
120 分钟(±60) 1.00 1.00 1.00 1.00

结论:权重生效了,是 V1/V2 的定义本身在宽窗上等于恒等。 11 张计分分盘里最慢的 D2 每 60 分钟换一次上升,窗宽 ≥ 60 分钟时 V1 每个系数都截断到 1。V2 只丢掉窗内一次都不变的分盘,窗宽 ≥ 60 分钟时每张都会变。±10 上两者确实改了分数,但幅度小于候选之间的分差。09-14「与 V0 相同」的数字是真实结果,不是没打上权重。

第二步:按 closure 口径重跑(G0 闸门、六题回放)

半径 方案 头名命中 真值在区间 宽度中位 引擎头名(答题前) 六题后再出 判定
±10 V0 0.80 20/20 15 0.30 3.25 基线
±10 V1 0.80 20/20 15 0.30 3.25 no_benefit
±10 V2 0.80 20/20 15 0.35 3.25 no_benefit
±10 V1n(补充) 0.85 20/20 15 0.45 3.25 no_benefit(宽度未降)
±30 V0 0.55 20/20 33 0.20 5.45 基线
±30 V1 / V2 0.55 20/20 33 0.20 5.45 no_benefit(恒等)
±30 V1n(补充) 0.60 20/20 33 0.15 5.45 no_benefit(宽度未降)
±60 V0 0.40 20/20 56 0.05 5.75 基线
±60 V1 / V2 0.40 20/20 56 0.05 5.75 no_benefit(恒等)
±60 V1n(补充) 0.50 20/20 73 0.10 5.90 no_benefit(宽度变宽)

判定沿用 precision_gate_lib.gate_verdict:头名不降且宽度下降才算有收益,覆盖不得下降。

V1n 是什么。 这是 09-14 设计里没有的补充方案。每张分盘的系数与「换一次上升的分钟数」成反比,再归一化到 11 张盘的平均系数等于 1。总分量不变,只把权重从慢盘挪到快盘(D2 0.17、D3 0.26、D5 0.43、D7 0.60、D9 0.77、D10 0.85、D11 0.94、D12 1.02、D4 1.36、D24 2.05、D30 2.56)。它改了全部候选的分数,头名多中 1 / 1 / 2 例(20 例里),但宽度没有收窄,±60 反而变宽。样本只有 20 例,+1 例在噪声范围内。

是否建议立实现单:不建议。 V1/V2 结论更新为 no_benefit(已实测)。V1n 若要继续,先补 ±7 天日期偏移和 R1 答错两项稳健性,再谈实现。


R3 · 改正「1 分钟 ≈ 1.1 天」与 _representative_pairs 推断

R3a · 1 分钟对应多少天

复跑:python3 scripts/research/dasha_shift_per_minute.py(1 秒)→ docs/research/dasha_shift_per_minute_2026_09_26.json

推导。 第一段大运的余额是 (1 − 星宿内进度) × 主星年数。之后每一个 MD / AD / PD 的起点都等于「出生 + 余额 + 固定时长」,所以出生时间挪 1 分钟,所有边界整体平移同一个天数:

平移天数 / 分钟 = 月亮每分钟走的度数 ÷ 13.333° × 主星年数 × 365.25

月亮平均每分钟 0.0091°。Vimshottari 120 年覆盖 9 个星宿(120°),平均 1° ≈ 365 天,按主星从 164 天(太阳 6 年)到 548 天(金星 20 年)不等。09-14 文档写的「1° ≈ 122 天」是错的,于是算成 0.0092 × 122 ≈ 1.1 天,把位移低估了约 3.5 倍。

实测(2000 个虚构时刻,种子 7,swisseph 恒星黄道 Raman):

测法 n 平均 p0 p10 p25 中位 p75 p90 p100
解析式(月速 × 主星年数) 2000 3.32 1.34 1.58 1.80 3.82 4.54 5.00 5.85
差分(余额在 t 与 t+1 分钟) 1997 3.32 1.34 1.58 1.80 3.82 4.54 5.00 5.85
仓库 _vim_start_dates(t 与 t+20 分钟,÷20) 299 3.50 1.35 1.60 1.95 4.05 4.55 5.00 5.75

仓库函数的所有 MD / AD 起点在 20 分钟内平移同一个天数(对齐后差值最大相差 1 天,是日期取整)。它是前 300 个时刻的子样本,中位 4.05 与全样本 3.82 的差异来自抽样。

按出生星宿主星分两档(中位,天 / 分钟):太阳 1.50、火星 1.71、计都 1.77、月亮 2.47 | 木星 3.96、水星 4.18、罗睺 4.54、土星 4.71、金星 4.93。前一档约占 45%。所以「中位 3.8」落在两档之间,单个人的实际值要么约 1.5–2.5,要么约 4–5。

闸门与窗宽换算(改正后)

候选相隔 边界相差(天,中位 / p10 / p90) ≥45 天的比例 ≥30 天的比例 旧文档写的
2 分钟 7.6 / 3.2 / 10.0 0% 0% ≈ 2 天
4 分钟 15.3 / 6.3 / 20.0 0% 0% —
10 分钟 38.2 / 15.8 / 50.0 27% 54% —
20 分钟 76.5 / 31.5 / 100.0 66% 94% ≈ 22 天、不可出题
30 分钟 114.7 / 47.3 / 149.9 94% 100% —
40 分钟 153.0 / 63.1 / 199.9 100% 100% ≈ 45 天
  • 45 天闸门 ↔ 中位 11.8 分钟(p10 9.0,p90 28.5,全范围 7.7–33.5)。
  • 30 天刷新闸门 ↔ 中位 7.8 分钟(6.0–19.0,全范围 5.1–22.3)。

不同精度的证据能分开多近的候选

证据日期要落在两个候选的边界之间,才能把它们分到两边。所需边界差约等于证据的日期跨度,再除以每分钟平移天数:

证据精度 日期跨度 稳定可分的候选间距(分钟) 快档 p90 中位 慢档 p10 最慢
确切某一天 1 天 0.2 0.3 0.6 0.7
某天 ±3 天 7 天 1.4 1.8 4.4 5.2
某天 ±7 天 15 天 3.0 3.9 9.5 11.2
记得到月 30.4 天 6.1 8.0 19.3 22.6
线上 45 天闸门 45 天 9.0 11.8 28.5 33.5
只记得年 365 天 73 95 232 272

低于这个间距时,只有两条边界恰好跨在月初(或年初)两侧才能分开,概率约为「边界差 ÷ 跨度」。例如按中位平移,相隔 2 分钟的一对候选:跨月概率 25%,跨年概率 2%;相隔 20 分钟:跨年概率 21%。

所以: 记得到月的事件,在候选相隔约 8 分钟以上(慢档约 20 分钟以上)时就够用;记得到天(容许几天误差)的事件,能分开相隔 2–5 分钟的候选。只记得年的事件单靠大运边界分不开 ±60 以内的候选,只有跨年的那一小部分边界例外。

R3c · _representative_pairs 推断核实

任务书的推断: 「出不来题」的真正原因可能是 _representative_pairs 只比较相邻代表分钟和首尾一对,相邻代表太近,边界差过不了闸门。

复跑:python3 scripts/research/representative_pairs_probe.py(约 6 分钟)→ docs/research/representative_pairs_probe_2026_09_26.json

对每例每个半径,在「初始」(全部候选)与「刷新」(六题回放后剩余候选,与 09-14 相同)两个阶段,比较三种设置:线上配对;研究补丁返回全部两两配对;研究补丁把 _boundary_windows 改成严格闸门(对所有配对都卡最小间隔、不豁免跨年,并把错位的 zip 对齐)。题目数在公开截断之前统计。

半径 · 阶段 代表数中位 线上配对:过闸对数均 全配对:过闸对数均 带日期的题(截断前,每例均值)线上 / 全配对 / 严格闸门 公开题里没有新的带日期题的例子 线上 / 全配对 / 严格闸门 边界月份评估次数均 能分开代表的比例
±10 初始 6 0.60 3.30 4.85 / 4.80 / 4.10 4 / 4 / 8 168 3.2%
±10 刷新 4 0.90 1.65 3.25 / 3.30 / 3.10 3 / 3 / 4 809 0.4%
±30 初始 16 1.00 76.5 6.75 / 6.75 / 6.55 2 / 2 / 2 226 4.2%
±30 刷新 5 1.80 4.95 5.30 / 5.25 / 5.30 2 / 2 / 2 1130 0.5%
±60 初始 31 1.00 400.6 6.95 / 7.05 / 6.85 2 / 2 / 2 255 4.5%
±60 刷新 5 1.95 5.55 5.55 / 5.60 / 5.60 2 / 2 / 2 1057 0.5%

「没有带日期题」的例子里,每格都有 2 例是 1900 年前出生的(毕加索 1881、弗洛伊德 1856):_birth_year 只接受 1900–2100,出题器对它们直接返回空,与闸门无关。

结论:推断被推翻。

  1. 全部两两配对没有多出一道带日期的题。 过闸的配对多了好几倍,日期并集也变大,但带日期的题数不变(差异 ≤0.1 道),没有题的例子数完全相同。首尾那一对已经是间距最大的一对,中间补上的配对只贡献更靠内的月份,这些月份照样分不开代表。
  2. 真正的卡点在逐月评估。 _evaluate_contexts 在每个边界月份判断各代表在该领域是否被激活,要求一边激活、一边不激活。初始阶段每例评估约 170–250 个边界月份,只有 3–4.5% 能分开;刷新阶段带上 PD 后评估 800–1100 个,只有约 0.5% 能分开。
  3. v4 回放里六题后题池并不空。 ±10 刷新阶段平均还能出 3.25 道新的带日期题,1900 年后出生的 18 例里只有 1 例为 0。真机上「问完了」的原因用 v4 复现不出来。候选原因包括:采集线已关或被拒、已问年份、封存年份、存在性封锁年份、真人事件多为月精度,都未测。需要真机统计(见 TASK-rectification-telemetry-20260926.md)才能定性。
  4. 新发现:_boundary_windows 有两处绕过闸门。
    • 跨年豁免:代码写的是 one.year == two.year and 差 < 阈值 才跳过。两条边界只差 7 天、但分别落在 12 月底和 1 月初,也会被放行。例:某例 ±10 初始阶段,放行的 6 个日期全是这种一周内跨年的对(12-27 / 01-03 这类),逐月评估全部失败。
    • zip 错位:两个候选的边界列表按位置配对。一旦某条边界跨出 [出生+5, 出生+80] 的年份边缘,列表会差一到两个元素(MD 起点与其第一个 AD 起点同一天,所以一次可能差两个)。此后每一对比的都是不对应的边界,间隔很大,于是全部放行。20 分钟虚构对(只算 MD+AD)有 10.7% 错位;刷新阶段(含 PD)线上配对有 35–44% 错位。
    • 改成严格闸门后,±10 初始阶段没有带日期题的例子从 4 例变成 8 例,刷新阶段从 3 例变成 4 例,宽窗基本不变。也就是说,窄窗上现有的一部分带日期题是靠这两个漏洞出来的。这些题问的是「边界只差几天的那个月」,按月精度回答是否可靠,本轮没有评估。已记为 BUG-1048(investigating),不改代码。

改正与文案建议

已加勘误段(不删原文):

  • docs/tasks/TASK-rectification-precision-adaptive-boundary-research-20260914.md(1.1 天、122 天 / 度、换算表)
  • docs/tasks/TASK-rectification-open-collect-invite-20260914.md(D1b 的依据句)
  • docs/tasks/TASK-rectification-precision-gate-guided-collect-20260916.md(实证第 5 条「20 分钟 ≈ 22 天,题池必然为空」)
  • docs/research/precision_gate_2026_09_14.md(M1b:V1/V2 改为已实测 no_benefit)
  • docs/research/rectification_minute_resolution_closure_2026_09_14.md(索引里 V1/V2「未测」的说明)

引导邀请语的依据:建议改写(不改线上文案)。 线上现在的引导题是「YYYY 年 M 月前后,有没有 X?」加年 / 月选择器,日期可选(BUG-740 起)。BUG-689 / D1b 的依据句建议改成:

出生时间每差 1 分钟,Vimshottari 边界整体平移约 1.3–5.9 天(中位约 3.8 天,取决于出生星宿的主星)。记得到月的事件,在候选相隔约 8 分钟以上(慢的星宿约 20 分钟以上)时就能把它们分开;记得到具体哪天(容许几天误差)的事件,能分开相隔 2–5 分钟的候选。但 v4 开放集上把日精度降成月精度,头名与宽度都没有变化(精度闸门研究 M0),所以不能写成「记得到天明显更有用」已经证实,更不能承诺能定到分钟。

对用户文案的建议(仅供产品决定):选择器保持「日可选」,旁边一句「记得哪天就选上,记不清选到月也可以」。只在剩余候选相隔不到约 8 分钟时(交付区间 ≤ 10 分钟的收尾阶段)才值得主动追问具体哪天。不写任何「能定到分钟」的承诺。


附:全部复跑命令

python3 scripts/research/answer_flip_tolerance.py            # R1,约 1 分钟
python3 scripts/research/varga_sensitivity_rerun.py          # R2,约 16 分钟
python3 scripts/research/dasha_shift_per_minute.py           # R3a,1 秒
python3 scripts/research/representative_pairs_probe.py       # R3c,约 6 分钟
python3 -m pytest tests/test_offline_research_20260926.py    # 纯函数回归