相邻分钟可区分:换运日期贴近度打分(P0)、known_event_quality 受门控升级为区分题、基础率校正的期望信息增益、簇内不可分时 的前瞻验证登记。依赖 Round A(provisional-adopt)先行合入。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
10 KiB
任务书 · Round 2 引擎侧收敛能力:相邻分钟可区分(2026-09-01)
基线:origin/staging @ 422fc65b。
0. 定位与执行顺序(必读)
本轮是 TASK-rectification-provisional-adopt-20260901.md(Round A)的后续,必须在 Round A 合入并验收后再合入本轮;可以并行开发,但不得混进同一个 PR。分工:
- Round A 解决"拿不到结果":provisional 采用成为一等成功出口(TS 决策层)。
- 本轮解决"结果能更细":让引擎具备把相邻分钟候选真正分开的能力(Python 引擎为主 + 少量 TS 接线)。Round A 红线 7"不修引擎"仅约束 A 轮,本轮就是引擎轮。
背景:为什么相邻分钟现在分不开(已静态核实)
事故 case f83d9b42(快照见 Round A §1):top-2 候选 05:00 与 05:07 分差 5、永远到不了 8,因为——
- 打分粗粒度:
_score_event只做"大运/副运/微运主星是否落在主题宫位/宫主/主题分盘"的匹配,对相差 7 分钟的两个候选给分几乎相同。 - dasha_boundary 区分题按大运边界年切窗口,相邻分钟几乎总在同一侧(逐条核对过该 case 全部
expected_outcomes)。 - 唯一能分开相邻分钟的 varga 换升对比题(D24 在 05:00/05:06 换升)无年份锚点,被
yearless_ungrounded_contrast政策丢弃——该丢弃政策是对的:不带时间锚的存在题("家里有没有结婚添丁住院")人群基础率接近 100%,答什么都不构成证据。 - 引擎自带的"已知事件品质题"机制被写死为 clarify-only:
scripts/rectification/event_probes.py第 4 行 "known_event_quality is clarification only and never a distinguish probe";TS 侧整类过滤(decision-from-dossier.ts:187、core/build-state.ts:254)。
方法论依据(本轮 P0 的正当性来源):references/birth-time-rectification-advanced.md——出生时间差 1 分钟,换运日期漂移 3-4 天。7 分钟差 ⇒ 换运日期差约 20-30 天 ⇒ 一条日级精度事件(该 case 已有 2024-08-08 分手)足以仲裁相邻候选。现有打分完全没有使用这一层。
1. 硬红线
- 绝不引入任何"答案钥匙"。 不得加入按已知用户/已知案例定向的回归提示、target_minute、校准包(教训见 Round A 根因 3:上游
pl9_1993 target_minute=14:49污染事件)。所有新打分与出题逻辑必须对任意未知用户同样成立,grep -rn "target_minute\|pl9_1993\|regression_only" scripts/ frontend/在改动后必须零命中。 - 确认门与表达边界不动。
confirmation_allowedfail-closed、"不可分区间/代表性候选"措辞、candidate/accepted/confirmed 三层语义、Round A 的采用门语义,一律不改。 - 版本与缓存一致性。 打分语义变化必须 bump
ALGORITHM_VERSION(active_rectification_events)与POLICY_VERSION(decision_policy.py),并确认 TScandidateSnapshotSource(core/snapshot-source.ts)因 policy 版本变化而判定旧快照过期、触发重算,而不是复用旧候选。 - 确定性。 新逻辑全部确定性可复算:同输入同输出;先验表是版本化常量,不得运行时拟合。
- 权重有界。 任何新分量单独不得超过一条日级事件本体的分值;不得让辅助层反客为主(沿用 skill 决策树"辅助裁判不是第一裁判"原则)。
- Python 侧改动跑
pytest tests/(受影响模块相关测试全过);frontend 侧./node_modules/.bin/tsc --noEmit+npx tsx --test tests/rectification-*.test.tsfail=0。不要用npx tsc。 - 不改
.gitea/workflows/**;不自行把 staging 提升到 main;无凭据不得声称已在真实环境验证。
2. 开工前置
git fetch origin --prune
git worktree add -b codex/rectification-engine-convergence-20260901 \
../.worktrees/rectification-engine-convergence-20260901 origin/staging
读 docs/research/pre_work_error_ledger.md、frontend/AGENTS.md、docs/BUG_HISTORY.md(BUG-456/459 及 Round A 记录)、references/birth-time-rectification-advanced.md(方法1)与 references/birth-time-rectification-decision-tree.md。行号只是线索,按符号名定位。
任务 0(门控)· 先写不变量,先让它红
Python 侧(tests/ 新增或扩展对应模块测试)+ frontend 侧各写:
- P0 核心回归:构造事故 case 形状(31 分钟网格、5 条事件含一条 day 级 2024-08-08 relationship_end),断言启用换运贴近度后 05:00 与 05:07 的分差发生可解释的非零变化,且 margin 方向与该分钟下 AD/PD 换运日期贴近度一致(用引擎自身输出核对,不得硬编码期望分数)。
- 基础率不变量:一道无年份家人存在题的最终出题排序必须低于一道锚定已知事件的品质题;主导答案先验 > 阈值的存在题不得被发出。
- 品质题门控:仅当候选 signature 组的分盘类型预测不同品质时,
known_event_quality才可作为 distinguish 出题;同品质预测时不得出题;每 case 上限 2 题。 - 无答案钥匙:红线 1 的 grep 断言写进测试或 CI 可执行脚本。
跑一遍确认 1-3 是红的。
任务 A(P0)· 换运日期贴近度打分——用已有证据分开相邻分钟
改 scripts/(Python):
- 新增确定性分量
dasha_transition_proximity:对每条date_precision ∈ {day, month}的可评分事件、每个候选分钟,计算该候选盘下事件日期附近(建议 ±45 天窗口)最近的 Vimshottari AD/PD 换运日期与 Narayana AD 换运日期,按贴近度给分(建议线性核max(0, 1 − |Δdays|/K),day 级 K≈15、month 级以月中代表日且 K≈45 并降权;year 级不参与)。边界日期计算复用event_probes.py既有的_vim_start_dates/_narayana_start_dates/_boundary_windows机制,不要另写一套历法。 - 分量并入候选打分(
_score_event或scoring_service聚合层,按现有架构选注入点),权重遵守红线 5;rule_ids记vim_transition_proximity_*/narayana_transition_proximity_*,execution ledger 增加对应 technique layer 行,_AUDIT_LABELS补中文行(如"换运贴近度:本轮已对照日级事件与候选换运日期的贴近程度")。 - 诊断联动:
date_sensitivity类诊断需覆盖新分量(日期扰动应显著改变贴近度分,这正是该分量的预期行为,不得因此误判不稳定——必要时对该分量单独设扰动容差并在 PR 里说明)。
验收锚:事故形状下,2024-08-08 这条 day 级事件对 05:00 与 05:07 产生可审计的分差贡献(贴 ledger 行与前后 margin)。
任务 B(P1)· known_event_quality 升级为受门控的区分题
改 scripts/rectification/event_probes.py + TS 接线:
- 政策变更(更新文件头注释):
known_event_quality允许作为 distinguish 探针,门控三条——(a) 仅当候选 signature 组在该事件主题分盘(D24/D5/D9/D10/D12/D4)上类型预测不同品质/方向时生成;(b) 每 case 上限 2 题;(c) 必须锚定一条 confirmed 证据(携带target_evidence_id与display_date_label),题干问品质不问存在("2016 年 9 月那次上大学,更接近如愿 / 将就调剂 / 发挥失常 / 说不清"),选项语义映射到候选组。 choice_kind沿用event_quality;expected_outcomes按类型表映射候选组,经assert_distinguish_contract校验。- TS 侧解除整类过滤但保留门控:
decision-from-dossier.ts(约 :187)与core/build-state.ts(约 :254)只放行携带target_evidence_id锚点的known_event_quality探针;method-followup.ts/choice-card.ts的 event_quality 渲染路径已存在(choice-card.ts:236),确认端到端可出卡;probe-question-contract如需版本演进按questionContractVersionIsCompatible兼容规则做。 - 打分权重:品质题答案对候选组的后验更新不得高于现有 ±2 制;在 PR 里说明取值。
任务 C(P1)· 基础率校正的期望信息增益
改 scripts/rectification/event_probes.py / candidate_contrast.py:
- 为每个(事件家族 × 窗口类型)配版本化答案先验常量表(保守估计即可,写明出处与理由;例:任意 3 年窗"家人婚/病/住院" p_yes≈0.85;指定年"本人迁居外地长住" p_yes≈0.2;已知事件品质"如愿/失常"≈0.5/0.3)。
- 排序指标改为期望信息增益
EIG = Σ_a p(a) × ΔH(a),保留原候选分割增益为raw_split_gain供审计;主导答案先验 > 0.8 的存在题不发出(进dropped_probes,reasondominant_answer_prior)。 yearless_ungrounded_contrast丢弃政策保留不动——本任务是给被丢弃的对比意图提供 B/C 两条合法出路,不是放开丢弃。
任务 D(P2)· 簇内不可分时的前瞻验证登记
改 scripts/rectification/refinement_packet.py + TS 展示:
- 当区分题耗尽且 top 簇稳定时,refinement packet 新增
prospective_probes:对每个存活候选组计算未来 1-3 年内的 AD/PD 换运窗口(领域 + 年月窗),输出"候选 A 预测下一次事业变动更可能在 X 年 Y 月附近;候选 B 在 Z 月附近"的结构化数据。不是问题、不计分、不进采用门,仅在交付轮叙述中呈现("下次发生时回来补一条,可进一步分辨"),并留在 receipt 里供 case 恢复时使用。 - TS:交付轮叙述接入该字段(
turn-narration.ts/ 交付文案路径),措辞保持"预测窗口"而非承诺;case 保持 resumable 语义不变。
验收标准
- Python:受影响模块 pytest 全过;任务 0 的四组不变量全绿。
- Frontend:
./node_modules/.bin/tsc --noEmitexit 0;npx tsx --test tests/rectification-*.test.tsfail=0(含 Round A 合入后的全部不变量)。 - 事故形状前后对照贴进 PR:任务 A 启用前后 top-2 分差与 margin、新 ledger 行;任务 B 生成的品质题样例(题干、选项、expected_outcomes);任务 C 下无年份存在题被
dominant_answer_prior丢弃的样例。 ALGORITHM_VERSION/POLICY_VERSIONbump 且旧快照判定过期的证明(snapshot-source 测试或等价说明)。- 红线 1 的零命中 grep 结果贴进 PR。
- 先验常量表逐项写明估计依据;未在真实环境验证的部分如实注明。