docs(research): brief for minute-resolution scoring, plus the upstream gap report

上游 b9a0ef8f..92d3a47a 的 43 个提交里生时校正零改动,没有新技法可取。候选
分不开的根因在本仓自己的打分结构:一个日精度事件里窗口内恒定的项上限 11.5
分,随分钟变化的项上限 2.125 分,约 5:1。研究单先修封存基准(v3 每例仅 3 件
事、被标 invalidated)出 v4,再离线量五个改法:分盘除数、去底座、KP 宫头子主
计分(产品 2026-09-14 拍板,推翻 BUG-325 的「不得计分」一条)、年精度事件改
边际似然、聚类签名层与计分层对齐。有收益才另立实现单。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
This commit is contained in:
Jesse_Chen
2026-09-14 11:17:33 +00:00
co-authored by Claude Fable 5
parent d97b9e9fe6
commit 9943a05a01
3 changed files with 298 additions and 0 deletions
@@ -0,0 +1,195 @@
# 上游生时校正能力对照报告(2026-09-14)
- 上游:`/workspace/yinduzhanxing`,分支 `origin/codex/add-birth-time-rectification-skill` @ **`92d3a47a`**2026-09-13 18:10)。上次评估点 `b9a0ef8f`2026-09-09)。
- 本仓:`origin/staging` @ `1c424bf6`2026-09-14)。
- 许可证:上游根 `LICENSE` = MITCopyright 2026 732642856),本仓 `references/upstream/yinduzhanxing/source-manifest.json` 已记录 `"license": "MIT"`。**代码可搬,需保留版权声明与出处**。上游 `references/open_source_sources/vedic-astro-skills/` 是第三方转载(自带 `LICENSE`,声称 MIT),若要引用其 `time_scan.py` / `vedic-rectifier` 内容,**需单独确认许可证**,不能按上游 MIT 一并处理。
- 本报告只读,未修改、未提交、未推送任何文件。
---
## 结论先行
1. **`b9a0ef8f..92d3a47a` 这 43 个提交里,生时校正一行代码都没动。** 全部是 PL9 长报告导出对账(parity dashboard、KP/Ashtakavarga 表格单元格、条件大运显示 profile、报告陈旧度审计)加研究台账。**没有新技法、没有新判据、没有新验证门。** 这一段增量对本仓的校正能力价值为零。
2. **上游唯一一条本仓没有的校正判据是 KP 宫头子主计分层**`KP_SUB_WEIGHTS`,上游 09-04 commit `27cdc353`,在 `b9a0ef8f` 之前就有,上一轮同步任务书没有逐条评估过它)。本仓已经算了同一份数据(`observe_kp_cusps`),但按 BUG-325 的产品红线**明确不计分**。要不要打开,是产品决策题,不是技术缺口题。
3. **"候选分不开"不是上游能解决的。** 上游自己 09-04 的复盘(`docs/research/rectification_process_v2_guardrails_2026_09_04.md` §5)写明:接了 KP 层、18 件事 5 个领域之后,结果仍是「整窗零淘汰」,从未批准唯一分钟。本仓 BUG-560 用 20 例封存 holdout 实测过同一件事。
4. **真正的根因在本仓自己的打分结构,而且是可算出来的:`_score_event` 里 11.5 分的上限来自窗口内恒定的项,只有 2.1 分上限来自会随分钟变化的项。** 详见 §4.1。这条本报告是新发现,之前的 Bug 记录只写到「引擎原始分分钟级≈随机」,没有定位到常量/变量项的配比。
5. 本仓在**产品层、问答层、诊断层**全面领先上游(信息增益选题、答案先验、边界年份反推、留一诊断、封存 holdout、区间交付)。缺的是**打分层的分钟分辨率**。
---
## 1. 上游增量摘要(`b9a0ef8f..92d3a47a`43 提交,194 文件,+283,695/493
### 1.1 按类别归并
| 类别 | 占比 | 代表落点 | 与生时校正的关系 |
| --- | --- | --- | --- |
| **PL9 长报告导出对账**(主体) | ≈90% | `scripts/pl9_full_parity_dashboard.py`(新 1,990 行)、`pl9_domi_same_case_dasha_replay.py`(新 1,190 行)、`pl9_export_maturity_contract.py``pl9_p92_p103_field_audit.py``pl9_p124_visual_cells.py``scripts/jyotish_engine.py` +2,733(全部是 `_attach_pl9_source_visible_tables` / `_sanitize_pl9_ai_density_markdown` / BAV 表格 / `_trikona_reduce` / `_ekadhipatya_reduce` 等导出函数) | **无关** |
| **研究台账 JSON/MD** | 体量最大 | `references/oracle/pl9_domi_p109_p120_same_case_date_diff_2026_09_10.json`+149,311 行)、`pl9_full_parity_dashboard_2026_09_11.json`+27,324 行) | **无关**,且按 `TASK-upstream-sync-20260903.md` 授权边界本来就不接收 |
| **Rashi dasha 显示 profile 仲裁** | 中 | `scripts/dasha_profile_arbitration.py`(新 314 行)、`rashi_dasha_named_profile_registry.py``drig_dasha.py` +179、`niryaana_shoola_dasha.py` +282、`shoola_dasha.py` +88、`navamsha_dasha.py` +85 | **无关**。目的是让 PL9 报告里的 Narayana/Drig/Shoola 大运日期与 Domi 参考 PDF 对上,不进校正评分(上游校正引擎只用 Vimshottari + Narayana,见 §2 |
| **Ashtakavarga PL9 显示 profile** | 小 | `scripts/ashtakavarga.py` +44`ASHTAKAVARGA_PROFILES = ("standard","pl9")``PL9_BAV_CELL_OVERRIDES`(对 Moon/Venus 若干星座**硬编码覆盖 bindu 值**) | **无关且不得取**。这是为了对齐某一份 PDF 而写死的单例覆盖,不是算法修正 |
| **其他** | 小 | `scripts/adhd_report_view.py`(新 203 行,报告可读性)、`electional_event_surface_contract.py`(择日)、`jh8_absorption_contract.py` / `jh8_external_inventory.py`(外部包清单)、`specialist_factor_surface.py``sade_sati.py` +303、`muhurta.py` +73、`tajika.py` +37、`competitive_product_signal_inventory.py`(竞品清单) | **无关** |
### 1.2 是否有新的校正技法 / 判据 / 门控
**没有。** 三重核验:
1. `git diff --name-only b9a0ef8f..92d3a47a | grep -iE 'rectif|birth.?time|minute'` 只命中 `references/oracle/pl9_public_varshaphala_minute_case_20260909.json`(年运案例,不是校正)。
2. 校正相关的 9 个源文件(`scripts/active_rectification_*.py``rectification_evidence.py``rectification_review.py``rectification_replay.py``rectification_technique_contract.py``birth_time_rectifier.py``references/birth-time-rectification-*.md``jyotish-app/rectification-engine.js`**全部零改动**。
3.`scripts/` + `mcp_server.py` 的新增行 grep `rectif|birth_time|candidate_minute|kp_dba|sub_lord`,12 条命中全部落在 PL9 KP 表格渲染与「竞品清单把 birth_time_rectification 列为一项产品功能」。
`docs/research/pl9_current_authority_state_2026_09_13.md`(本段最后一个提交)也只谈报告导出成熟度。
> 上一轮已评估过的项(`TASK-upstream-sync2-20260909.md` §1)不再展开:婚恋三层触发模型(已取)、10 套条件大运(已取)、Shadbala Raman profile(不取)、PL9 用户版(不取)、年运 SVG(不取)、`_known_case_regression_hint` 答案泄漏(不取)、`compare_candidate_minutes`(不取)。
---
## 2. 技法能力逐项对照
对照基准:上游 `scripts/active_rectification_event_engine.py` @ `92d3a47a`499 行,下称 `UP`)与本仓 `scripts/active_rectification_event_engine.py` @ `origin/staging`722 行,下称 `US`);辅以各自的问答层与诊断层。
| 维度 | 上游怎么做 | 本仓怎么做 | 判定 |
| --- | --- | --- | --- |
| **分盘(进评分)** | `UP:55 DOMAIN_CONFIG`education=D24relocation=D4relationship=D9career=D10finance=D2+D11health=D30family/parent=D12sibling=D3spouse_family=D9 | `US:55 DOMAIN_CONFIG`education=**D24+D5**relocation=D4relationship=D9career=D10finance=D2+D11health=D30family=**D12+D7+D3 合一**;另有 appearance(仅 D1 1 宫)、occupationD10 | **本仓超集**。本仓多 D5,且把六亲三分盘合进一个 family 域 |
| **分盘(算但不进评分)** | 无 | `US:452` 静态上下文算 D2/D3/D4/D5/D7/D9/D10/D11/D12/D24/D30 全部上升星座,进特征扫描与选题 | **本仓独有** |
| **D60 / D150 / Nadiamsa** | `references/birth-time-rectification-decision-tree.md` §6 写"已高度收敛后作最后参考",但引擎里没有 | 明确红线排除(BUG-317 防复发条:不得把 D16/D20/D27/D40/D45/D60、KP、Gulika、Kunda、Nadiamsa 当确认层) | 双方都不用;本仓是显式红线 |
| **Arudha** | `UP:246` A7/ULrelationship、spouse_family)、A10career),命中 +0.35 | `US:249` A7/ULrelationship)、A10career、occupation),命中 +0.35`US:471` UL 单独并入 `arudha_padas` | **等价** |
| **大运体系(进评分)** | Vimshottari MD/AD/PD`UP:113`+ Narayana MD/AD`UP:129`)。**仅此两轨** | Vimshottari MD/AD/PD + Narayana MD/AD。**仅此两轨** | **持平**。双方都没有把 Yogini / Ashtottari / Kala Chakra / 条件大运族接进校正(本仓引擎主链有这些,但 `scripts/rectification/**``active_rectification_*` 里 grep 零命中) |
| **pratyantar 深度** | PD 参与计分,权重 0.75 | PD 参与计分,权重 0.75 | 持平 |
| **大运换运临近度** | **无** | `scripts/rectification/dasha_transition_proximity.py`(198 行):day 精度事件距最近 Vim AD/PD 或 Narayana 换运 ≤45 天时按三角核给 ≤1.0 分,Vim/Narayana 6:4 分摊 | **本仓独有,且是本仓少数真正随分钟变化的评分项** |
| **过运 Gochara** | `UP:283` 仅木星/土星,事件日 12:00 起盘,对本命上升整宫,命中 +0.25/条,year 精度事件跳过 | `US:283` 同一实现,逐字节等价 | 持平。**双方都没有** Ashtakavarga 加权过运、Sade Sati、Vedha、Ashtakavarga Kakshya |
| **Ashtakavarga** | `UP:308` 目标宫 SAV 均值 ≥32 → +0.2,≤24 → 0.1 | `US:308` 同一实现 | 持平。均为整宫量,**窗口内恒定** |
| **Shadbala** | `UP:326` 只用 Sthana+Drik+Naisargika 三项,大运主星均值高于全盘均值 → +0.1,低于 → −0.05 | `US:326` 同一实现;另在 `US:479``birth_minute` 入参算全量 Shadbala 存指纹(只进诊断) | 持平(评分口径),本仓诊断更细 |
| **功能吉凶星** | `UP:209` `derive_functional_benefic_malefic(asc_sign)`,大运主星为功能吉 +0.2 / 功能凶 −0.1 | `US:209` 同一实现 | **持平**。注意:由上升**星座**推出,窗口内不跨星座时恒定 |
| **KP 宫头(Placidus 子主)** | **`UP:49 KP_SUB_WEIGHTS` + `UP:368 _kp_house_sublords` + `UP:437 kp_layer` 开关**:按候选分钟算 12 宫恒星 Placidus 宫头,取目标宫的 `sub_lord`/`sub_sub_lord`/`nakshatra_lord`,与当时运行的 Vim MD/AD/PD 主星比对,命中加分(MD 0.50/0.25、AD 0.35/0.15、PD 0.20/0.10)。默认 `kp_layer=False` | `scripts/rectification/kp_cusp_observation.py`87 行)算同一份数据(`swe.houses(..., b"P")` + Krishnamurti 岁差 + `get_kp_lords`),但文件头写明 **"Display-only … must never mix into ranking, propose, or unique-minute confirmation"**`US:71 OBSERVATION_ONLY_LAYERS = {"KP_cusps"}``decision_policy.py:39 POLICY_SKIPPED_LAYERS` 同样跳过 | **上游有、本仓故意没有。** 唯一一条上游领先的判据。BUG-325 防复发条写死"不得把 KP 观察计分或打开确认门" |
| **月宿边界** | 决策树 §5 文字层面提到"Nakshatra/Pada 是第四层收口" | `refinement_packet.py:509 nakshatra_boundary`:上升距月宿边界 ≤2.0° 时生成 A/B 性格二选一题(`NAKSHATRA_TRAITS` | **本仓独有(可执行实现)** |
| **上升星座边界** | 第三方转载的 `vedic-rectifier/scripts/time_scan.py``check_lagna_boundary`03° / 2730°)与 `ACCURACY_MATRIX`(按矫正精度决定哪些分盘可用);上游自己的引擎没有 | `refinement_packet.py:464 lagna_contrast`:窗口内出现两段本命上升时并列两组 D9/D10 类型表 | 各有一半。**上游的"精度→可用分盘矩阵"本仓没有**,但那是第三方 MIT 代码,需单独确认许可证 |
| **Ayanamsa / node mode 口径** | `UP` 全部 `request.get("ayanamsa","raman")` / `request.get("node_mode","true")`;R1「口径事实前置门」要求定案前核验代码默认/注册表/请求透传/引用口径四处一致 | `US:50-51` `AYANAMSA=DEFAULT_AYANAMSA_NAME`raman/ `NODE_MODE="mean"`,同样支持请求覆盖;`scoring_service.calculation_spec` 把 ayanamsa/nodeMode 写进输入合同哈希 | **口径默认不同:交点模式上游 `true`、本仓 `mean`。** 双方各自自洽,但跨仓对比任何数字前必须先对齐这一项,否则罗睺/计都最多差约 1.7°,足以翻宫 |
| **事件→技法映射** | `UP:55` 域→(分盘, 目标宫);另有 `birth_time_rectifier.py:22 EVENT_HOUSE_MAP`,每类事件带 `primary` / `secondary`**加一个 `karaka` 自然征象星**marriage→Venus、child_birth→Jupiter、career→Saturn、accident→Mars…)。**但 `EVENT_HOUSE_MAP` 没有接进上游评分引擎**,只是方法论模块 | `US:55` 域→(分盘, 目标宫)`scoring_service.py:26 _ENGINE_KIND_BY_NATIVE_KIND` 把 30 种 `event_kind` 映射到 8 个引擎域;`scoring_service.py:138 _KIND_SEMANTICS` 给每种 kind 一个方向(+1/0/−1)与强度,再乘 `_event_kind_factor`0.81.2);**无 karaka 项** | **本仓事件语义分层更细;双方都没把自然征象星接进评分。** karaka 是上游的参照数据,不是上游的能力 |
| **事件拟合率算法** | `references/birth-time-rectification-advanced.md` 方法1:吻合事件数/总事件数,>80% 准 / 6080% 微调 / <60% 大调;`birth_time_rectifier.py:90 calculate_confidence` = 匹配率 ×100,精度 +10,上升在边界 −15 | `refinement_packet.py:372 event_fit_rate` + `:406 dasha_agreement` + `:125 match_level`(按 rule_ids 分强/中/弱);`scoring_service.py:259 date_sensitivity` 给每个事件算 `winner_retention_rate``score_variance``active_rectification_event_engine.py:660 _leave_one_event_out` 留一诊断 | **本仓明显更强** |
| **候选生成** | `UP:90 _candidate_datetimes` 逐分钟,上限 1,440 | `api_service.py:74 _adaptive_minute_step`:窗宽 >360 分 → 10 分钟步长,>180 → 5,否则 2 | **本仓更实用**(上游一小时窗要算 61 次全盘) |
| **候选淘汰 / 并列** | `active_rectification_events.py:403 build_candidate_exclusion_table` + `:509 build_candidate_group_exclusion_table`:按与领先者的分差,>max(|leader|×0.12, 1.0) 标 `outside_public_rectification_retention_band`。**纯展示聚合,不改分** | `candidate_contrast.py:25 SIGNATURE_LAYERS=(d1,d9,d10,d24,d4,d12,md)` 做特征签名聚簇 → `:249 cap_clusters_by_adjacent_merge`(上限 64,超出按相邻弱簇合并,不按时间截断)→ `decision_policy.py:402 build_candidate_decisions``relative_support``RELATIVE_SUPPORT_MODE="proportional"``decision_policy.py:378`)→ 前端 `core/apply-probe-outcome.ts` 按答案做后验淘汰,`core/candidate-separation.ts:7 MIN_SEPARATION_LEAD=8` 判分离 | **本仓更强**(上游只有排序表,没有答案驱动的后验淘汰) |
| **置信度与确认门** | `rectification_technique_contract.py:8`:事件 <3 → `insufficient_events`,领域 <2 → `insufficient_domains`,高严谨 → `three_engine_parity_not_passed``can_narrow_to_minute` **硬编码 False** | `decision_policy.py:34-38``MIN_ACCEPTANCE_EVENTS=3``MIN_ACCEPTANCE_DOMAINS=2``MIN_DATE_QUALITY_MEAN=0.65``MIN_DIAGNOSTIC_RETENTION=0.75``MIN_ACCEPTANCE_MARGIN_PERCENT=10`;提出门/采用门/确认门三级分离(BUG-323/325 | **本仓更细**;两边都不批准唯一分钟 |
| **外部校验 / holdout** | `references/real_case_calibration/timing_rectification_candidate_holdout_labels_2026_07_23.json`(公开名人 + **negative windows**,脚本自注"未经两名评审批准前不是独立冻结标签");`timing_rectification_holdout_freeze_audit.py` | `references/real_case_calibration/minute_rectification_holdout_v3.json`20 例 Rodden-AA 封存 holdout`truth_hidden_from_ranker=true``frozen_before_replay=true`、带 `false_minute_offsets`+ `minute_rectification_development_v1.json` 3 例开发集;`scripts/rectification_prior_calibration.py` 做尺度合入门 | **本仓已冻结并真的跑过门;上游还停在待评审。**但本仓 holdout 有两个硬伤,见 §4.2 |
| **MEVG / 真实案例** | `references/birth-time-rectification-cases.md`:奥巴马、居里夫人、爱因斯坦、乔布斯、梦露五例,叙事级"验证结论",无可复跑数据 | 同上封存 holdout 可复跑 | 本仓更强 |
---
## 3. 本仓缺什么(按价值排序)
### 3.1 【第一优先 · 中等工作量】把已经在算的 KP 宫头子主接进评分(需产品推翻红线)
- **缺的是什么**:一条在 20 分钟窗口内会变 3–5 次的评分项。
- **上游怎么做**`scripts/active_rectification_event_engine.py:49``KP_SUB_WEIGHTS`)、`:259283``_score_event` 内的比对块)、`:368 _kp_house_sublords``:437``kp_layer` 请求开关,默认 False 以保持旧分逐字节不变)、`scripts/domain_calculation_service.py::compute_sidereal_placidus_cusps`。判据是:**事件发生时正在走的 Vim MD/AD/PD 主星,是不是该事件领域宫宫头的 KP 子主 / 次子主 / 星主**。commit `27cdc353` 附 9 个确定性测试。
- **本仓现状**`scripts/rectification/kp_cusp_observation.py:18` 文件头写死 display-only`scripts/active_rectification_event_engine.py:71 OBSERVATION_ONLY_LAYERS={"KP_cusps"}``scripts/rectification/decision_policy.py:39 POLICY_SKIPPED_LAYERS={"KP_cusps"}`。数据已经每分钟算好并存进 `feature_payload["indices"]``US:494520`kp1/4/7/10 的 `sub_index`),只是从不计分。**所以这是接线,不是实现。**
- **收益**:宫头子主在一个月宿(13°20′)内分 9 段不等长,最短 Ketu 段约 0.78° ≈ 3 分钟、最长 Venus 段约 2.2° ≈ 9 分钟。这是本仓目前**唯一**能在不跨上升星座的窗口内给出高频变化的整宫级判据。
- **诚实边界(必须写进任何任务书)**:
- 上游自己的复盘(`docs/research/rectification_process_v2_guardrails_2026_09_04.md` §5「遗留」)写着 **"② KP 权重标定"尚未做**,且接了 KP 之后他们那例的结果仍是「整窗零淘汰」。**上游没有证据证明这条能真的把候选拉开。**
- 本仓 BUG-325 的防复发条明确禁止。要做必须由产品负责人在任务书「决策记录」里显式推翻,并且只解冻到"进提出门前的排序",不解冻确认门。
- **收益未验证**:必须先在 `minute_rectification_holdout_v3` 上离线跑一遍(`scripts/rectification_prior_calibration.py` 的门:覆盖 ≥ 旧方案 −1 且中位宽度更窄),过门才上线。
- **工作量**:中。Python 侧约 80 行(引擎比对块 + 请求开关)+ 权重标定脚本 + holdout 复跑;不动前端。
### 3.2 【第一优先 · 小工作量】重新配平"窗口内恒定项"与"随分钟变化项"的权重
- **缺的是什么**:不是技法,是**权重比例**。这是本报告的新发现,此前 Bug 记录只到"分钟级≈随机"。
- **本仓现状(可算出来)**`scripts/active_rectification_event_engine.py:216246`,以一个 career 日精度事件为例,单事件满分拆开是——
- **窗口内恒定**(本命宫位按整宫制 `jyotish_engine.py::compute_chart_data``house=((si-asc_idx)%12)+1`,只在跨上升星座时才变;宫主、功能吉凶、Narayana 宫、Ashtakavarga、Shadbala、过运同理):`vim_md_domain_house` 2.0 + `vim_md_domain_lord` 2.0 + AD 1.5+1.5 + PD 0.75+0.75 + `narayana_md` 2.0 + `narayana_ad` 1.0 = **11.5**
- **随分钟变化**`points += weight / (2 * len(varga_charts))``:231`= 1.0 + 0.75 + 0.375 = **2.125**;外加 `dasha_transition_proximity` ≤1.0,以及事件恰好落在被平移的大运边界上时的主星翻转
- 比例约 **5 : 1**。这正好解释 BUG-570 记录的"底座 1115、事件差只有 45",和今天 `TASK-rectification-tiebreak-before-card-20260914.md` §1 抓到的 6 轮后 posterior 16/16/15/14/13。
- **改法(三选一或组合,都要过 holdout 门)**:
1. 分盘命中的除数 `2*len(varga_charts)` 改为 `len(varga_charts)`(分盘满命中从 1.0 提到 2.0,与 D1 宫位同权);
2. 或者给窗口恒定项统一乘一个 <1 的系数;
3. 或者在 `scoring_service.score_from_matrix` 出分后,按候选网格逐事件减去该事件在全窗口上的最小值(等价于 `decision_policy``offset` 尺度,但在**事件级**而不是**候选级**做,避免 BUG-560 里"整体拉尖"的过拟合)。
- **收益**:直接增大候选间方差,`relative_support` 不再被恒定底座稀释。**未验证,需离线实测**;但和 3.1 不同,这条不触碰任何产品红线,也不引入新技法,`ALGORITHM_VERSION` bump 即可。
- **工作量**:小(引擎 1–3 行 + 校准脚本复跑 + `ALGORITHM_VERSION` bump 与旧 Case 兼容处理)。
### 3.3 【第二优先 · 小工作量】年精度事件用"某一个月发生过"的边际似然,而不是 12 个月取平均
- **缺的是什么**`scripts/rectification/scoring_service.py:250`,年精度事件采样 12 个月(`sample_event_dates``:100`),然后 `"points": round(sum(points)/len(points), 4)` **取算术平均**
- **为什么这是问题**:用户说"2019 年换了工作",语义是"这 12 个月中的某一个月",不是"这 12 个月同时都在换工作"。取平均会把"某一候选分钟下 3 月恰好踩中 AD 换运"的信号摊薄成 1/12。而本仓真实会话里**年精度事件占大多数**(探针问的就是"哪一年")。
- **上游怎么做**`UP:78 _event_datetime` 对 year 精度直接取 7 月 1 日单点(更粗糙,不可借鉴),但上游 `PRECISION_WEIGHTS["year"]=0.5` 与本仓一致。**这条上游未涉及,是本仓自己的建模问题。**
- **改法**:把平均改为 log-sum-exp(软最大):`points = T * log(mean(exp(p_i / T)))`T 取 0.5–1.0。保留"不知道是哪个月"的不确定性,同时不把峰值抹平。不要直接取 max(会系统性抬分并过拟合)。
- **收益**:年精度事件重新获得分钟分辨率。**未验证,需在 holdout 上实测**。
- **工作量**:小(`scoring_service.py` 几行 + 测试 + holdout 复跑)。
### 3.4 【第三优先 · 中等工作量】把已经在算但从不计分的"细分钟层"接进评分
- **缺的是什么**`scripts/active_rectification_event_engine.py:383 _fine_minute_indices` 已经每分钟算出 `pada_index`(上升月宿四分位,约 3.3 分钟一变)、`bhava_sign_index``hora_sign_index``ghati_sign_index``pranapada_sign_index`(特殊上升,Ghati Lagna 约为本命上升 5 倍速)。这些**只进特征扫描和选题,不进任何分数**。
- **上游怎么做**:**上游未涉及**——上游引擎根本不算特殊上升(不 import `special_lagnas` / `saham_daynight`)。这是本仓自有资产没用起来。
- **本仓现状**`candidate_contrast.py:25 SIGNATURE_LAYERS` 只有 `d1,d9,d10,d24,d4,d12,md`,这些细层既不在签名里也不在分数里。(顺带:`md` = 月亮月宿序号,约 24 小时才变一次,在同日窗口内恒为常量,实际上是签名里的一个空位。)
- **收益**Hora/Ghati/Pranapada 上升在传统里确实用于校时收口(决策树 §5「第四层:细分钟收口层」)。但它们的判据是"哪个宫/哪个主星",和事件的绑定比 KP 宫头弱。**收益不确定,优先级低于 3.1–3.3**。
- **工作量**:中,且需要先确定判据(例如"Ghati Lagna 落在事件目标宫"),不能只把数值塞进分数。
### 3.5 【低优先 · 小】把自然征象星(karaka)加进域配置
- **上游怎么做**`scripts/birth_time_rectifier.py:22 EVENT_HOUSE_MAP`,每类事件带 `karaka`marriage→Venus、child_birth→Jupiter、career→Saturn、relocation→Rahu、accident→Mars、health_crisis→Saturn、windfall→Jupiter)。**注意:上游自己没把它接进评分引擎**,只是方法论模块的一张表。
- **本仓现状**`scripts/rectification/``active_rectification_*` 全文 grep `karaka` 零命中。
- **收益**:判据形如"运行主星 == 事件 karaka"或"karaka 落目标宫"。karaka 是行星身份,与上升无关 → **窗口内恒定,帮不上"候选分不开"**。只能提高单事件的判别强度(区分"这个事件是否真被激活"),不能拉开候选。
- **工作量**:小。但**别指望它解决第一痛点**。
### 3.6 【低优先】"精度 → 可用分盘"矩阵
- **上游怎么做**`references/open_source_sources/vedic-astro-skills/*/skills/vedic-rectifier/scripts/time_scan.py::ACCURACY_MATRIX` + `get_effective_accuracy`(声明精度 × 时间来源 → 有效精度 → 哪些分盘 enabled / warn / disabled)。
- **本仓现状**:有 `BIRTH_TIME_ACCURACY` 贯通与 `refinement_packet.py:560 precision_stage`,但没有"精度决定哪些分盘可信"的显式矩阵。
- **收益**:主要是诚实边界(报告里哪一层该标 `parameter_sensitive`),不是判别力。
- **许可证**:这是**第三方转载代码**,不在上游 MIT 覆盖范围内,**需单独确认许可证**才能借鉴实现;借鉴思路(而非代码)没有问题。
- **工作量**:小。
---
## 4. 可优化项(与上游无关,读本仓代码时发现)
### 4.1 打分结构:恒定项 / 变化项配比 —— 见 §3.2
单列在此提醒:这是本报告认为**优先级最高、且完全在本仓掌控内**的一条。BUG-560 的结论「引擎原始分在分钟级几乎没有区分力」是现象描述;本条给出了它的算术来源(11.5 : 2.1)。只改 `relative_support` 的归一尺度(offset/softmax)解决不了它,因为分子分母都被同一个恒定底座污染——BUG-560 实测 offset 覆盖只有 12/20,正是这个原因。
### 4.2 封存 holdout 本身欠力,导致"合入门"过严
`references/real_case_calibration/minute_rectification_holdout_v3.json` 实测:
- 20 例,**每例恰好 3 件事、2–3 个领域**,精度只有 `day``year` 两种,`candidate_radius_minutes` 全部为 10(即 ±10 分钟 / 21 个候选)。
- `"source_audit_status": "invalidated_after_replay"``source_audit_issues` 列了 2 处事件年份错误(`robbins_marriage_1968` 实为 1967-03-10`takamoto_joined_disney_1947` 实为 1945)。
问题:真实会话收集到 7–18 件事(今天的任务书里是 5 件,上游那例 18 件),而门禁基准只有 3 件。**用一个事件量只有产品实际水平 1/3、且自标 invalidated 的基准,去否决所有尺度与权重改动,是过严的。** BUG-560 的 "offset 覆盖 12/20" 很可能是样本欠力而非方案无效。
建议(不需要上游):
1. 修掉 2 条已确认的日期错误,把 `source_audit_status` 重新走一遍;
2. 补一个 `minute_rectification_holdout_v4`,每例 ≥7 件事、≥4 个领域、`candidate_radius_minutes` 覆盖 10 / 30 / 60 三档;
3. 在 v4 上重跑 `scripts/rectification_prior_calibration.py`,再判定 offset / softmax / §3.2 的权重改动是否过门。
工作量:中(主要是公开 Rodden-AA 案例的事件采集与两人复核,不是代码)。
### 4.3 `SIGNATURE_LAYERS` 与实际计分分盘不一致
`candidate_contrast.py:25` 的签名层是 `(d1, d9, d10, d24, d4, d12, md)`,但 `DOMAIN_CONFIG``active_rectification_event_engine.py:55`)实际计分的分盘还包括 **D5(教育)、D7/D3(六亲)、D2/D11(财务)、D30(健康)**
后果:两个分数不同的分钟(例如只有 D30 上升不同,健康事件因此得分不同)会被归进同一个签名簇,`select_signature_representatives``:287`)只留簇内最高分的一个代表,另一个分钟连同它携带的区分信息一起消失。反过来,`md`(月亮月宿)在同一天的窗口内恒定,占了一个无效位。
建议:签名层改为**按本次会话实际有证据的领域动态取用**(有财务事件就把 d2/d11 进签名,有健康事件就进 d30),并去掉同日窗口下恒定的 `md`。这会增加簇数,但增加的每一簇都是有证据支撑的真实分歧——正好可以喂给 §3.2 之后重新拉开的分数。
工作量:小到中。注意这会改变 `candidate_split_hash``candidate_contrast.py:199`)→ 旧 Case 的快照失效,须走 BUG-559 / BUG-580 那条"快照过期"的既有处理路径。
### 4.4 `_score_event` 的分盘命中除数掩盖了"多分盘一致"这一信号
`active_rectification_event_engine.py:231``points += weight / (2 * len(varga_charts))`。family 域配了 D12+D7+D3 三张盘,三张全命中得 `2.0/6 × 3 = 1.0`;career 域只有 D10,单张命中也得 `2.0/2 = 1.0`。也就是说**"三张分盘一致同意"和"一张分盘同意"拿到完全相同的分**。
传统上多分盘一致是更强的证据。建议改成"每张盘固定权重 + 一致性加成",而不是按盘数摊薄。同样需过 holdout 门。
### 4.5 交点模式默认值与上游不同,跨仓比数前必须对齐
本仓 `active_rectification_event_engine.py:51 NODE_MODE="mean"``scoring_service.calculation_spec``nodeMode` 默认 `"mean"`;上游 `request.get("node_mode","true")`。真交点与平交点最大相差约 1.7°,足以让罗睺/计都翻宫或翻分盘。**本身不是 bug**(各自自洽且都写进了输入合同哈希),但任何"上游算出来是 X 我们算出来是 Y"的对比,都必须先把这一项和 ayanamsa 一起对齐——上游 `docs/research/rectification_process_v2_guardrails_2026_09_04.md` 的 R1「口径事实前置门」讲的正是这个教训(他们为此作废了两轮定案)。
### 4.6 `block_scan` 之外仍有"按段长度偏置"的同型隐患
BUG-570 已修 `block_scan`(段内均值减全日最低分)。同型模式值得复查一遍:`decision_policy.py:341 _distribute_percent` 按簇代表分摊 100%,而簇的大小(`cluster_times` 长度)差异很大(`cap_clusters_by_adjacent_merge` 会把弱簇合并成宽簇)。当前用的是簇内**最高分**代表(`candidate_contrast.py:308 best = max(...)`),所以宽簇不会因为成员多而占优——**这一处是对的**。记录在此,避免将来重构时踩回去。
---
## 附:核验命令
```bash
git -C /workspace/yinduzhanxing log --oneline b9a0ef8f..92d3a47a | wc -l # 43
git -C /workspace/yinduzhanxing diff --name-only b9a0ef8f..92d3a47a | grep -iE 'rectif|birth.?time|minute'
git -C /workspace/yinduzhanxing log --oneline -S'KP_SUB_WEIGHTS' origin/codex/add-birth-time-rectification-skill -- scripts/active_rectification_event_engine.py # 27cdc353, 2026-09-04
git -C /workspace/Jyotisha show origin/staging:references/real_case_calibration/minute_rectification_holdout_v3.json | python3 -c "import json,sys;d=json.load(sys.stdin);print(d['source_audit_status'], len(d['cases']), sorted({len(c['events']) for c in d['cases']}))"
```
+2
View File
@@ -184,6 +184,8 @@
| `TASK-rectification-targeted-card-dead-20260913.md` | `PROGRESS-rectification-targeted-card-dead-20260913.md` | **P0**:定向补事卡在快照投影里拿不到 `choice_card`(承接焦点分支不重建 `choice_frame`),卡片看得见点不动、流程停在采集等待态;模型还会把定向题改写成口述题(BUG-669~671)。先于 tie-break 修复单执行 | 待验收 | `codex/rectification-targeted-card-dead-20260913` |
| `TASK-rectification-minute-resolution-research-20260914.md` | `PROGRESS-rectification-minute-resolution-research-20260914.md` | **研究单**:候选分不开的根因是打分尺度——窗口内恒定项 11.5 分 vs 随分钟变化项 2.125 分(≈5:1)。先修封存基准(v3 每例仅 3 件事且被标 invalidated)出 v4,再离线量五个改法:分盘除数、去底座、**KP 宫头子主计分(产品 09-14 拍板,推翻 BUG-325 一条红线)**、年精度事件改边际似然、聚类签名层对齐。有收益才立实现单 | 待执行 | `codex/rectification-minute-resolution-research-20260914` |
| `TASK-rectification-tiebreak-before-card-20260914.md` | `PROGRESS-rectification-tiebreak-before-card-20260914.md` | **P0**:点「再答两道参考题」服务端 ok 但界面无反应(`requestTieBreak` 的 `loadCaseSnapshot()` 不带合并回调,新 turn 不入对话区)(BUG-685);产品拍板放宽版 A——出交付卡前只要参考题可用且没用过就先问两道(不看分差),卡上收起按钮(BUG-686);交付文案列出用户已拒答的线(BUG-687) | 待验收 | `codex/rectification-tiebreak-before-card-20260914` |
| `TASK-rectification-tied-first-premature-delivery-fix-20260914.md` | `PROGRESS-rectification-tied-first-fix-20260914.md` | **P0 回归修复单**BUG-680 的 `tied_first` 早退被实现到 `coverageBlocks` 之前且无 `probe` 守卫 → 新案子答两题、区间还是整个开局窗口就宣布 `can_adopt`/代表分钟(BUG-683);交付态下仍出现死卡致 `delivered` 终态不触发、印「没有拿到下一个问题」(BUG-684 investigating | 待验收 | `codex/rectification-tied-first-fix-20260914` |
@@ -0,0 +1,101 @@
# 研究单 · 为什么候选分不开:打分尺度的分钟分辨率(2026-09-14)
- 基线:`origin/staging` @ `d97b9e9f`(含 BUG-685/686/687 的实现 `7f28bfec` 与风格题前置 `d97b9e9f`)。
- 分支:`codex/rectification-minute-resolution-research-20260914`worktree `.worktrees/rectification-minute-resolution-research-20260914`
- 性质:**离线测量,不改线上行为。** 除任务 0(修基准数据)外,任何尺度改动都必须先量出收益才另立实现单。
- 来源:2026-09-14 与上游 `/workspace/yinduzhanxing` 的能力对照(subagent 报告存档 `docs/research/upstream_rectification_gap_2026_09_14.md`,执行方开工时把 scratchpad 那份 195 行报告落盘到这个路径)。
## 1. 问题
真机连续多轮出现"带年月的题问完、候选仍然并列":最近一次 6 轮后 posterior 是 16 / 16 / 15 / 14 / 13,交付卡给出 26% / 26% / 20%,用户只能蒙。
**这不是题问得不够,是打分对分钟不敏感。** `scripts/active_rectification_event_engine.py:216246`,一个日精度事业事件的分数拆成两类:
| 类别 | 上限 | 在 20 分钟窗内是否变化 |
| --- | --- | --- |
| 本命宫位(整宫制)、宫主、功能吉凶、Narayana、Ashtakavarga、Shadbala、过运 | **11.5** | 基本不变(只在跨上升星座时变) |
| 分盘命中 `points += weight / (2 * len(varga_charts))` | **2.125** | 每分钟都在变 |
**5 : 1**。每答一题,九个候选拿到的分里约八成是"人人有份"的底座,真正区分分钟的只有一两分。BUG-570 记的"底座 1115、事件差 4–5"是同一件事。**再加十道题,比例不变,仍然分不开。**
同时,用来判断"改动有没有收益"的封存基准本身欠力:`references/real_case_calibration/minute_rectification_holdout_v3.json` 每例**恰好 3 件事**、半径 ±10 分钟,自带 `source_audit_status: invalidated_after_replay`(两处日期错)。真实会话是 5–18 件事。**用它否决尺度改动是过严的**,BUG-560 当时记的「offset 覆盖 12/20」很可能是样本欠力而非改法无效。
上游对照结论(已核):`b9a0ef8f..92d3a47a` 43 个提交里生时校正**零改动**,没有新技法可抄;上游自己 09-04 的复盘也承认接了 KP、18 件事 5 领域之后仍「整窗零淘汰」。**这条路得我们自己走。**
## 2. 决策记录
| 决策 | 内容 |
| --- | --- |
| D1 | **KP 宫头子主参与评分**(产品负责人 2026-09-14 拍板)。这**推翻 BUG-325 防复发条里的「不得把 KP 观察计分」**——该条写于 2026-08-20,当时的理由是 KP 快照刚做出来、未经标定。现在的理由是:KP 宫头子主是 20 分钟窗内唯一变化 3–5 次的整宫级判据,数据本仓已经每分钟在算(`scripts/rectification/kp_cusp_observation.py`),只被 `active_rectification_event_engine.py:71``OBSERVATION_ONLY_LAYERS` 挡在评分外。**方向已定,本研究单只负责标定权重与验证收益,不负责"要不要做"。** 执行方不得以 BUG-325 为由拒改;但也不得在没有测量结果的情况下直接改线上默认权重。 |
| D2 | **不得为了提高命中率放宽置信度或确认门控**`AGENTS.md` §8)。所有改法只动打分尺度,不动 `confirmation_allowed` / `acceptance_allowed` / 并列判据。 |
| D3 | **不得硬编码对齐特定答案。** 上游 `scripts/ashtakavarga.py``PL9_BAV_CELL_OVERRIDES`(为对齐某份 PDF 覆写特定行星/星座的 bindu)是反面样板,本仓不采用这种做法。 |
| D4 | **口径前置**:本仓交点模式默认 `mean`、上游默认 `true`(最大差 1.7°,足以翻宫)。本单所有测量在**本仓口径**下进行,结果文档首行写明 ayanamsa 与 node mode,不得与上游数字直接对比。 |
| D5 | 任务 0(修基准)是唯一允许落盘改数据的部分,且只改 `references/real_case_calibration/**` 与研究脚本,不碰线上评分代码。 |
## 3. 任务 0 · 先把基准修好(前置,必做)
没有可信基准,后面全部测量都无法判读。
-`minute_rectification_holdout_v3.json` 的两处日期错,重跑 `source_audit`,把 `source_audit_status` 恢复成有效或明确注明每例的来源与精度。
- 产出 **v4**`references/real_case_calibration/minute_rectification_holdout_v4.json`
- 每例 **≥ 7 件带年月事件**、**≥ 4 个领域**(对齐真实会话,而不是 3 件);
- 出生时间来源为公开 AA 级;**不得使用真实用户资料**(`AGENTS.md` §8);
- 三档搜索半径:**±10 / ±30 / ±60 分钟**,分别记录,用来看改法在宽窗和窄窗上的表现是否一致;
- 每例标注真实分钟所在簇,供命中率统计。
- 交付:数据文件 + `docs/research/holdout_v4_build_2026_09_14.md`(来源、标注协议、与 v3 的差异、为什么 v3 不足以做判据)。
- 验收:v4 上重跑当前线上算法,给出**基线成绩单**(下面五个指标),这份成绩单是后续所有改法的对照。
## 4. 任务 1 · 要量的五个改法
在 v4 上逐项单独测量、再测两两组合。**统一指标(五个)**:
1. **真实分钟命中率**:真实分钟落在头名簇的比例;
2. **真实分钟落在交付区间内的比例**(不得为了收窄把真值挤出去);
3. **交付区间宽度**(分钟)中位数;
4. **并列率**:前两名 posterior 分差 = 0 的案例占比(当前痛点的直接度量);
5. **每轮熵下降**:答完第 N 题后的候选熵,看收敛速度。
| 编号 | 改法 | 改哪里 |
| --- | --- | --- |
| **R1** | 分盘项除数调整:`weight / (2 * len(varga_charts))` 的除数取 `2 * len` / `len` / `sqrt(len)` / 固定 2 四档 | `active_rectification_event_engine.py:231` |
| **R2** | **去底座**:每个事件的分数减去该事件在**当前窗口所有候选上的最小值**,只保留差异部分 | 同文件,事件分汇总处 |
| **R3** | **KP 宫头子主计分**D1 已拍板):把 `KP_cusps` 移出 `OBSERVATION_ONLY_LAYERS`,按 kp1/4/7/10 与事件领域的对应关系给权重,权重取 0.5 / 1.0 / 2.0 三档 | `active_rectification_event_engine.py:71``scripts/rectification/kp_cusp_observation.py` |
| **R4** | **年精度事件改边际似然**:现在对 12 个月取算术平均,把"某一个月正好踩中换运"摊薄成 1/12;改为对月取 max 或对数边际似然 | `scripts/rectification/scoring_service.py:250` 一带 |
| **R5** | **聚类签名层与计分层对齐**`candidate_contrast.py:25``SIGNATURE_LAYERS` 只有 d1/d9/d10/d24/d4/d12/md,实际计分还用 D5/D7/D3/D2/D11/D30 → 分数不同的分钟被并进同一簇丢掉;`md`(月宿)在同日窗口内恒定,占空位。改为按本次有证据的领域动态取签名层 | `candidate_contrast.py:25` |
补充要求:
- 每个改法都要报告**副作用**:真值被挤出区间的案例数、区间过窄的案例数、某一档半径上退化的案例数。
- R3 额外要报告:KP 在各例 20 分钟窗内实际变化几次;若某例窗内不变,该例不计入 R3 的收益统计(避免用无关样本稀释)。
- R2 要注意与 `decision_policy.py:341` 的按簇分摊交互(那里已用簇内最高分代表,不存在 BUG-570 的同型偏置,改动不得把它破坏)。
## 5. 交付
- `scripts/research/minute_resolution_sweep.py`(新,只读线上模块,不改默认行为;参数化跑五个改法与组合)。
- `docs/research/minute_resolution_2026_09_14.md` + 同名 `.json`:基线成绩单 + 每个改法在三档半径上的五个指标 + 副作用统计 + 口径声明(D4)。
- 结论只允许三种:**有收益**(命中率与区间覆盖率不降、并列率下降、区间宽度中位数下降)→ 立实现单并给推荐参数;**无收益** → 关闭并写明;**不确定** → 说明还缺什么数据或样本量。
- 不得把研究脚本接进生产路径;不得改 `active_rectification_event_engine.py` / `scoring_service.py` / `candidate_contrast.py` 的线上默认值。
## 6. 硬红线
1. Python 改动跑 `.venv/bin/python scripts/run_quality_gate.py --profile quick`;改到哪个模块就跑对应 `tests/test_*.py`
2. 不得使用真实用户出生资料、姓名、邮箱;样本只用公开名人或明确虚构数据。
3. 不得放宽置信度、确认门控或并列判据(D2)。
4. 不得为对齐某个期望答案硬编码覆盖(D3)。
5. 研究结论不得写成"感觉更好";每条都要落到五个指标上的数字。
## 7. 开工前置命令
```bash
git fetch origin --prune
git worktree add -b codex/rectification-minute-resolution-research-20260914 \
.worktrees/rectification-minute-resolution-research-20260914 origin/staging
cd .worktrees/rectification-minute-resolution-research-20260914
python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45
```
开工前读:`docs/research/upstream_rectification_gap_2026_09_14.md`(对照报告)、`docs/BUG_HISTORY.md` 的 BUG-325(KP 红线,本单 D1 推翻其中一条)、BUG-560holdout 否决记录)、BUG-570(底座与事件差)。
## 8. BUG 编号
- 本单是研究单,**不新增 BUG 编号**。测量后若立实现单,届时按 `docs/BUG_HISTORY.md` 当时的最大号顺延。