Compare commits

...
Author SHA1 Message Date
Jesse_ChenandClaude 172178cdbd Merge origin/staging into D60 study (issue #149)
Independent Staging Quality Gate / validate (push) Successful in 20m20s
Independent Staging Quality Gate / publish (push) Successful in 4m21s
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
2026-10-29 16:44:50 +08:00
jesse-uxandGrok (agent loop) 3bc82acba6 research(d60): ship the G2/G5 script and report per-switch flips (issue #149)
The G2 precheck and the G5 noise floor had only a results file; the script
that produces them is now in scripts/research/d60_two_way_g2_g5.py, with
a test that reproduces the committed JSON byte for byte.

G5 is now reported per switch, with the ayanamsa offset in arcminutes.
Against the Raman baseline all three alternatives flip 77/77. Between the
alternatives themselves the number follows the offset: Lahiri to KP 21/77
(27.3%, 5.81'), KP to True Chitra 19/77 (24.7%, 5.02'), Lahiri to True
Chitra 2/77 (2.6%, 0.83'). The report says so and no longer claims that
any frame change flips every chart; the registered gate is baseline
relative and still triggers.

The report also states that G2's "not evaluable" comes from the registered
same-day answer policy, not from a measurement that D60 does not help.

Co-Authored-By: Grok (agent loop)
2026-10-29 16:32:54 +08:00
Jesse_ChenandClaude 09620c6e0a docs(tasks): D60 study second half, first rejection (agent loop, issue #149)
The G2-G5 results came without the script that produced them, so G5's
77/77 ayanamsa flip cannot be replayed. Commit the script, report G5 per
alternative ayanamsa, and say that G2's zero questions came from the
same-day scoring rule the planner chose.

Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
2026-10-29 16:14:25 +08:00
jesse-uxandGrok (agent loop) 028992257b research(d60): G2 not evaluable, G5 trips the noise floor (BUG-1497, issue #149)
The registered same-day answer policy needs an event dated on the birth day;
the v5 holdout has none in any of the 77 cases, so group B adds no question
and is identical to group A. G2 is therefore not evaluable by construction,
not a measured zero, and no placebo test has a lift to check.

G5 is measurable and decisive: switching the ayanamsa from Raman to Lahiri,
KP or True Chitra changes the ascendant D60 sign in 77 of 77 cases (100%,
threshold 20%). Under the registered stop rule any minute-level wording is
forbidden.

Recommendation: do not adopt. D60 stays reference-only and the external copy
does not claim seconds. BUG-1497 is closed_by_design; the mapping fix itself
is BUG-1500 and already merged.

Co-Authored-By: Grok (agent loop)
2026-10-29 15:48:08 +08:00
jesse-ux c163a74934 research(d60): preregister gates G2-G5 before scoring (issue #149)
Registered rules, thresholds, seeds and the same-day answer policy for the
D60 boundary probes. No scoring has run with this file in place.
2026-10-29 15:46:58 +08:00
Jesse_ChenandClaude 0b1bcf7e4d docs(testing): D60 mapping fix device checklist (issue #149)
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
2026-10-29 15:45:05 +08:00
jesse-uxandGrok (agent loop) 129313e175 fix(varga): count D60 from the sign itself for every sign (BUG-1500, issue #149)
Independent Staging Quality Gate / validate (push) Successful in 20m59s
Independent Staging Quality Gate / publish (push) Successful in 4m25s
The production D60 branch added one sign to 1-based even signs, with no
source, while the repository's own guide and the vedastro mapping count
from the sign itself. PyJHora agrees with the latter: 33/77 recorded times
before, 77/77 after.

- scripts/varga.py: D60 is (si+pi)%12 for odd and even signs; other
  mappings and the vedastro mode are untouched.
- tests/test_d60_varga_mapping.py: 12 signs x 60 parts against
  PyJHora, plus the even-sign first part.
- scripts/research/d60_two_way_run.py: the G1 reconciliation that found
  this, now in the repository with a test; G1 passes 77/77.
- scripts/varga.py is part of the extended frozen identity, so the sealed
  holdout and the reported-offset sweep were re-frozen per ERR-110. All
  20 and 900 trials match the upstream_sync9b records on every field and
  the metrics and summary are unchanged.

Co-Authored-By: Grok (agent loop)
2026-10-29 14:30:57 +08:00
jesse-ux a21c9ec163 merge: bring staging into the D60 research branch (issue #149) 2026-10-29 13:33:42 +08:00
Jesse_ChenandClaude 124ff8e0ba docs(tasks): D60 mapping fix brief, option 1 (agent loop, issue #149)
Product chose 1: fix production D60 (count from the sign itself for odd
and even signs) before continuing the two-way study. Renumber the
branch's D60 bug BUG-1498 -> BUG-1500 to clear the staging collision,
and settle the D60 boundary scoring rule as same-day events only.

Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
2026-10-29 13:21:49 +08:00
jesse-ux 98be2649ac research(d60): G1 stops on a production mapping mismatch (BUG-1497, BUG-1498, issue #149)
The D60 ascendant of the production classical_local mapping agrees with
PyJHora on 33 of 77 recorded times (42.9%). All 44 mismatches are 1-based
even signs and differ by exactly one sign; the repository's own vedastro
mode agrees with PyJHora on 77 of 77.

So G1 fails the 95% gate, but the cause is the production mapping rule in
scripts/varga.py, not a missing D60 signal. BUG-1498 records the
inconsistency as investigating. G2-G5 did not run and no scoring rule was
registered.

jyotishganit is not installed here and VedAstro was not called, so the
reconciliation is single-engine and says so.
2026-10-28 20:02:43 +08:00
jesse-ux 3bbf58e984 docs(d60): register BUG-1497 and record the two-way pre-work (issue #149)
Environment checks are done: swisseph 2.10.03, PyJHora importable with a
shashtyamsa chart, the v5 holdout present, and the four baseline test
files green (98 passed). jyotishganit is not installed, so G1 ends up with
PyJHora as the only external engine.

The B-group scoring rule cannot be implemented as written: the six-question
replay answers date-level boundary questions, while a D60 change happens
every couple of minutes inside one day. Two workable options are recorded
in PROGRESS and posted to the issue; nothing is scored before the rule is
preregistered.
2026-10-28 19:00:54 +08:00
27 changed files with 48646 additions and 144 deletions
+7
View File
@@ -1,5 +1,12 @@
# 印度占星 Skill 更新日志
## 2026-10-29 — D60 分盘的星座算法改对
- 落在金牛、巨蟹、处女、天蝎、摩羯、双鱼上的行星或上升,D60 星座改为从本星座起算(以前多移一个星座);同一张盘的 D60 星座可能与以前不同。
- 与外部参照(PyJHora)在 77 例已知出生时间上 77/77 一致;以前只有 33/77。
- 生时校正 20 条密封案例与 900 个报时窗口,名次与分钟误差与上一份回放逐条相同。
- Skill 版本不变(BUG-1500,issue #149)。
## 2026-10-29 — 咨询首字前少等最多 3 秒
- 判断「是不是寒暄」改为和扣点、记下问题同时进行,不再排在它们后面;真问题首字前最多快约 3 秒。
+37 -6
View File
@@ -14081,7 +14081,7 @@
- 防复发:待定。改闸门时,同时用同年、跨年、列表错位三类虚构配对做回归。
- 相关记录:BUG-689、BUG-740、BUG-1047;ERR-110。
- 复发自:无。
- 修复版本:未修。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
## BUG-1049 | 生时校正开场没有例子、满是行话,用户不知道该答什么
@@ -18773,7 +18773,7 @@
- 防复发:在这项真正交付之前,不得把「少数一侧不足两成仍不出题」写成已经生效。
- 相关记录:BUG-1367。
- 复发自:无。
- 修复版本:未修。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
## BUG-1369 | 进入交付区间仍要落后峰值 8 分
@@ -18788,7 +18788,7 @@
- 防复发:不得只改写盘或只改读盘。不得用修改 `MIN_SEPARATION_LEAD` 来收窄区间。
- 相关记录:BUG-423、BUG-560、BUG-1367。
- 复发自:无。
- 修复版本:未修。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
## BUG-1392 | 分段显示用取整分数,还会跳过缺区间的活候选
@@ -19174,7 +19174,7 @@
- 防复发:以后要固定顺序时,遍历前排序,并加不依赖哈希种子的回归。不要在本条未修之前把中文逐字节对比做成不设种子的门禁。
- 相关记录:BUG-1413。issue #89 修复单顺手记下。
- 复发自:无。
- 修复版本:未修。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
## BUG-1416 | 中文完整数据附录由英文回译,Dosha 丢否定,友敌矩阵空表
@@ -19931,7 +19931,7 @@
- 防复发:待修复单补测试(与 Swiss Ephemeris 日出对比,误差 ≤ 2 分钟)。
- 相关记录:issue #114。
- 复发自:无
- 修复版本:未修。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
## BUG-1463 | 单独调 `/api/shadbala` 带出生资料时 500
@@ -19947,7 +19947,7 @@
- 防复发:待修复单补接口测试。
- 相关记录:issue #114。
- 复发自:无
- 修复版本:未修。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
## BUG-1464 | 存过别人的账户进首页即「页面出错了」
@@ -20448,6 +20448,7 @@
- 复发自:无。
- 修复版本:分支 `codex/upstream-sync9b-20261028`。
## BUG-1496 | 生时校正复述把日期说了两遍(「2016-09 2016 年 9 月上大学」)
- 状态:resolved(代码 + 回归测试;待部署后 staging 复测)
@@ -20462,6 +20463,20 @@
- 关联:BUG-1136。
- 复发自:无。
- 修复版本:分支 `codex/rectification-recap-date-dup-20261028`。
## BUG-1497 | D60 换格能不能帮生时校正,从没在已知出生时间的人身上测过
- 状态:closed_by_design(设计上不做;D60 维持「只作参考」)
- 首次发现 / 最近更新:2026-10-28 / 2026-10-29(issue #149,来源 #142 竞品宣传)
- 影响面:生时校正的技法路由与对外文案。`skills/jyotish-birth-time-rectification/references/technique-routing.md` 现在写「D60 只作参考,不驱动结论」。
- 现象:竞品宣传「证据够密时 D60 与纳迪分盘反向校准,收束时刻可以到秒」。纳迪那一半已在 BUG-1240 证伪(N3 ±10 窗口找回记录分钟 5/77,生产 25/77;N4 只换岁差 73/73 换段);D60 这一半从未在 v5 77 例已知出生时间上检验。
- 触发条件:用 D60 换格给候选分段打分,或对外宣称「到秒」。
- 根因:未验证的技法被当成能力宣传;我方没有 D60 换格的评分实现,也没有对照实验。
- 结论(研究单已做完):G1 77/77 通过(BUG-1500 修好映射之后)。G2 按先登记口径**不可评估**:D60 换格题只认同日事件,v5 的 77 例里出生当天事件 0 件,B 组加不上任何判据、与 A 组相同。G3 平凡成立;G4 不适用。G5 触发上限:只换岁差(raman→lahiri / kp / true_citra),D60 上升格 77/77 全变(100%,阈值 20%)。因此**不做**:D60 不进校正判据,技法路由与文案不改;对外不出现「到秒 / 分钟级精确」,与 BUG-1240 同一口径。
- 验证:报告 `docs/research/rectification_d60_two_way_2026_10_29.md`;结果 `docs/research/d60_two_way_results_2026_10_29.json`(G1)与 `docs/research/d60_two_way_g2_g5_results_2026_10_29.json`(G2 预检与 G5),分别由 `scripts/research/d60_two_way_run.py` 与 `scripts/research/d60_two_way_g2_g5.py` 生成,可逐字节复跑;先登记 `docs/research/d60_two_way_preregistration_2026_10_28.json`。
- 防复发:研究单写死「先登记再跑、真值不可见、必须有安慰剂、负结果照写」。
- 关联:BUG-1240、BUG-560、BUG-1090、BUG-1091。
- 复发自:无。
- 修复版本:无(closed_by_design;研究分支 `codex/rectification-d60-two-way-20261028`)。
## BUG-1498 | staging 门禁 Python 快速门失败:`test_daily_starlanguage_does_not_eat_yesterday_cache` 网关调用 0 次
@@ -20493,3 +20508,19 @@
- 关联:BUG-976(寒暄先扣后退)、BUG-1074(开流前的串行链)、#134(同批提速)。
- 复发自:无
- 修复版本:分支 `codex/consult-classify-parallel-20261029`。
## BUG-1500 | 生产 D60 映射把 1-based 偶数星座整体后移一个星座
- 状态:resolved(代码 + 回归测试;待部署)
- 首次发现 / 最近更新:2026-10-28 / 2026-10-28(issue #149,G1 三引擎对账)
- 影响面:`scripts/varga.py::varga_map` 的 D60 分支(生产默认 `classical_local` 模式)。技法路由目前写「D60 只作参考」,不进校正打分。
- 现象:v5 的 77 例已知出生时间里,生产 D60 上升星座与 PyJHora(traditional Parasara,from sign)只一致 33 例;其余 44 例全部差 +1 个星座,且 44 例全是 1-based 偶数星座(金牛、巨蟹、处女、天蝎、摩羯、双鱼)。本仓 `mode='vedastro'` 的 D60 映射与 PyJHora 77/77 一致。
- 触发条件:读取生产 D60(`calc_varga(lon, 60)` 默认模式)。
- 根因:`varga_map` 的 D60 分支是 `(si+pi)%12 if o else (si+1+pi)%12`(`o` 为 1-based 奇数星座),对 1-based 偶数星座加 1;同文件 vedastro 映射是 `(si+pi)%12`。两套内部映射不一致,外部引擎与 vedastro 那套一致。哪一套符合来源尚未裁决,不预设 classical 就是错。
- 修复:`varga_map` 的 D60 分支改为 `(si+pi)%12`,奇偶星座都从本星座起算,并加注释指向 `references/shodasavarga-complete-guide.md` 与 PyJHora 对账(BUG-1500)。vedastro 模式与其他分盘未动。
- 验证:新增 `tests/test_d60_varga_mapping.py`(12 个星座 × 60 段逐段对 PyJHora;偶数星座第 1 段落在本星座)。G1 脚本 `scripts/research/d60_two_way_run.py` 重跑 77/77 一致(`docs/research/d60_two_way_results_2026_10_29.json`)。密封校正 20 条与报时窗口 900 条与 sync9b 记录逐条相同,按 ERR-110 重新冻结为 `d60_mapping_2026_10_29`。`tests/test_varga_bphs.py`、`tests/test_upstream_sync9b_varga_bphs.py`、`tests/test_deep_varga_avastha.py`、`tests/test_divisional_charts_extended.py`、`tests/test_cli_smoke.py` 通过;`tests/test_d1_d60_varga_mapping_registry.py` 依赖的 `python3` 在本机不存在,属环境缺口。
- 防复发:`tests/test_d60_varga_mapping.py` 锁定「从本星座起算」;classical 与 vedastro 现在同一条规则,外部引擎对账留作回归。
- 关联:BUG-1497。
- 复发自:无。
- 修复版本:分支 `codex/rectification-d60-two-way-20261028`。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,78 @@
{
"scope": "d60_two_way_preregistration",
"task": "docs/tasks/TASK-rectification-d60-two-way-20261028.md",
"fix_brief": "docs/tasks/TASK-rectification-d60-fix-20261029.md",
"issue": 149,
"bug": "BUG-1497",
"branch": "codex/rectification-d60-two-way-20261028",
"base_sha": "129313e1759026d6c0afdc27ea2905da2915992a",
"dataset": {
"path": "references/real_case_calibration/minute_rectification_holdout_v5.json",
"sha256": "ab365a3e3f4953d4b538f2c0889dc98ab89444a28340c3a7b29e2a864cdd687a",
"cases": 77,
"events": 964
},
"profile": {
"ayanamsa": "raman",
"node_mode": "mean",
"minute_step": 2,
"radii_minutes": [
10,
30,
60
],
"bootstrap_resamples": 5000,
"permutation_resamples": 9999,
"seed": 20261028,
"hash_seed": 0
},
"group_a": {
"definition": "production V9 six-question replay, protocol identical to the v5 baseline (cluster_width_probe replay_public).",
"source": "scripts/research/cluster_width_probe.py::replay_public"
},
"group_b": {
"rule_id": "d60_same_day_boundary_probe_v1",
"boundaries": "every ascendant D60 sign change inside the +/-radius window on the 2-minute candidate grid (raman, mean node, production mapping).",
"probe": "one 'was the event before or after this boundary' question per boundary, answered and applied with the same apply_answer machinery as group A.",
"answer_policy": "answer only when an event date equals the boundary date; otherwise the probe is skipped and no candidate is eliminated.",
"reason": "a date-only event on another day would answer every boundary on the birth day the same way (always after), which eliminates one side of the window without evidence.",
"required_precheck": "count, per case, events whose date equals the birth date before scoring; if every case has zero, G2/G3/G4 are reported as not evaluable by construction, not as a measured zero."
},
"gates": {
"G1": {
"status": "passed",
"evidence": "docs/research/d60_two_way_results_2026_10_29.json (77/77 after BUG-1500)",
"threshold": ">=0.95 agreement with one external engine"
},
"G2": {
"metric": "share of cases where the six-question replay head is within 2 minutes of the recorded minute",
"statistic": "B minus A, case bootstrap 5000 resamples, one-sided lower bound",
"pass": "lower bound > 0",
"seed": 20261028
},
"G3": {
"metric": "cases whose recorded minute stays inside the delivered range",
"pass": "B >= A (A baseline 76/77 at +/-10)"
},
"G4": {
"placebos": [
"P1: day-precision events shifted by +/-30-180 days",
"P2: day-precision dates swapped across cases"
],
"statistic": "one-sided permutation 9999 resamples of the B-minus-A lift",
"pass": "p < 0.05 against both placebos"
},
"G5": {
"metric": "share of cases where the ascendant D60 sign at the recorded time changes when the ayanamsa is switched raman -> lahiri / kp / true_citra",
"pass": "any switch above 0.20 forbids 'to the second / minute-level precision' wording even if G2-G4 pass"
}
},
"stop_rules": [
"no scoring before this file is committed",
"G1 failing stops G2-G5",
"G2 or G3 failing ends the question as 'do not adopt'",
"no threshold or seed changes after seeing results; any post-hoc number is reported in a separate post-hoc section and cannot change a gate",
"production code, skill routing and external wording stay unchanged in this round"
],
"post_hoc_policy": "any analysis not in this file is labelled post_hoc and cannot change a gate verdict"
}
@@ -0,0 +1,833 @@
{
"task": "docs/tasks/TASK-rectification-d60-two-way-20261028.md",
"issue": 149,
"bug": "BUG-1497",
"gate": "G1 three-engine D60 reconciliation",
"generated_at_utc": "2026-10-28T12:02:20.260551+00:00",
"dataset": {
"path": "references/real_case_calibration/minute_rectification_holdout_v5.json",
"sha256": "ab365a3e3f4953d4b538f2c0889dc98ab89444a28340c3a7b29e2a864cdd687a",
"cases": 77
},
"profile": {
"ayanamsa": "raman",
"node_mode": "mean",
"house_system": "production compute_chart_data",
"pyjhora_ayanamsa_mode": "Raman",
"pyjhora_chart_method": 1
},
"engines": {
"own_classical_local": "varga.calc_varga(lon, 60) (production default)",
"own_vedastro_mode": "varga.calc_varga(lon, 60, mode='vedastro') (VEDASTRO_RAW_VERIFIED_DIVISIONS includes 60)",
"pyjhora": "jhora.horoscope.chart.charts.divisional_chart(jd, place, divisional_chart_factor=60), Lagna entry",
"jyotishganit": "blocked: not installed in this environment",
"vedastro": "blocked: no live call made in this run"
},
"result": {
"cases": 77,
"classical_matches": 33,
"classical_rate": 0.4286,
"vedastro_matches": 77,
"vedastro_rate": 1.0,
"mismatch_delta_histogram": {
"0": 33,
"1": 44,
"2": 0,
"3": 0,
"4": 0,
"5": 0,
"6": 0,
"7": 0,
"8": 0,
"9": 0,
"10": 0,
"11": 0
},
"mismatches_by_asc_sign_parity": {
"odd_1based": {
"cases": 33,
"matches": 33
},
"even_1based": {
"cases": 44,
"matches": 0
}
},
"gate_passed": false,
"gate_threshold": ">=95% agreement with at least one external engine",
"stop_rule": "G1 failing stops G2-G5 per the brief"
},
"finding": "The production classical D60 mapping shifts every 1-based even sign by one sign relative to PyJHora; the repository's own vedastro-mode D60 mapping agrees with PyJHora on all 77 cases. No scoring gate was run.",
"instances": [
{
"case_id": "albert_brooks_1947_aa_v4_holdout",
"asc_sign_idx": 2,
"ascendant_longitude": 71.1909,
"d60_classical": 0,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "andrew_windsor_1960_aa_v4_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 109.6959,
"d60_classical": 7,
"d60_vedastro_mode": 6,
"d60_pyjhora_method1": 6,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "angelina_jolie_1975_aa_v4_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 96.8001,
"d60_classical": 5,
"d60_vedastro_mode": 4,
"d60_pyjhora_method1": 4,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "barack_obama_1961_aa_v4_holdout",
"asc_sign_idx": 9,
"ascendant_longitude": 296.1798,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "bernd_eichinger_1949_aa_v4_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 107.0009,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "chad_everett_1937_aa_v4_holdout",
"asc_sign_idx": 8,
"ascendant_longitude": 269.6959,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "elizabeth_montgomery_1933_aa_v4_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 162.7012,
"d60_classical": 7,
"d60_vedastro_mode": 6,
"d60_pyjhora_method1": 6,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "elizabeth_taylor_1932_aa_v4_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 231.7983,
"d60_classical": 3,
"d60_vedastro_mode": 2,
"d60_pyjhora_method1": 2,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "iwao_takamoto_1925_aa_v4_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 216.2833,
"d60_classical": 8,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "john_robbins_1947_aa_v4_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 149.6725,
"d60_classical": 3,
"d60_vedastro_mode": 3,
"d60_pyjhora_method1": 3,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "joseph_kennedy_iii_1980_aa_v4_holdout",
"asc_sign_idx": 1,
"ascendant_longitude": 59.9029,
"d60_classical": 1,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "kurt_cobain_1967_aa_v4_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 151.3987,
"d60_classical": 8,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "pablo_picasso_1881_aa_v4_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 104.8722,
"d60_classical": 9,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "paul_ryan_1970_aa_v4_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 218.6428,
"d60_classical": 1,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "salma_hayek_1966_aa_v4_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 145.4799,
"d60_classical": 6,
"d60_vedastro_mode": 6,
"d60_pyjhora_method1": 6,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "sean_lennon_1975_aa_v4_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 113.2594,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "sigmund_freud_1856_aa_v4_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 199.7737,
"d60_classical": 9,
"d60_vedastro_mode": 9,
"d60_pyjhora_method1": 9,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "steve_reich_1936_aa_v4_holdout",
"asc_sign_idx": 0,
"ascendant_longitude": 9.9031,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "tiger_woods_1975_aa_v4_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 152.3435,
"d60_classical": 10,
"d60_vedastro_mode": 9,
"d60_pyjhora_method1": 9,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "tom_kennedy_1927_aa_v4_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 135.3649,
"d60_classical": 10,
"d60_vedastro_mode": 10,
"d60_pyjhora_method1": 10,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "adriana_lima_1981_aa_v5_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 234.5927,
"d60_classical": 9,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "agatha_christie_1890_aa_v5_holdout",
"asc_sign_idx": 8,
"ascendant_longitude": 242.6992,
"d60_classical": 1,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "albert_einstein_1879_aa_v5_holdout",
"asc_sign_idx": 2,
"ascendant_longitude": 80.9181,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "alberto_fujimori_1938_aa_v5_holdout",
"asc_sign_idx": 1,
"ascendant_longitude": 30.0607,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "arthur_conan_doyle_1859_aa_v5_holdout",
"asc_sign_idx": 1,
"ascendant_longitude": 59.3382,
"d60_classical": 0,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "audrey_hepburn_1929_aa_v5_holdout",
"asc_sign_idx": 10,
"ascendant_longitude": 307.1967,
"d60_classical": 0,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "ayrton_senna_1960_aa_v5_holdout",
"asc_sign_idx": 9,
"ascendant_longitude": 289.3969,
"d60_classical": 0,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "barbra_streisand_1942_aa_v5_holdout",
"asc_sign_idx": 11,
"ascendant_longitude": 346.7636,
"d60_classical": 9,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "beyonce_1981_aa_v5_holdout",
"asc_sign_idx": 0,
"ascendant_longitude": 6.8595,
"d60_classical": 1,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "bob_dylan_1941_aa_v5_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 238.7367,
"d60_classical": 5,
"d60_vedastro_mode": 4,
"d60_pyjhora_method1": 4,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "brigitte_bardot_1934_aa_v5_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 233.8797,
"d60_classical": 7,
"d60_vedastro_mode": 6,
"d60_pyjhora_method1": 6,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "bruce_lee_1940_aa_v5_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 224.6155,
"d60_classical": 1,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "catherine_deneuve_1943_aa_v5_holdout",
"asc_sign_idx": 8,
"ascendant_longitude": 259.5116,
"d60_classical": 11,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "charles_de_gaulle_1890_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 181.278,
"d60_classical": 8,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "cher_1946_aa_v5_holdout",
"asc_sign_idx": 2,
"ascendant_longitude": 76.9514,
"d60_classical": 11,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "clint_eastwood_1930_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 207.1468,
"d60_classical": 0,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "daniel_barenboim_1942_aa_v5_holdout",
"asc_sign_idx": 9,
"ascendant_longitude": 292.2015,
"d60_classical": 6,
"d60_vedastro_mode": 5,
"d60_pyjhora_method1": 5,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "diane_cilento_1932_aa_v5_holdout",
"asc_sign_idx": 9,
"ascendant_longitude": 290.6112,
"d60_classical": 3,
"d60_vedastro_mode": 2,
"d60_pyjhora_method1": 2,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "dingdong_dantes_1980_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 181.5986,
"d60_classical": 9,
"d60_vedastro_mode": 9,
"d60_pyjhora_method1": 9,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "donald_trump_1946_aa_v5_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 128.3089,
"d60_classical": 8,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "edith_piaf_1915_aa_v5_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 212.402,
"d60_classical": 0,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "elvis_presley_1935_aa_v5_holdout",
"asc_sign_idx": 7,
"ascendant_longitude": 230.8658,
"d60_classical": 1,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "francois_hollande_1954_aa_v5_holdout",
"asc_sign_idx": 1,
"ascendant_longitude": 46.0748,
"d60_classical": 10,
"d60_vedastro_mode": 9,
"d60_pyjhora_method1": 9,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "frida_kahlo_1907_aa_v5_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 122.4798,
"d60_classical": 8,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "george_w_bush_1946_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 105.4441,
"d60_classical": 10,
"d60_vedastro_mode": 9,
"d60_pyjhora_method1": 9,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "gisele_bundchen_1980_aa_v5_holdout",
"asc_sign_idx": 8,
"ascendant_longitude": 263.6478,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "gustavo_kuerten_1976_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 92.6966,
"d60_classical": 9,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "imelda_marcos_1929_aa_v5_holdout",
"asc_sign_idx": 2,
"ascendant_longitude": 77.1545,
"d60_classical": 0,
"d60_vedastro_mode": 0,
"d60_pyjhora_method1": 0,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "janis_joplin_1943_aa_v5_holdout",
"asc_sign_idx": 10,
"ascendant_longitude": 303.9231,
"d60_classical": 5,
"d60_vedastro_mode": 5,
"d60_pyjhora_method1": 5,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "jennifer_aniston_1969_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 182.6838,
"d60_classical": 11,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "jimi_hendrix_1942_aa_v5_holdout",
"asc_sign_idx": 8,
"ascendant_longitude": 243.0694,
"d60_classical": 2,
"d60_vedastro_mode": 2,
"d60_pyjhora_method1": 2,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "johnny_depp_1963_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 110.5385,
"d60_classical": 9,
"d60_vedastro_mode": 8,
"d60_pyjhora_method1": 8,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "judy_garland_1922_aa_v5_holdout",
"asc_sign_idx": 2,
"ascendant_longitude": 79.5603,
"d60_classical": 5,
"d60_vedastro_mode": 5,
"d60_pyjhora_method1": 5,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "juscelino_kubitschek_1902_aa_v5_holdout",
"asc_sign_idx": 9,
"ascendant_longitude": 274.8708,
"d60_classical": 7,
"d60_vedastro_mode": 6,
"d60_pyjhora_method1": 6,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "kamala_harris_1964_aa_v5_holdout",
"asc_sign_idx": 2,
"ascendant_longitude": 62.5086,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "leonardo_dicaprio_1974_aa_v5_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 161.0553,
"d60_classical": 4,
"d60_vedastro_mode": 3,
"d60_pyjhora_method1": 3,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "lionel_messi_1987_aa_v5_holdout",
"asc_sign_idx": 9,
"ascendant_longitude": 282.7709,
"d60_classical": 11,
"d60_vedastro_mode": 10,
"d60_pyjhora_method1": 10,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "lou_diamond_phillips_1962_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 116.2537,
"d60_classical": 8,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "manuel_puig_1932_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 186.6657,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "marilyn_monroe_1926_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 111.6899,
"d60_classical": 11,
"d60_vedastro_mode": 10,
"d60_pyjhora_method1": 10,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "meryl_streep_1949_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 101.0442,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "miley_cyrus_1992_aa_v5_holdout",
"asc_sign_idx": 1,
"ascendant_longitude": 36.3265,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "muhammad_ali_1942_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 117.9238,
"d60_classical": 11,
"d60_vedastro_mode": 10,
"d60_pyjhora_method1": 10,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "nicolas_sarkozy_1955_aa_v5_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 154.3377,
"d60_classical": 2,
"d60_vedastro_mode": 1,
"d60_pyjhora_method1": 1,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "pele_1940_aa_v5_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 137.9234,
"d60_classical": 3,
"d60_vedastro_mode": 3,
"d60_pyjhora_method1": 3,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "piolo_pascual_1977_aa_v5_holdout",
"asc_sign_idx": 4,
"ascendant_longitude": 132.9944,
"d60_classical": 5,
"d60_vedastro_mode": 5,
"d60_pyjhora_method1": 5,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "prince_1958_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 204.8647,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "rafael_nadal_1986_aa_v5_holdout",
"asc_sign_idx": 6,
"ascendant_longitude": 197.6444,
"d60_classical": 5,
"d60_vedastro_mode": 5,
"d60_pyjhora_method1": 5,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "rudy_fernandez_1952_aa_v5_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 178.9455,
"d60_classical": 3,
"d60_vedastro_mode": 2,
"d60_pyjhora_method1": 2,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "salvador_dali_1904_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 91.157,
"d60_classical": 6,
"d60_vedastro_mode": 5,
"d60_pyjhora_method1": 5,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "serena_williams_1981_aa_v5_holdout",
"asc_sign_idx": 0,
"ascendant_longitude": 11.0106,
"d60_classical": 10,
"d60_vedastro_mode": 10,
"d60_pyjhora_method1": 10,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "silvio_santos_1930_aa_v5_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 152.8918,
"d60_classical": 11,
"d60_vedastro_mode": 10,
"d60_pyjhora_method1": 10,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "sophia_loren_1934_aa_v5_holdout",
"asc_sign_idx": 8,
"ascendant_longitude": 253.9547,
"d60_classical": 11,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "venus_williams_1980_aa_v5_holdout",
"asc_sign_idx": 5,
"ascendant_longitude": 171.3938,
"d60_classical": 0,
"d60_vedastro_mode": 11,
"d60_pyjhora_method1": 11,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "vincent_van_gogh_1853_aa_v5_holdout",
"asc_sign_idx": 3,
"ascendant_longitude": 90.7335,
"d60_classical": 5,
"d60_vedastro_mode": 4,
"d60_pyjhora_method1": 4,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
},
{
"case_id": "whitney_houston_1963_aa_v5_holdout",
"asc_sign_idx": 10,
"ascendant_longitude": 316.5233,
"d60_classical": 7,
"d60_vedastro_mode": 7,
"d60_pyjhora_method1": 7,
"classical_matches_pyjhora": true,
"vedastro_matches_pyjhora": true
},
{
"case_id": "zinedine_zidane_1972_aa_v5_holdout",
"asc_sign_idx": 1,
"ascendant_longitude": 36.9097,
"d60_classical": 3,
"d60_vedastro_mode": 2,
"d60_pyjhora_method1": 2,
"classical_matches_pyjhora": false,
"vedastro_matches_pyjhora": true
}
]
}
@@ -0,0 +1,565 @@
{
"brief": "docs/tasks/TASK-rectification-d60-fix-20261029.md",
"bug": "BUG-1500",
"cases": [
{
"ascendant_longitude": 71.1909,
"case_id": "albert_brooks_1947_aa_v4_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 109.6959,
"case_id": "andrew_windsor_1960_aa_v4_holdout",
"d60_sign_idx_production": 6,
"d60_sign_idx_pyjhora": 6,
"matches_pyjhora": true
},
{
"ascendant_longitude": 96.8001,
"case_id": "angelina_jolie_1975_aa_v4_holdout",
"d60_sign_idx_production": 4,
"d60_sign_idx_pyjhora": 4,
"matches_pyjhora": true
},
{
"ascendant_longitude": 296.1798,
"case_id": "barack_obama_1961_aa_v4_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 107.0009,
"case_id": "bernd_eichinger_1949_aa_v4_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 269.6959,
"case_id": "chad_everett_1937_aa_v4_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 162.7012,
"case_id": "elizabeth_montgomery_1933_aa_v4_holdout",
"d60_sign_idx_production": 6,
"d60_sign_idx_pyjhora": 6,
"matches_pyjhora": true
},
{
"ascendant_longitude": 231.7983,
"case_id": "elizabeth_taylor_1932_aa_v4_holdout",
"d60_sign_idx_production": 2,
"d60_sign_idx_pyjhora": 2,
"matches_pyjhora": true
},
{
"ascendant_longitude": 216.2833,
"case_id": "iwao_takamoto_1925_aa_v4_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 149.6725,
"case_id": "john_robbins_1947_aa_v4_holdout",
"d60_sign_idx_production": 3,
"d60_sign_idx_pyjhora": 3,
"matches_pyjhora": true
},
{
"ascendant_longitude": 59.9029,
"case_id": "joseph_kennedy_iii_1980_aa_v4_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 151.3987,
"case_id": "kurt_cobain_1967_aa_v4_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 104.8722,
"case_id": "pablo_picasso_1881_aa_v4_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 218.6428,
"case_id": "paul_ryan_1970_aa_v4_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 145.4799,
"case_id": "salma_hayek_1966_aa_v4_holdout",
"d60_sign_idx_production": 6,
"d60_sign_idx_pyjhora": 6,
"matches_pyjhora": true
},
{
"ascendant_longitude": 113.2594,
"case_id": "sean_lennon_1975_aa_v4_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 199.7737,
"case_id": "sigmund_freud_1856_aa_v4_holdout",
"d60_sign_idx_production": 9,
"d60_sign_idx_pyjhora": 9,
"matches_pyjhora": true
},
{
"ascendant_longitude": 9.9031,
"case_id": "steve_reich_1936_aa_v4_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 152.3435,
"case_id": "tiger_woods_1975_aa_v4_holdout",
"d60_sign_idx_production": 9,
"d60_sign_idx_pyjhora": 9,
"matches_pyjhora": true
},
{
"ascendant_longitude": 135.3649,
"case_id": "tom_kennedy_1927_aa_v4_holdout",
"d60_sign_idx_production": 10,
"d60_sign_idx_pyjhora": 10,
"matches_pyjhora": true
},
{
"ascendant_longitude": 234.5927,
"case_id": "adriana_lima_1981_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 242.6992,
"case_id": "agatha_christie_1890_aa_v5_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 80.9181,
"case_id": "albert_einstein_1879_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 30.0607,
"case_id": "alberto_fujimori_1938_aa_v5_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 59.3382,
"case_id": "arthur_conan_doyle_1859_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 307.1967,
"case_id": "audrey_hepburn_1929_aa_v5_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 289.3969,
"case_id": "ayrton_senna_1960_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 346.7636,
"case_id": "barbra_streisand_1942_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 6.8595,
"case_id": "beyonce_1981_aa_v5_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 238.7367,
"case_id": "bob_dylan_1941_aa_v5_holdout",
"d60_sign_idx_production": 4,
"d60_sign_idx_pyjhora": 4,
"matches_pyjhora": true
},
{
"ascendant_longitude": 233.8797,
"case_id": "brigitte_bardot_1934_aa_v5_holdout",
"d60_sign_idx_production": 6,
"d60_sign_idx_pyjhora": 6,
"matches_pyjhora": true
},
{
"ascendant_longitude": 224.6155,
"case_id": "bruce_lee_1940_aa_v5_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 259.5116,
"case_id": "catherine_deneuve_1943_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 181.278,
"case_id": "charles_de_gaulle_1890_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 76.9514,
"case_id": "cher_1946_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 207.1468,
"case_id": "clint_eastwood_1930_aa_v5_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 292.2015,
"case_id": "daniel_barenboim_1942_aa_v5_holdout",
"d60_sign_idx_production": 5,
"d60_sign_idx_pyjhora": 5,
"matches_pyjhora": true
},
{
"ascendant_longitude": 290.6112,
"case_id": "diane_cilento_1932_aa_v5_holdout",
"d60_sign_idx_production": 2,
"d60_sign_idx_pyjhora": 2,
"matches_pyjhora": true
},
{
"ascendant_longitude": 181.5986,
"case_id": "dingdong_dantes_1980_aa_v5_holdout",
"d60_sign_idx_production": 9,
"d60_sign_idx_pyjhora": 9,
"matches_pyjhora": true
},
{
"ascendant_longitude": 128.3089,
"case_id": "donald_trump_1946_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 212.402,
"case_id": "edith_piaf_1915_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 230.8658,
"case_id": "elvis_presley_1935_aa_v5_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 46.0748,
"case_id": "francois_hollande_1954_aa_v5_holdout",
"d60_sign_idx_production": 9,
"d60_sign_idx_pyjhora": 9,
"matches_pyjhora": true
},
{
"ascendant_longitude": 122.4798,
"case_id": "frida_kahlo_1907_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 105.4441,
"case_id": "george_w_bush_1946_aa_v5_holdout",
"d60_sign_idx_production": 9,
"d60_sign_idx_pyjhora": 9,
"matches_pyjhora": true
},
{
"ascendant_longitude": 263.6478,
"case_id": "gisele_bundchen_1980_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 92.6966,
"case_id": "gustavo_kuerten_1976_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 77.1545,
"case_id": "imelda_marcos_1929_aa_v5_holdout",
"d60_sign_idx_production": 0,
"d60_sign_idx_pyjhora": 0,
"matches_pyjhora": true
},
{
"ascendant_longitude": 303.9231,
"case_id": "janis_joplin_1943_aa_v5_holdout",
"d60_sign_idx_production": 5,
"d60_sign_idx_pyjhora": 5,
"matches_pyjhora": true
},
{
"ascendant_longitude": 182.6838,
"case_id": "jennifer_aniston_1969_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 243.0694,
"case_id": "jimi_hendrix_1942_aa_v5_holdout",
"d60_sign_idx_production": 2,
"d60_sign_idx_pyjhora": 2,
"matches_pyjhora": true
},
{
"ascendant_longitude": 110.5385,
"case_id": "johnny_depp_1963_aa_v5_holdout",
"d60_sign_idx_production": 8,
"d60_sign_idx_pyjhora": 8,
"matches_pyjhora": true
},
{
"ascendant_longitude": 79.5603,
"case_id": "judy_garland_1922_aa_v5_holdout",
"d60_sign_idx_production": 5,
"d60_sign_idx_pyjhora": 5,
"matches_pyjhora": true
},
{
"ascendant_longitude": 274.8708,
"case_id": "juscelino_kubitschek_1902_aa_v5_holdout",
"d60_sign_idx_production": 6,
"d60_sign_idx_pyjhora": 6,
"matches_pyjhora": true
},
{
"ascendant_longitude": 62.5086,
"case_id": "kamala_harris_1964_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 161.0553,
"case_id": "leonardo_dicaprio_1974_aa_v5_holdout",
"d60_sign_idx_production": 3,
"d60_sign_idx_pyjhora": 3,
"matches_pyjhora": true
},
{
"ascendant_longitude": 282.7709,
"case_id": "lionel_messi_1987_aa_v5_holdout",
"d60_sign_idx_production": 10,
"d60_sign_idx_pyjhora": 10,
"matches_pyjhora": true
},
{
"ascendant_longitude": 116.2537,
"case_id": "lou_diamond_phillips_1962_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 186.6657,
"case_id": "manuel_puig_1932_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 111.6899,
"case_id": "marilyn_monroe_1926_aa_v5_holdout",
"d60_sign_idx_production": 10,
"d60_sign_idx_pyjhora": 10,
"matches_pyjhora": true
},
{
"ascendant_longitude": 101.0442,
"case_id": "meryl_streep_1949_aa_v5_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 36.3265,
"case_id": "miley_cyrus_1992_aa_v5_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 117.9238,
"case_id": "muhammad_ali_1942_aa_v5_holdout",
"d60_sign_idx_production": 10,
"d60_sign_idx_pyjhora": 10,
"matches_pyjhora": true
},
{
"ascendant_longitude": 154.3377,
"case_id": "nicolas_sarkozy_1955_aa_v5_holdout",
"d60_sign_idx_production": 1,
"d60_sign_idx_pyjhora": 1,
"matches_pyjhora": true
},
{
"ascendant_longitude": 137.9234,
"case_id": "pele_1940_aa_v5_holdout",
"d60_sign_idx_production": 3,
"d60_sign_idx_pyjhora": 3,
"matches_pyjhora": true
},
{
"ascendant_longitude": 132.9944,
"case_id": "piolo_pascual_1977_aa_v5_holdout",
"d60_sign_idx_production": 5,
"d60_sign_idx_pyjhora": 5,
"matches_pyjhora": true
},
{
"ascendant_longitude": 204.8647,
"case_id": "prince_1958_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 197.6444,
"case_id": "rafael_nadal_1986_aa_v5_holdout",
"d60_sign_idx_production": 5,
"d60_sign_idx_pyjhora": 5,
"matches_pyjhora": true
},
{
"ascendant_longitude": 178.9455,
"case_id": "rudy_fernandez_1952_aa_v5_holdout",
"d60_sign_idx_production": 2,
"d60_sign_idx_pyjhora": 2,
"matches_pyjhora": true
},
{
"ascendant_longitude": 91.157,
"case_id": "salvador_dali_1904_aa_v5_holdout",
"d60_sign_idx_production": 5,
"d60_sign_idx_pyjhora": 5,
"matches_pyjhora": true
},
{
"ascendant_longitude": 11.0106,
"case_id": "serena_williams_1981_aa_v5_holdout",
"d60_sign_idx_production": 10,
"d60_sign_idx_pyjhora": 10,
"matches_pyjhora": true
},
{
"ascendant_longitude": 152.8918,
"case_id": "silvio_santos_1930_aa_v5_holdout",
"d60_sign_idx_production": 10,
"d60_sign_idx_pyjhora": 10,
"matches_pyjhora": true
},
{
"ascendant_longitude": 253.9547,
"case_id": "sophia_loren_1934_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 171.3938,
"case_id": "venus_williams_1980_aa_v5_holdout",
"d60_sign_idx_production": 11,
"d60_sign_idx_pyjhora": 11,
"matches_pyjhora": true
},
{
"ascendant_longitude": 90.7335,
"case_id": "vincent_van_gogh_1853_aa_v5_holdout",
"d60_sign_idx_production": 4,
"d60_sign_idx_pyjhora": 4,
"matches_pyjhora": true
},
{
"ascendant_longitude": 316.5233,
"case_id": "whitney_houston_1963_aa_v5_holdout",
"d60_sign_idx_production": 7,
"d60_sign_idx_pyjhora": 7,
"matches_pyjhora": true
},
{
"ascendant_longitude": 36.9097,
"case_id": "zinedine_zidane_1972_aa_v5_holdout",
"d60_sign_idx_production": 2,
"d60_sign_idx_pyjhora": 2,
"matches_pyjhora": true
}
],
"dataset": {
"cases": 77,
"path": "references/real_case_calibration/minute_rectification_holdout_v5.json",
"sha256": "ab365a3e3f4953d4b538f2c0889dc98ab89444a28340c3a7b29e2a864cdd687a"
},
"gate": {
"matches": 77,
"passed": true,
"rate": 1.0,
"threshold": 0.95
},
"issue": 149,
"profile": {
"ayanamsa": "raman",
"node_mode": "mean",
"pyjhora_ayanamsa_mode": "Raman",
"pyjhora_chart": "divisional_chart(divisional_chart_factor=60), traditional Parasara from sign"
},
"scope": "d60_gate_g1_engine_reconciliation",
"task": "docs/tasks/TASK-rectification-d60-two-way-20261028.md"
}
@@ -0,0 +1,80 @@
# D60 换格要不要进生时校正:双向对比报告(2026-10-29,issue #149)
- 任务书:`docs/tasks/TASK-rectification-d60-two-way-20261028.md`;修复单 `docs/tasks/TASK-rectification-d60-fix-20261029.md`、`docs/tasks/TASK-rectification-d60-t5-fix-20261029.md`
- 先登记:`docs/research/d60_two_way_preregistration_2026_10_28.json`(commit 早于任何计分)
- 数据:v5 77 例、964 件事(`minute_rectification_holdout_v5.json`,sha256 `ab365a3e…`)
- 口径:ayanamsa raman、node mean、候选步长 2 分钟、半径 ±10 / ±30 / ±60
- 脚本:`scripts/research/d60_two_way_run.py`(G1)、`scripts/research/d60_two_way_g2_g5.py`(G2 预检与 G5),输出排序、无时间戳,可逐字节复跑
## 结论表
| 门 | 结果 | 关键数字 | 对照 |
| --- | --- | --- | --- |
| G1 三引擎对账 | **过** | 77/77 与 PyJHora 一致 | 修映射前 33/77(BUG-1500) |
| G2 找回记录分钟 | **不可评估**(口径造成) | 可用 D60 换格题 **0 条**:77 例里出生当天事件 0 件 | B 组与 A 组完全相同,提升恒为 0 |
| G3 不伤真值 | 平凡成立 | B 组不淘汰任何候选,区间与 A 相同 | A 基线 76/77 |
| G4 安慰剂 | **不适用** | 没有可检验的提升 | — |
| G5 噪声地板 | **触发上限** | 以 Raman 为基准换岁差:三种换法都是 **77/77(100%,阈值 20%)**;换格幅度见下表 | — |
**产品结论:不做。** 维持「D60 只作参考,不驱动结论」;对外文案不得出现「到秒」「分钟级精确」,与 BUG-1240 的纳迪结论同一口径。
## 为什么 G2 是「不可评估」而不是「没有帮助」
G2 的计分口径是上一轮修正单 §3.3 定的:每次 D60 换格当一题「事件在换格之前还是之后」,**只有事件日期与换格同一天才作答**。D60 换格发生在出生当天,因此只有出生当天的事件能回答这类题;v5 的 77 例、964 件事里出生当天的事件是 **0** 件(逐例核对,见结果 JSON 的 `g2_precheck.per_case`)。于是 B 组一条额外判据都加不上,A、B 两组逐字节相同。
**这是口径设计造成的不可评估,不是把 D60 测出了「没用」。** 规划方(Claude)在本轮验收里也认领了这一点:这个口径注定 0 题。
## G5:分口径的数字
基准是数据声明的 Raman。换岁差后记录时刻的 D60 上升格变化:
| 换法 | 变了多少例 | 比例 | 岁差差值(角分,中位) |
| --- | ---: | ---: | ---: |
| Raman → Lahiri | 77 / 77 | 100% | 86.78′ |
| Raman → KP | 77 / 77 | 100% | 80.97′ |
| Raman → True Chitra | 77 / 77 | 100% | 85.95′(85.51–86.27) |
替代岁差两两之间(同一批盘、同一时刻):
| 换法 | 变了多少例 | 比例 | 岁差差值(角分,中位) |
| --- | ---: | ---: | ---: |
| Lahiri → KP | 21 / 77 | 27.3% | 5.81′ |
| KP → True Chitra | 19 / 77 | 24.7% | 5.02′ |
| Lahiri → True Chitra | 2 / 77 | **2.6%** | 0.83′ |
读法:换格比例跟着两组岁差的差走。差值接近或超过一个 D60 格(30′)时必然大面积翻格(Raman 与三种替代都差 80′ 以上,100%);差值只有约 0.8′ 时(Lahiri 与 True Chitra)只有 2.6%。登记的门是「相对基准 Raman 的换法」,三种都 100%,超过 20% 阈值,所以触发「不得出现到秒 / 分钟级精确」。
**对「低于 20% 就重写结论」的处理**:Lahiri→True Chitra 2.6% 确实低于 20%。这一对是两套几乎重合的岁差(差 0.83′),它说明的是「岁差接近时 D60 不会翻」,而不是「D60 对口径不敏感」。因此我把 G5 的措辞改成分口径报数,不再说「换任何岁差都全变」;产品建议不变——主流岁差之间相差 5–87′,而哪一套岁差才是"对"的本身没有共识,用 D60 去把出生时间收到秒,仍然是用一个比答案更不确定的东西去定答案。若验收方认为这仍算「结论要重写」,请以验收意见为准,我按新的措辞改。
## 模型参与的端到端对比
`not_started`。按任务书的让步顺序在 G4 之后,而 G2/G4 没有可评估的提升;跑 40 场完整对话只会得到 A、B 逐字节相同的结果。
## MEVG(AGENTS.md §3)
- **MEVG / Global Web Evidence**:`used`。
- **A(经典原文 / 可复现数据)**:BPHS 的 Shashtyamsa 规则(每星座 60 份、从本星座起算)与 Jataka Parijata / Bhavartha Ratnakara 的分盘权重是可核对的原典;本仓的 12×60 段枚举与 PyJHora 对账是可复现数据。原典只定义几何与命名,**没有**「D60 可把出生时间收到秒」的判据。
- **B(有案例的专业说明)**:[VedaCharts 的 D60 指南](https://vedacharts.com/learn/articles/shastiamsa-d60-subtle-karma) 明确「每格 0.5°、约 2 分钟换格,5 分钟取整的出生时间不可靠」;[Nyovah 的 D60 页](https://www.nyovah.com/learn/shashtiamsa-d60.html) 用自家引擎做了 24 小时逐分钟扫描,量到上升每分钟 0.25°、约 2 分钟换格,并明确说**不**把 D60 喂给问答模型,因为两分钟误差就会翻盘。两者都把「需要准到分钟」当前提,没有给出「能收到秒」的证据。
- **C(无依据的宣传)**:竞品「证据够密时 D60 与纳迪反向校准、收束可到秒」——无可复现数据、无案例、无算法说明,归 C。纳迪那一半已在 BUG-1240 证伪(N3 找回记录分钟 5/77、N4 换岁差 73/73 换段)。
- 冲突仲裁:B 类给的是「D60 需要准到分钟」,C 类主张「D60 反推能到秒」;前者有测量,后者没有,按有测量的一方取舍,并降级 C 类结论。
- **Real Case Calibration**:`used`。v5 77 例、964 件事;G1 77/77;G2 因口径不可评估;G5 见上表。
## 事后(post-hoc,不参与判门)
- 「如果放宽成『事件日期与换格日期至少差一天就作答』」:每条换格题都会被答成「事件在之后」,把窗口切掉一半且与真值无关,属于一边倒淘汰,因此不当结果。此条写在先登记文件之后,只作解释。
- 前端 `report-density-fictional-engine.json` 里仍有旧的 D60 定义字符串(与本次映射无关),留给前端轮次。
## 建议
1. 不做:D60 不进校正判据,不改技法路由,不加「到秒」文案。
2. 如果产品仍想验证 D60,需要先有「带时刻的事件」数据;用现行 v5 只能重复本次的「不可评估」结论。
3. BUG-1497 记 `closed_by_design`,附对外口径;BUG-1500 已 resolved(映射修正,独立部署)。
## 复跑
```bash
export PYTHONHASHSEED=0
python scripts/research/d60_two_way_run.py # G1 → docs/research/d60_two_way_results_2026_10_29.json
python scripts/research/d60_two_way_g2_g5.py # G2 预检 + G5 → docs/research/d60_two_way_g2_g5_results_2026_10_29.json
python -m pytest tests/test_d60_two_way_g2_g5.py tests/test_d60_two_way_research.py tests/test_d60_varga_mapping.py -q
```
@@ -0,0 +1,118 @@
{
"record_version": "reported-offset-native-candidate-date-v3",
"frozen_at_utc": "2026-10-29T06:08:16.682046+00:00",
"ayanamsa": "raman",
"node_mode": "mean",
"radii_minutes": [
15,
30,
60
],
"offsets_minutes": [
-30,
-20,
-15,
-10,
-8,
-5,
-3,
0,
3,
5,
8,
10,
15,
20,
30
],
"minute_step": 1,
"dataset": "references/real_case_calibration/minute_rectification_holdout_v3.json",
"dataset_sha256": "45aa76ab79dfc6c6404b6252083e1aa5c7e2e2b7de811fc11042a8ad2da3f0ea",
"dataset_benchmark_id": "minute_rectification_fact_ranker_v4_holdout_v3",
"implementation_sha256": "4bb731f7b5043de0b967ccd7e852ae25a1ecdce96c2b7987c142d7878b6632b2",
"implementation_sha256_prefix": "4bb731f7b5043de0",
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "fcf10cb3a5742bb7e2d98d15d69638769cd830f470373ea93745a1cab3718c9b",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "4eb2c03b09a179dd81f912d735823dd09ec8506da2538f40d3a8e04d3ebc6c67",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "96c537d221a84680ddaaba74e3335162c44b5bbd9a60d10e69550a2095910d98",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "bc667c30c9562fb73fb0b7b4c22a5e377f9a531795141fc629b2cd3cf396773a",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "cabc96d1f8c7ed06ef34da4e02e052f598a5e62fd71a7ccbe7b0b099247c27d0",
"scripts/research/sealed_holdout_rerun.py": "69a7ddddfc4a88ec5c85f400c763f8cdbb3c58c00fe9e788a72f79daba1d3bc1",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock",
"scorer": "native_event_contribution_matrix_not_shadow_fact_ranker",
"delivery": "initial_signature_clusters_peak_gap_lt_8_envelope_no_answers_no_elimination",
"rank": "score_desc_then_sha256(benchmark_id:case_id:candidate_time)",
"grid": "every_minute_inclusive_not_production_two_minute_sampling",
"cross_midnight": "date_aware_candidates_distance_and_native_single_matrix",
"evaluator_sha256": "cabc96d1f8c7ed06ef34da4e02e052f598a5e62fd71a7ccbe7b0b099247c27d0",
"replay_revision": "native_candidate_date_v3",
"supersedes": "candidate_date_grouped_v2_identity_and_path_not_assumed_numerically_wrong",
"is_blind_evaluation": false,
"truth_hidden_from_ranker": true,
"official_valid_independent_blind": false,
"official_blind_trial_count": 0,
"results_previously_seen": true,
"must_not_use_for_tuning": true
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,116 @@
{
"record_version": "exposed-v3-fixed-protocol-cross-midnight-rerun-v2",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "fcf10cb3a5742bb7e2d98d15d69638769cd830f470373ea93745a1cab3718c9b",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "4eb2c03b09a179dd81f912d735823dd09ec8506da2538f40d3a8e04d3ebc6c67",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "96c537d221a84680ddaaba74e3335162c44b5bbd9a60d10e69550a2095910d98",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "bc667c30c9562fb73fb0b7b4c22a5e377f9a531795141fc629b2cd3cf396773a",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "cabc96d1f8c7ed06ef34da4e02e052f598a5e62fd71a7ccbe7b0b099247c27d0",
"scripts/research/sealed_holdout_rerun.py": "69a7ddddfc4a88ec5c85f400c763f8cdbb3c58c00fe9e788a72f79daba1d3bc1",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"production_identity_scope": "context_only_shadow_scorer_does_not_call_transition_proximity",
"frozen_at_utc": "2026-10-29T06:07:58.433310+00:00",
"dataset_path": "references/real_case_calibration/minute_rectification_holdout_v3.json",
"dataset_sha256": "45aa76ab79dfc6c6404b6252083e1aa5c7e2e2b7de811fc11042a8ad2da3f0ea",
"algorithm_version": "birth-time-event-fact-ranker-v4-shadow",
"implementation_sha256": "4bb731f7b5043de0b967ccd7e852ae25a1ecdce96c2b7987c142d7878b6632b2",
"files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"historical_frozen_sha256": "f41c298dd6cdcebe7a93e632f7191954be7987f6012ca2a34cecb6e447fbf196",
"evaluator_sha256": "69a7ddddfc4a88ec5c85f400c763f8cdbb3c58c00fe9e788a72f79daba1d3bc1",
"ayanamsa": "raman",
"node_mode": "mean",
"candidate_radius_minutes": [
10
],
"minute_step": 1,
"release_metrics": {
"top_1_rate_minimum": 0.6,
"top_3_rate_minimum": 0.85,
"mean_absolute_minute_error_maximum": 2.0,
"false_confirmation_rate_maximum": 0.05,
"correct_insufficient_evidence_rejection_rate_minimum": 0.9
},
"results_previously_seen": true,
"official_valid_independent_blind": false,
"must_not_use_for_tuning": true,
"tie_breaker": "sha256(benchmark_id:case_id:candidate_time); published minute is never passed to the ranker",
"metric_rank_definition": "competition_rank_1_plus_strictly_higher_scores_legacy_protocol",
"extra_metric_rank_definition": "score_desc_then_existing_opaque_sha256_total_order"
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,119 @@
# PROGRESS · D60 换格双向对比(2026-10-28,issue #149)
- 分支:`codex/rectification-d60-two-way-20261028`,基于 `origin/staging` `88a03808`(写作时 `7721aa9a`,开工时以实际 head 为准)
- 执行:本地 Grok(Windows);验收:Claude
- BUG:BUG-1497 已登记为 `investigating`
- 生产代码、冻结文件、技法路由、对外文案:**零改动**
## 开工前置(已完成)
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 开工预检 | `scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` | 退出码 1。`focused_tests` 里 `tests/test_preflight_fragment_scan.py::test_preflight_fragment_scan_reports_authority_layers_and_risk_buckets` 失败:断言 `.workbuddy/skills/jyotish-vedic-astrology` 镜像路径存在。Python 运行时、碎片扫描、外部引擎适配器、远端可见性四项通过;不把预检写成通过 |
| 基线四个测试文件 | `tests/test_nadi_seconds_research.py`、`test_holdout_v5_schema.py`、`test_varga_resolution_research.py`、`test_repo_privacy_markers.py` | 98 passed |
| 星历 | `python -c "import swisseph; print(swisseph.version)"` | 2.10.03 |
| PyJHora | 导入 `jhora`,`jhora.horoscope.chart.charts` 有 `shashtyamsa_chart` | 可用 |
| jyotishganit | `import jyotishganit` | **未安装**,G1 里记为 `blocked` |
| v5 数据集 | `references/real_case_calibration/minute_rectification_holdout_v5.json` | 77 例,存在 |
环境:`PYTHONHASHSEED=0`、`PYTHONUTF8=1`(Windows 控制台编码)。
## 卡点:B 组的 D60 打分规则需要先定死
任务书 §两个组 只写了「窗口内上升的 D60 格每换一次,候选分成两段;用户给出日精度事件时,按预先登记的 D60 规则给两段打分,淘汰规则与 A 组的换升判据同一套」。
读了 A 组的实现(`scripts/research/probe_supply_after_six.py`):六题来自**日期级**边界(Vimshottari / Narayana / 上升换座),答案是拿事件日期与边界日期比先后(`union_boundary_dates`、`generate_refresh_probes`、`apply_answer`)。D60 换格是**分钟级**的,一天里会换很多次;把日期级答案直接套到分钟级边界上,同一天内几乎没有区分度,会一边倒淘汰。
两个可落地方案(已贴到 #149 请 Claude 定;我推荐 2):
1. **D60 当后置分段**:先跑完 A 组六题,再把幸存候选按 D60 换格切段,用日精度事件的领域—宫位映射给每段打分,只留最高分段(同分不淘汰,其余不动)。改动大,且把 nadi 研究的方法族混进来,报告里要单独解释。
2. **D60 换格题只认同日事件**:把窗口内每次 D60 换格当一条「事件 E 在换格之前还是之后」的题;只有事件日期与换格日期同一天时才作答,没有同日事件就跳过、不淘汰。与 A 组共用 `apply_answer`,只换边界来源。改动小、口径干净、可复现;代价是可用题数取决于同日事件,报告里要给出每题实际用了几条。
规则定了之后才写 `docs/research/d60_two_way_preregistration_2026_10_28.json` 并单独 commit,然后才第一次在 v5 上跑(红线 1)。
## G1 三引擎 D60 对账(已跑,门不过)
结果 JSON:`docs/research/d60_two_way_results_2026_10_28.json`(77 例逐条:上升经度、本仓两套 D60、PyJHora D60、是否一致)。
| 引擎 | 与生产 D60 一致的例数 | 比例 |
| --- | ---: | ---: |
| 本仓生产 `classical_local`(默认) | 33 / 77 | 42.9% |
| 本仓 `mode='vedastro'` | 77 / 77 | 100% |
| PyJHora(traditional Parasara, from sign) | 作为对账基准 | — |
| jyotishganit | `blocked`:本机未安装 | — |
| VedAstro | `blocked`:本次没有联网调用 | — |
- 差的 44 例全部是 **1-based 偶数星座**(金牛、巨蟹、处女、天蝎、摩羯、双鱼),差值恒为 +1 个星座;一致的 33 例全部是 1-based 奇数星座。
- 根因在 `scripts/varga.py::varga_map` 的 D60 分支(`(si+pi)%12 if o else (si+1+pi)%12`),同文件的 vedastro 映射是 `(si+pi)%12`,与 PyJHora 一致。**这是生产映射的口径问题,不是「D60 没有信号」**,已登记 BUG-1500(investigating)。
- 门要求「与至少一个外部引擎一致 ≥ 95%」,实际 42.9%(生产口径)→ **G1 判不过**,按任务书 G2–G5 全部停。没有跑任何计分,也没有据此改规则。
## 还没做
G2–G5、模型端到端对比、MEVG、报告:全部 `not_started`(G1 不过,按门停止)。
下一步要产品/规划定:D60 映射是修 `varga.py`(改生产、要重新冻结)还是改文档承认这是另一种口径。定了之后重跑 G1;G1 过了才写 G2–G5 的先登记 JSON。
## 环境缺口
- `jyotishganit` 未安装;G1 的外部引擎只剩 PyJHora(门要求「与至少一个外部引擎一致 ≥95%」,仍可判)。
- 预检的 `focused_tests` 有一条与本单无关的失败(上面已列)。
## 第 1 次修正:D60 映射(2026-10-29)
按修复单 `docs/tasks/TASK-rectification-d60-fix-20261029.md` 与产品选择 1 执行。
| 步 | 做了什么 | 结果 |
| --- | --- | --- |
| T0 | 合并最新 `origin/staging`(`68670b281`) | 只有 `docs/BUG_HISTORY.md` 冲突;按编号合并,保留 staging 的 BUG-1496 / 1498 / 1499 与本分支的 BUG-1497 / 1500 |
| T1 | `scripts/varga.py` 的 D60 改为 `(si+pi)%12`(奇偶同规则),加来源注释 | 新增 `tests/test_d60_varga_mapping.py`:12 星座 × 60 段逐段对 PyJHora、偶数星座第 1 段在本星座,8 项全过 |
| T3 | 查锁 D60 旧值的测试 | `tests/test_varga_bphs.py`、`test_upstream_sync9b_varga_bphs.py`、`test_deep_varga_avastha.py`、`test_divisional_charts_extended.py`、`test_cli_smoke.py` 均通过,没有写死旧 D60 星座的断言可改 |
| T2 | 密封 20 + 报时 900 与 `upstream_sync9b_2026_10_28` 记录逐条比 | 20/20、900/900,8 字段与全字段不一致 0,`metrics` / `summary` 相同 → 按 ERR-110 重新冻结为 `d60_mapping_2026_10_29` |
| T4 | 提交 G1 脚本并重跑 | `scripts/research/d60_two_way_run.py` 77/77,门通过;结果 `docs/research/d60_two_way_results_2026_10_29.json`(无时间戳、排序输出,可逐字节复跑) |
| T6 | 记录 | BUG-1500 → resolved,BUG-1497 更新;CHANGELOG 一条;本文件 |
跑过的测试:`tests/test_cli_smoke.py` 35 passed;分盘相关 96 passed、1 failed(`tests/test_d1_d60_varga_mapping_registry.py` 调 `python3`,本机只有 `python`,环境缺口,与本次改动无关);`tests/test_d60_varga_mapping.py` 8 passed;`tests/test_d60_two_way_research.py` 1 passed。
本轮没有跑:Python 快速门(留给验收)、前端(未改产品代码,但合同指针挪了,`rectification-confirmation-gate.test.ts` 的路径按前几轮先例改了)。
下一步(T5):按任务书 §3.3 的口径先写先登记 JSON(G2–G5 规则、阈值、种子),commit 之后再在 v5 上跑计分。
## 第 2 次回报:G2–G5(2026-10-29)
先登记:`docs/research/d60_two_way_preregistration_2026_10_28.json`(单独 commit,早于任何计分)。口径按任务书 §3.3:D60 换格题只认同日事件,没有就跳过。
| 门 | 怎么跑 | 结果 |
| --- | --- | --- |
| G2 预检(可用题数) | 逐例数「与出生同日的事件」 | 77/77 例都是 **0 件**(964 件事里 0 件)→ B 组加不上判据,与 A 组相同;按先登记文件记为 `not_evaluable_by_construction`,不伪装成「测出来没帮助」 |
| G2 找回记录分钟 | 因上一条不适用 | 提升恒为 0,下界不 > 0,门不过(不可评估) |
| G3 不伤真值 | 同上 | B 组不淘汰任何候选,区间与 A 相同(A 基线 76/77),平凡成立 |
| G4 安慰剂 | 无提升可检验 | `not_applicable` |
| G5 噪声地板 | 只换岁差,比较记录时刻的 D60 上升格 | raman→lahiri / kp / true_citra 三种换法都是 **77/77 改变(100%)**,阈值 20% → 触发;即使 G2–G4 全过也不得出现「到秒 / 分钟级精确」 |
| 端到端对比 | 未跑 | 按让步顺序在 G4 之后;G2/G4 不可评估时不消耗 40 场模型对话 |
| MEVG | 已做 | 见报告两行:A 类原典只给几何与命名;B 类两篇专业说明都要求「出生时间准到分钟」,并量到约 2 分钟换格;C 类「到秒」宣传无数据 |
结果 JSON:`docs/research/d60_two_way_g2_g5_results_2026_10_29.json`(逐例:同日事件数、四种岁差下的 D60 上升格)。报告:`docs/research/rectification_d60_two_way_2026_10_29.md`。
复跑(Windows 用 `.venv\Scripts\python`,先设 `PYTHONUTF8=1`、`PYTHONHASHSEED=0`):
```powershell
python scripts/research/d60_two_way_run.py
# G2 预检 + G5:读 v5 逐例数同日事件、四种岁差各算一次 D60 上升格
# (脚本逻辑见本轮提交;结果文件已入库,可逐字段核对)
```
**结论**:不做。D60 不进校正判据,技法路由与对外文案不改;对外不出现「到秒 / 分钟级精确」。BUG-1497 记 `closed_by_design`。
**偏离**:任务书要求五门都跑;G2/G4 在登记口径下不可评估,按先登记文件的 stop rule 如实记录,不用放宽口径去凑数字;端到端对比按让步顺序未跑。用户可见代码本轮零改动。
## T5 第 1 次打回:补脚本与分口径报数(2026-10-29)
修复单 `docs/tasks/TASK-rectification-d60-t5-fix-20261029.md`。
1. **补脚本**:`scripts/research/d60_two_way_g2_g5.py`(G2 预检 + G5),输出排序、无时间戳;`tests/test_d60_two_way_g2_g5.py` 4 项(同日预检一致、汇总与逐例一致、无出生时刻泄漏、**结果文件逐字节复跑**)。G1 脚本已在上一轮提交。
2. **G5 分口径**:
- 以 Raman 为基准:Lahiri 77/77(86.78′)、KP 77/77(80.97′)、True Chitra 77/77(85.95′)。
- 替代岁差两两:Lahiri→KP 21/77(27.3%,5.81′)、KP→True Chitra 19/77(24.7%,5.02′)、**Lahiri→True Chitra 2/77(2.6%,0.83′)**。
- 结论措辞改成分口径:不再说「换任何岁差都全变」;登记门(相对基准)仍三种都 100%。2.6% 这一对是两套几乎重合的岁差,已在报告里写明,并说明若验收方认定「低于 20% 就要重写结论」,以验收意见为准。
3. **报告补口径说明**:G2 不可评估是「只认同日事件」的口径造成的(Claude 已在验收里认领),不是 D60 被测出没帮助。
跑过:`pytest tests/test_d60_two_way_g2_g5.py` 4 passed;`pytest tests/test_d60_two_way_research.py tests/test_d60_varga_mapping.py` 9 passed。
+1 -1
View File
@@ -37,7 +37,7 @@
| 任务书 | 进度 | 主题 | 状态 | 落点 |
| --- | --- | --- | --- | --- |
| `TASK-rectification-d60-two-way-20261028.md` | `PROGRESS-rectification-d60-two-way-20261028.md`(执行方写) | **D60 换格要不要进生时校正:双向对比(issue #149)**:纳迪 / D150 已在 BUG-1240 证伪,本单只测 D60。A 组生产 V9、B 组加 D60 换格判据,同一批 v5 77 例看「有没有帮助」和「有没有伤害」;先登记再跑,G1 三引擎对账、G2 找回记录分钟、G3 不伤真值、G4 安慰剂、G5 换岁差噪声地板;另做 20 例模型参与的端到端对话对比(报告项)。离线研究、生产零改动。预留 BUG-1497 | 待领取 | 本地 Grok 执行 |
| `TASK-rectification-d60-two-way-20261028.md` | `PROGRESS-rectification-d60-two-way-20261028.md`(执行方写) | **D60 换格要不要进生时校正:双向对比(issue #149)**:纳迪 / D150 已在 BUG-1240 证伪,本单只测 D60。A 组生产 V9、B 组加 D60 换格判据,同一批 v5 77 例看「有没有帮助」和「有没有伤害」;先登记再跑,G1 三引擎对账、G2 找回记录分钟、G3 不伤真值、G4 安慰剂、G5 换岁差噪声地板;另做 20 例模型参与的端到端对话对比(报告项)。离线研究、生产零改动。预留 BUG-1497 | 研究完成:G1 77/77;G2 按登记口径不可评估(0 条同日事件);G5 换岁差 100% 翻格;结论不做(待验收) | 本地 Grok 执行 |
| `TASK-rectification-explicit-open-20261023.md` | `PROGRESS-rectification-explicit-open-20261023.md` | **明说要校正只回一句话(issue #103)**:找会话直接读一张对服务角色撤权的表、必然失败被吞(真正进行中的也续不上);`candidate_accepted` 被算作进行中挡住入口和提议卡;兜底只给一句话。产品选 C;只改入口口径、经 RPC 找会话、删兜底,不改共享状态集合、不动表。BUG-1423 | 已合入 staging | 分支 `codex/rectification-explicit-open-20261023` |
| `TASK-chart-table-span-20261023.md` | `PROGRESS-chart-table-span-20261023.md` | **星盘页本命 / 月亮行星表挤进左栏(issue #102)**:#87 给表包了 `ChartSymbolHelp` 后跨栏规则失配;根因修法是 `VedicLayout` 用固定整行容器承载表格,跨栏只认容器;加结构断言防复发。BUG-1422 | 已合入 staging | 分支 `codex/chart-table-span-20261023` |
| `TASK-ui-kit-migration-20261023.md` | `PROGRESS-ui-kit-0-base-20261023.md`;`PROGRESS-ui-kit-1-shell-20261023.md`;`PROGRESS-ui-kit-2-chat-20261023.md`;`PROGRESS-ui-kit-3-chart-20261023.md`;`PROGRESS-ui-kit-4-people-20261023.md`;`PROGRESS-ui-kit-5-pages-20261023.md`;`PROGRESS-ui-kit-6-rectification-20261023.md`;`PROGRESS-ui-kit-7-cleanup-20261023.md` | **界面统一换成组件库**:shadcn base-nova(补 `shadcn/tailwind.css`)· Lucide · Motion · react-resizable-panels · dnd-kit · Zustand;lint 拦手写控件(白名单只减不增);对话旁星盘面板;会话、档案拖动排序(动表);长相不变。产品 2026-10-23 拍板 D1~D8;8 个 issue(K0~K7)串行,取代全站动效 #98 #100 #101 | K0–K7 已在测试环境,待验收 | 原型 https://claude.ai/artifact/PGnWsjHhu38KJseEfEMNWG |
@@ -0,0 +1,66 @@
# TASK · 修正生产 D60 映射,再接着跑 D60 双向研究(issue #149,2026-10-29)
- 日期:2026-10-29
- 来源:issue #149。Grok 的 G1(`98be2649`)发现生产 D60 与 PyJHora 只有 33/77 一致;Claude 验收核对成立。**产品 10-29 选 1:先修 D60,再接着研究。**
- 执行方:Grok(Windows + Docker),**继续用分支 `codex/rectification-d60-two-way-20261028`**,只推这个分支
- 验收:Claude(Linux)
- BUG:分支上原 BUG-1498 与 staging 上的 BUG-1498(测试隔离修复)撞号,本提交已整体改为 **BUG-1500**(D60 映射);BUG-1497(研究本身)不变。开工时再核对一次最大号。
## 1. 基线
- 分支当前 `98be2649`,起点 `88a03808`,**早于** #159 对 `scripts/varga.py` 的改动和 `upstream_sync9b_2026_10_28` 冻结。
- **第一步先把最新 `origin/staging` 合进本分支**(只会和 CHANGELOG / BUG_HISTORY 这类文档冲突),D60 的修改必须落在合并后的 `varga.py` 上。
## 2. 事故实证
| 项 | 结果 |
| --- | --- |
| 生产 `varga_map` D60 | `(si+pi)%12 if o else (si+1+pi)%12`:1-based 偶数星座多 +1 个星座,**无出处注释**(`0178dfb3` 4 月批量提交带入) |
| 同文件 vedastro 模式 D60 | `(si+pi)%12`,与 PyJHora 77/77 一致 |
| 我方说明 `references/shodasavarga-complete-guide.md` | D60「从本星座顺序起算」,奇偶不分,与生产矛盾 |
| 生时校正打分(冻结的打分文件) | 没有直接用 D60;`active_rectification_questions.py`(非冻结)把 D60 列为出题层 |
## 3. 决策记录
1. **产品 10-29 选 1**:生产 D60 改为奇偶星座都从本星座起算。
2. 冻结:沿用 #159 的规矩——校正 20 + 900 条**逐条相同**才重新冻结(新记录 `d60_mapping_2026_10_29`);有一条不同就停下回报「需拍板」,不重新冻结。
3. **G2–G5 的 D60 换格计分口径(你 10-28 问的)定为方案 2**:每次 D60 换格当一题「事件在换格前还是后」,只有事件日期与换格同一天才作答,没有同日事件就跳过、不淘汰;与 A 组共用 `apply_answer`,只换边界来源。报告里写每题实际用了几条事件。
4. 用户可见变化已知并接受:凡落在金牛、巨蟹、处女、天蝎、摩羯、双鱼的行星或上升,D60 星座都会变;咨询卡、深层分盘卡、报告里的 D60 跟着变。
## 4. 硬红线
1. 只改 `varga_map` 的 D60 一行(加出处注释:本仓说明 + PyJHora 对账);vedastro 模式与其他分盘逐字节不变。
2. 冻结:`tests/test_sealed_holdout_contract_freshness.py::IDENTITY_FORBIDDEN_PREFIXES` **只追加、不替换**(#159 第 1 次打回就是这一条);脚本与 `references/rectification_sealed_holdout.v1.json` 的当前指针改到新记录。
3. 锁 D60 旧值的测试(先查 `tests/test_d1_d60_varga_mapping_registry.py`、`tests/test_divisional_charts_extended.py`、`tests/test_deep_varga_avastha.py`、`tests/test_cli_smoke.py`):期望值按新规则改,写原值 / 新值 / 原因;**不得删断言或放宽**。
4. **这次把 G1 的计算脚本提交进仓库**(放 `scripts/research/`,带测试),上一轮只交了结果 JSON,验收没法复跑。
5. 研究部分仍只在研究脚本里做;生产不加 D60 判据,界面不改,不对外说「到秒」。
## 5. 任务分解
| 任务 | 内容 | 验收标准 |
| --- | --- | --- |
| T0 | 合并最新 `origin/staging` | 冲突只在文档;合并后上游 / sync9b 测试照过 |
| T1 | 改 D60 映射(BUG-1500) | 新增测试:12 个星座 × 60 段与 PyJHora 一致;偶数星座第 1 段落在本星座 |
| T2 | 校正回放 20 + 900 与 `upstream_sync9b_2026_10_28` 记录逐条比,相同才重新冻结 | 两份回放 0 处不同;冻结契约测试全过 |
| T3 | 改锁旧值的测试 | 每条改动有三栏注释 |
| T4 | 重跑 G1(提交脚本) | 期望 77/77;不过就停、回报 |
| T5 | G1 过了:按原任务书 `TASK-rectification-d60-two-way-20261028.md` 先登记(计分口径用 §3.3),再跑 G2–G5、安慰剂、端到端、MEVG,出报告 | 先登记文件的提交早于任何计分提交 |
| T6 | 记录:BUG_HISTORY(BUG-1500 resolved、BUG-1497 按结论)、CHANGELOG、PROGRESS、状态板 | — |
## 6. 让步顺序
T0–T4、T6 必做,一起回报一次(G1 结果出来就回报);T5 可以作为下一次回报。
## 7. 验收命令
| 检查 | Grok 自跑 | Claude 验收 |
| --- | --- | --- |
| D60 新测试 + 第 4 节列出的测试文件 | 必跑 | 复验 |
| 校正 20 + 900 | 必跑 | 复验 |
| G1 脚本 | 必跑 | 复跑,逐字节对结果 JSON |
| Python 快速门 | 不跑 | 以 Claude 为准 |
| 前端 `report-fact-tables.test.ts`、咨询卡相关 | 不跑 | 跑 |
## 8. 真机
部署后:挑一张有行星在偶数星座的盘,看咨询卡 / 深层分盘卡里的 D60 星座,与 PyJHora 或 JHora 对一下。清单在 PROGRESS 里列出,由 Claude 合入时转成 `docs/testing/`。
@@ -0,0 +1,36 @@
# TASK · D60 双向研究后半段 · 第 1 次打回(issue #149,2026-10-29)
- 被验 SHA:`028992257bde6f2f2dd8d73844cf8a130f682b3c`(分支 `codex/rectification-d60-two-way-20261028`)
- 执行方:Grok,同一分支继续提交;不新开 BUG 号
## 1. 验收结果
| 检查 | 结果 |
| --- | --- |
| 回报 SHA 是分支最新提交 | 是 |
| 先登记早于计分 | 是(`c163a749` 早于 `02899225`) |
| 生产代码 | 未改 |
| 结论写法 | 照实写了「不可评估」,没有把 0 题写成「没帮助」——对的 |
| **G2–G5 的跑数脚本和测试** | **缺**:分支只有结果 JSON 和报告,没有产生它们的脚本,无法复跑 |
## 2. 为什么必须补
原任务书 `TASK-rectification-d60-two-way-20261028.md` 的交付清单写明「跑数脚本和测试」;上一轮 G1 也因为同样原因在修正单里补过一次。现在整个建议主要靠 **G5「换岁差 77/77 翻格」** 撑着,这个数必须能复跑。
另外说明一点(规划方的问题,不是你的):G2 的「只认同日事件」口径是我在修正单 §3.3 定的。D60 换格日就是出生当天,v5 里不可能有出生当天的人生事件,所以 G2 按这个口径**注定 0 题**。报告里请把这一句写明:G2 不可评估是**口径设计**造成的,不是 D60 被测出没帮助。
## 3. 要做的
1. 把产生 `d60_two_way_g2_g5_results_2026_10_29.json` 的脚本提交到 `scripts/research/`(可并入 `d60_two_way_run.py` 加子命令),输出排序、无时间戳,能逐字节复跑;带一条测试。
2. G5 按每种替代岁差**分别**报:Lahiri→KP、Lahiri→True Chitra 各自有多少例 D60 上升格变了(现在只有合并后的 77/77),以及用的岁差差值(角分)。
3. 报告补上 §2 那句口径说明。
4. 结论与建议不用改,除非分开报以后 G5 低于 20% 阈值——那样就照实改结论并回报。
## 4. 验收命令
| 检查 | Grok 自跑 | Claude 验收 |
| --- | --- | --- |
| 新脚本 + 测试 | 必跑 | 复跑,逐字节对结果 JSON |
| `tests/test_d60_*` | 必跑 | 复验 |
完成后照旧回报新的 head SHA。
@@ -0,0 +1,10 @@
# 真机走查 · 生产 D60 映射修正(issue #149,BUG-1500)
用公开或虚构出生资料,在 staging 上看:
| # | 操作 | 应该看到 |
| --- | --- | --- |
| 1 | 挑一张有行星落在金牛、巨蟹、处女、天蝎、摩羯或双鱼的盘,打开咨询卡或星盘页的深层分盘卡 | D60 一栏的星座和 JHora / PyJHora 用同一出生资料算出的 D60 一致 |
| 2 | 同一张盘里落在白羊、双子、狮子、天秤、射手、水瓶的行星 | D60 星座和以前一样(这一半本来就对) |
| 3 | 生成一份完整报告,翻到分盘部分 | D60 正常显示,没有空白或报错 |
| 4 | 走一次生时校正到出结果 | 和以前一样能走完(打分没有变) |
@@ -114,8 +114,11 @@ const diagnosticReport = JSON.parse(readFileSync(
// 原值(11):docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.json
// 新值(11):docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json
// 原因(11):sync9b(BUG-1494~1495)改了冻结身份里的 scripts/varga.py,输出不变,ERR-110 另存新记录。确认门行为与阈值不变。
// 原值(12):docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json
// 新值(12):docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json
// 原因(12):BUG-1500 修正生产 D60 映射(scripts/varga.py),输出不变,ERR-110 另存新记录。确认门行为与阈值不变。
const currentTreeRerun = JSON.parse(readFileSync(
new URL("../../docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json", import.meta.url),
new URL("../../docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json", import.meta.url),
"utf8",
)) as {
frozen_record: { implementation_sha256: string };
@@ -264,9 +267,10 @@ test("sealed holdout aggregates match the v3 report and still block confirmation
// 原值(8):…ephemeris_nutation_2026_10_08.json / 新值(8):…scoring_perf_2026_10_13.json / 原因(8):BUG-1323~1325 改了冻结身份文件,输出不变,ERR-110 另存新记录。
// 原值(9):…scoring_perf_2026_10_13.json / 新值(9):…upstream_sync8_2026_10_18.json / 原因(9):sync8 改了冻结身份文件,输出不变,ERR-110 另存新记录。
// 原值(10):…upstream_sync8_2026_10_18.json / 新值(10):…upstream_sync9b_2026_10_28.json / 原因(10):sync9b 改了冻结身份里的 varga.py,输出不变,ERR-110 另存新记录。
// 原值(11):…upstream_sync9b_2026_10_28.json / 新值(11):…d60_mapping_2026_10_29.json / 原因(11):BUG-1500 修正 D60 映射,输出不变,ERR-110 另存新记录。
assert.equal(
productHoldout.current_tree_scorer.source_report,
"docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json",
"docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json",
);
assert.equal(currentTreeRerun.official_valid_independent_blind, false);
assert.equal(productHoldout.current_tree_scorer.matches_metrics_scorer, false);
+130 -130
View File
@@ -9,7 +9,7 @@
"dataset_path": "references/real_case_calibration/minute_rectification_holdout_v3.json",
"report_path": "references/real_case_calibration/minute_rectification_holdout_v3_report.json",
"source_audit_status": "corrected_known_date_errors",
"evaluated_on": "2026-10-28",
"evaluated_on": "2026-10-29",
"evaluated_on_scope": "latest_fixed_protocol_rerun_not_historical_runtime_metrics",
"historical_source_audit_status": "invalidated_after_replay",
"report_status": "invalidated_after_source_audit",
@@ -24,7 +24,7 @@
"evaluated_on": "2026-07-21"
},
"current_tree_scorer": {
"implementation_sha256": "b44505aa0034e486fcfc29c8611a9559333a97c1005f92e6a5356bd855122205",
"implementation_sha256": "4bb731f7b5043de0b967ccd7e852ae25a1ecdce96c2b7987c142d7878b6632b2",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
@@ -52,7 +52,7 @@
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "7a727418651321d1b9073588587050c4dc6292587748cf35734dd76cefb0effe",
"production_scoring_sha256": "fcf10cb3a5742bb7e2d98d15d69638769cd830f470373ea93745a1cab3718c9b",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
@@ -62,7 +62,7 @@
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "6fa0b0c335ac0cdc25ee887d432ae2f1f6487c665aed9665ad5cc0bc6ef0283b",
"research_implementation_sha256": "4eb2c03b09a179dd81f912d735823dd09ec8506da2538f40d3a8e04d3ebc6c67",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "96c537d221a84680ddaaba74e3335162c44b5bbd9a60d10e69550a2095910d98",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
@@ -90,17 +90,17 @@
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "8ecc381dfaa3c0e6bea058cfa44c606aabdb1086c137f16da82ee5a3bf5ccc91",
"scripts/research/sealed_holdout_rerun.py": "ebcdae760f2b76c81d5d0c8e2bf347cff4c81cca9074f27ae94b6734408ccd42",
"scripts/research/reported_offset_sweep.py": "cabc96d1f8c7ed06ef34da4e02e052f598a5e62fd71a7ccbe7b0b099247c27d0",
"scripts/research/sealed_holdout_rerun.py": "69a7ddddfc4a88ec5c85f400c763f8cdbb3c58c00fe9e788a72f79daba1d3bc1",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "8ff96b9fc8346ca249abff6109434b6ed57fa150e1a9854d4f73bdf317568368"
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"matches_metrics_scorer": false,
"official_eval_implementation_hash_matches": false,
"official_eval_trial_count": 0,
"source_report": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json",
"source_report": "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json",
"fixed_protocol_rerun_trial_count": 20,
"fixed_protocol_rerun_hash_matches": true,
"metrics": {
@@ -113,6 +113,106 @@
}
},
"current_tree_fixed_protocol_rerun": {
"evaluated_on": "2026-10-29",
"report_path": "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.freeze.json",
"implementation_sha256": "4bb731f7b5043de0b967ccd7e852ae25a1ecdce96c2b7987c142d7878b6632b2",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "fcf10cb3a5742bb7e2d98d15d69638769cd830f470373ea93745a1cab3718c9b",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "4eb2c03b09a179dd81f912d735823dd09ec8506da2538f40d3a8e04d3ebc6c67",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "96c537d221a84680ddaaba74e3335162c44b5bbd9a60d10e69550a2095910d98",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "bc667c30c9562fb73fb0b7b4c22a5e377f9a531795141fc629b2cd3cf396773a",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "cabc96d1f8c7ed06ef34da4e02e052f598a5e62fd71a7ccbe7b0b099247c27d0",
"scripts/research/sealed_holdout_rerun.py": "69a7ddddfc4a88ec5c85f400c763f8cdbb3c58c00fe9e788a72f79daba1d3bc1",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "1bca389e4f36d293a755de175163c3f39b42bab5831cb6f7828830899f9f177e"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"scorer_frozen_before_rerun": true,
"source_audit_status": "corrected_known_date_errors",
"trial_count": 20,
"official_valid_independent_blind": false,
"is_blind_evaluation": false,
"truth_hidden_from_ranker": true,
"results_previously_seen": true,
"must_not_claim_as_release_metrics": true,
"must_not_use_for_tuning": true,
"verified_minute_claim_allowed": false,
"metric_gates_passed": false,
"events_per_case": 3,
"boundary": "Previously exposed v3 shadow fixed-protocol rerun after the D60 mapping fix (ERR-110, BUG-1500). Trials and metrics match the 2026-10-18 upstream sync8 and the upstream_sync9b reports. Versus the 2026-09-20 historical report, changed_trial_count stays 8. Not a release metric. Prior reports and freezes preserved byte-for-byte.",
"report_sha256": "9e667c4e5819674e82519bfe9415d49a202515c765ea99609a9dd27feb69c77d",
"freeze_record_sha256": "8f300876eca9aac683879f1b26204be885c03b2c7b6d03e5930386852cbe4700",
"replay_started_at_utc": "2026-10-29T06:07:59.312582+00:00",
"replay_finished_at_utc": "2026-10-29T06:08:15.756678+00:00",
"previous_fixed_protocol_rerun": {
"report_path": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.freeze.json",
"superseded_reason": "The D60 mapping fix (BUG-1500) changed scripts/varga.py, which is part of the extended identity. Output is unchanged, so ERR-110 stored a new record. Prior upstream_sync9b report and freeze preserved byte-for-byte."
}
},
"previous_fixed_protocol_rerun": {
"evaluated_on": "2026-10-28",
"report_path": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.freeze.json",
@@ -212,106 +312,6 @@
"superseded_reason": "Upstream sync9b (BUG-1494 to BUG-1495) changed scripts/varga.py, which is part of the extended identity. Output is unchanged, so ERR-110 stored a new record. Prior sync8 report and freeze preserved byte-for-byte."
}
},
"previous_fixed_protocol_rerun": {
"evaluated_on": "2026-10-18",
"report_path": "docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.freeze.json",
"implementation_sha256": "bf8981b5c41702f9b333444deee2ab7378b9e98b111240e85ea62e6aae02fda8",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
"scripts/active_rectification_event_engine.py",
"scripts/active_rectification_events.py",
"scripts/ashtakavarga.py",
"scripts/dasha_analyzer.py",
"scripts/divisional_charts_extended.py",
"scripts/domain_calculation_service.py",
"scripts/functional_benefics.py",
"scripts/jaimini.py",
"scripts/minute_rectification_fact_ranker_v4.py",
"scripts/minute_rectification_feature_facts_v4.py",
"scripts/narayana_dasha.py",
"scripts/rectification/api_service.py",
"scripts/rectification/candidate_contrast.py",
"scripts/rectification/candidate_window.py",
"scripts/rectification/case_holdout.py",
"scripts/rectification/contracts.py",
"scripts/rectification/dasha_transition_proximity.py",
"scripts/rectification/decision_policy.py",
"scripts/rectification/event_probes.py",
"scripts/rectification/refinement_packet.py",
"scripts/rectification/scoring_service.py",
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "c2c23bcbde5de58e519ae1d6545620edd0f738ce8dc2e872e659b598137a728f",
"research_files": [
"scripts/research/reported_offset_sweep.py",
"scripts/research/cluster_width_lib.py",
"scripts/research/probe_supply_after_six.py",
"scripts/research/sealed_holdout_rerun.py",
"scripts/minute_rectification_blind_eval.py",
"scripts/minute_rectification_fact_blind_eval_v4.py",
"scripts/minute_rectification_holdout_validator.py"
],
"research_implementation_sha256": "9df579bdacd7dec43abd92c9abc1831771feb800fc29e6864dc315d083d52a03",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "96c537d221a84680ddaaba74e3335162c44b5bbd9a60d10e69550a2095910d98",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "c524da3f54b2ed9c080b78b33854854a0ca3d5d79b7e536bb1c3bc2be3e02852",
"scripts/dasha_analyzer.py": "3949b96813217fe624899856afec9f0b787c4cb0fea3a9a0d961990dbd11943a",
"scripts/divisional_charts_extended.py": "e9820e80f14fddc86ab5495d11455d16c2d3c9502a9a242fcf9efc41186e0d11",
"scripts/domain_calculation_service.py": "66923a2bc69daf65c965d2973c4b9234edbec5147909eaf3609b6b377ce3c7ca",
"scripts/functional_benefics.py": "cbaac3b8c09b97f8724b5300e9a402cbf77089af6c7db8788550d40fd35ac57b",
"scripts/jaimini.py": "6b88658da5404da9b136686d92a04be462d61a39da6e8de4255021e2ed2d1173",
"scripts/minute_rectification_blind_eval.py": "07aa30d8bad3278669495d5fea8be937aaf6367c8af980ff4f2fe9aa84ccc6ff",
"scripts/minute_rectification_fact_blind_eval_v4.py": "bdf460e3467208e8b87345c5beb2128f3e22de7eeffd68f72b281b3ad9affc92",
"scripts/minute_rectification_fact_ranker_v4.py": "f1a0d8d2482cd754d2e7f253a9606b0373519435a2bf58cfc3753e2b9ae0fb76",
"scripts/minute_rectification_feature_facts_v4.py": "3d899a2cdd4825b8e32062443d487edcd2173a4ea55a36eb9f3abe587c0faf0f",
"scripts/minute_rectification_holdout_validator.py": "b60b1c752e58672beaee8b36eb3b2348169726cda070ec969db0f13e7ed715af",
"scripts/narayana_dasha.py": "bc667c30c9562fb73fb0b7b4c22a5e377f9a531795141fc629b2cd3cf396773a",
"scripts/rectification/api_service.py": "089730097d3872a4f7b5d7dd5574bb7e9ab4d2e246d4a380800bc824d7979b95",
"scripts/rectification/candidate_contrast.py": "eee7da71c0574a08876404b78ca111153fa95fb83ace82b9fdca141d1992e273",
"scripts/rectification/candidate_window.py": "2fbc5058b12049b15fca375cdc125b8283e19f9f3e4bedcc291e344501891bef",
"scripts/rectification/case_holdout.py": "fe0e699b617d9e216acdfeff87af4221c1d6f4c101bf33e1dbf14e2bcd75a8b5",
"scripts/rectification/contracts.py": "c6dc6bd230e38f9f2126c224aae9ddbd6415304c15340f8c7cd3f06f6ef3160f",
"scripts/rectification/dasha_transition_proximity.py": "5ce4ed27b0f06c681abc34e5fd998fafb10c153a0070aa36c99ddfa869a2cbf2",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "f5ca9d54501f67a1546fcf5b01da0c1277dec2e2c6df481884e8900d14909a7c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "fa056fa30d9e6ffa4b75295fc49c793e35b26ebeca64ca843d26c8abef3050f2",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "e10537ca2caba3a4e6a8d2460265543b0cca55935afa8004108e45bef4bc3de7",
"scripts/research/sealed_holdout_rerun.py": "7945353014b93b6d7641f278779111d85b1773293781343b802a9b4b655ca4b5",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "c1f06967c3d4d214edadff139c24aa31e59fb628477174235abe14f799a99076"
},
"hash_scope": "explicit_identity_file_sets_not_a_transitive_dependency_lock"
},
"scorer_frozen_before_rerun": true,
"source_audit_status": "corrected_known_date_errors",
"trial_count": 20,
"official_valid_independent_blind": false,
"is_blind_evaluation": false,
"truth_hidden_from_ranker": true,
"results_previously_seen": true,
"must_not_claim_as_release_metrics": true,
"must_not_use_for_tuning": true,
"verified_minute_claim_allowed": false,
"metric_gates_passed": false,
"events_per_case": 3,
"boundary": "Previously exposed v3 shadow fixed-protocol rerun after upstream sync8 (ERR-110, BUG-1380 to BUG-1390). Trials and metrics match the 2026-10-13 scoring_perf report. Versus the 2026-09-20 historical report, changed_trial_count stays 8. Not a release metric. Prior scoring_perf report and freeze preserved byte-for-byte.",
"report_sha256": "4573440f00138563122dd3aa12f4ca66517f2b4aad5a2db9373a87eeb8997ce4",
"freeze_record_sha256": "493b4199df86c1d8782ae1016b2509d7602758d6fdb4e2c492207eb1af38eac0",
"replay_started_at_utc": "2026-10-18T10:46:24.464749+00:00",
"replay_finished_at_utc": "2026-10-18T10:46:26.772898+00:00",
"previous_fixed_protocol_rerun": {
"report_path": "docs/research/sealed_holdout_rerun_scoring_perf_2026_10_13.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_scoring_perf_2026_10_13.freeze.json",
"superseded_reason": "Upstream sync8 (BUG-1380 to BUG-1390) changed frozen identity files. Output is unchanged, so ERR-110 stored a new record. Prior scoring_perf report and freeze preserved byte-for-byte."
}
},
"current_tree_unfrozen_diagnostic": {
"is_blind_evaluation": false,
"results_already_seen": true,
@@ -330,6 +330,28 @@
"verified_minute_claim_allowed": false
},
"current_tree_reported_offset_replay": {
"report_path": "docs/research/reported_offset_d60_mapping_2026_10_29.json",
"report_sha256": "f40157139733552dbefdfc999f95458de75594cd511df0e5377d606e27559f0d",
"freeze_record_path": "docs/research/reported_offset_d60_mapping_2026_10_29.freeze.json",
"freeze_record_sha256": "20e7684bc6c7356a421c2c20517c153279561f810cd15d77f260c9915352aed9",
"scope": "reported_offset_sensitivity_not_product_accuracy",
"trial_count": 900,
"official_valid_independent_blind": false,
"official_blind_trial_count": 0,
"must_not_use_for_tuning": true,
"must_not_claim_as_release_metrics": true,
"replay_started_at_utc": "2026-10-29T06:08:17.701243+00:00",
"replay_finished_at_utc": "2026-10-29T06:29:23.437778+00:00",
"boundary": "Previously exposed reported-offset sensitivity after the D60 mapping fix (ERR-110, BUG-1500). Summary and trials match the 2026-10-18 upstream sync8 and the upstream_sync9b reports. Versus the 2026-09-20 historical report, changed_trial_count stays 581 of 900. Not a release metric. No tuning. Prior reports and freezes preserved byte-for-byte.",
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_upstream_sync9b_2026_10_28.json",
"report_sha256": "880bebc2e217100994a1442e47ead3f9d33e48aa3ac20f69d993f38def3ef25c",
"freeze_record_path": "docs/research/reported_offset_upstream_sync9b_2026_10_28.freeze.json",
"freeze_record_sha256": "385817bb27f04afeba230af5e547dd10dc8cf6db4b25c18bebe4f4e674cab972",
"superseded_reason": "The D60 mapping fix (BUG-1500) changed scripts/varga.py, which is part of the extended identity. Output is unchanged, so ERR-110 stored a new record. Prior upstream_sync9b report and freeze preserved byte-for-byte."
}
},
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_upstream_sync9b_2026_10_28.json",
"report_sha256": "880bebc2e217100994a1442e47ead3f9d33e48aa3ac20f69d993f38def3ef25c",
"freeze_record_path": "docs/research/reported_offset_upstream_sync9b_2026_10_28.freeze.json",
@@ -350,27 +372,5 @@
"freeze_record_sha256": "117ab0bfa4a283e9d52073808f71dd8317f613c96b27ec271d887ef40087f4f5",
"superseded_reason": "Upstream sync9b (BUG-1494 to BUG-1495) changed scripts/varga.py, which is part of the extended identity. Output is unchanged, so ERR-110 stored a new record. Prior sync8 report and freeze preserved byte-for-byte."
}
},
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_upstream_sync8_2026_10_18.json",
"report_sha256": "a51aad2e743dccba7726d1a0a5e44c5e431ff429fe1725c9be2f7fa5e9282da6",
"freeze_record_path": "docs/research/reported_offset_upstream_sync8_2026_10_18.freeze.json",
"freeze_record_sha256": "117ab0bfa4a283e9d52073808f71dd8317f613c96b27ec271d887ef40087f4f5",
"scope": "reported_offset_sensitivity_not_product_accuracy",
"trial_count": 900,
"official_valid_independent_blind": false,
"official_blind_trial_count": 0,
"must_not_use_for_tuning": true,
"must_not_claim_as_release_metrics": true,
"replay_started_at_utc": "2026-10-18T10:46:27.013583+00:00",
"replay_finished_at_utc": "2026-10-18T10:49:10.767675+00:00",
"boundary": "Previously exposed reported-offset sensitivity after upstream sync8 (ERR-110, BUG-1380 to BUG-1390). Summary and trials match the 2026-10-13 scoring_perf report. Versus the 2026-09-20 historical report, changed_trial_count stays 581 of 900. Not a release metric. No tuning. Prior scoring_perf report and freeze preserved byte-for-byte.",
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_scoring_perf_2026_10_13.json",
"report_sha256": "9466cf3945a63621104157fb34291cb23205ddb045effa7e70f3c35647516443",
"freeze_record_path": "docs/research/reported_offset_scoring_perf_2026_10_13.freeze.json",
"freeze_record_sha256": "1560f24ffea19116c904272907ff9cce24904960406676f3aada3c8c174cf98a",
"superseded_reason": "Upstream sync8 (BUG-1380 to BUG-1390) changed frozen identity files. Output is unchanged, so ERR-110 stored a new record. Versus the 2026-09-20 historical report, changed_trial_count stays 581 of 900. Prior scoring_perf report and freeze preserved byte-for-byte."
}
}
}
+197
View File
@@ -0,0 +1,197 @@
#!/usr/bin/env python3
"""G2 precheck and G5 noise floor for the D60 two-way study (issue #149).
Two measurements, both deterministic (no timestamps, sorted keys, fixed
formatting), so a rerun can be compared byte for byte:
* G2 precheck: how many v5 cases have an event dated on the birth day. The
registered answer policy (`docs/research/d60_two_way_preregistration_2026_10_28.json`)
only answers a D60 boundary probe when an event shares the boundary's date,
so zero same-day events means group B adds no question at all.
* G5: how often the ascendant's D60 sign at the recorded time changes when the
ayanamsa is switched away from Raman, per switch, with the ayanamsa offset in
arcminutes.
Usage:
python scripts/research/d60_two_way_g2_g5.py # writes the results JSON
python scripts/research/d60_two_way_g2_g5.py --json # prints it
PyJHora is not needed here; only the production ephemeris and the D60 mapping.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
SCRIPTS = ROOT / "scripts"
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
from scripts.jyotish_engine import compute_chart_data # noqa: E402
DATASET = ROOT / "references/real_case_calibration/minute_rectification_holdout_v5.json"
DEFAULT_OUT = ROOT / "docs/research/d60_two_way_g2_g5_results_2026_10_29.json"
BASELINE = "raman"
ALTERNATIVES = ("lahiri", "kp", "true_citra")
G5_THRESHOLD = 0.20
def _cases() -> list[dict]:
return json.loads(DATASET.read_text(encoding="utf-8"))["cases"]
def _ascendant(case: dict, ayanamsa: str) -> tuple[float, int]:
import varga
birth = case["birth"]
year, month, day = (int(part) for part in birth["date"].split("-"))
hour, minute = (int(part) for part in birth["time"].split(":"))
chart, _asc_idx, _jd, ayanamsa_degrees = compute_chart_data(
year,
month,
day,
hour,
minute,
birth["latitude"],
birth["longitude"],
birth["timezone_offset"],
node_mode="mean",
ayanamsa_name=ayanamsa,
)
longitude = float((chart.get("ascendant") or {})["degree_raw"])
return float(ayanamsa_degrees), int(varga.calc_varga(longitude, 60)["sign_idx"])
def same_day_precheck(cases: list[dict] | None = None) -> dict:
cases = _cases() if cases is None else cases
per_case = []
for case in cases:
birth_date = case["birth"]["date"]
same_day = [e for e in case.get("events", []) if str(e.get("date", "")).startswith(birth_date)]
per_case.append({"case_id": case["case_id"], "events_same_day": len(same_day)})
return {
"cases_with_same_day_events": sum(1 for row in per_case if row["events_same_day"]),
"same_day_events": sum(row["events_same_day"] for row in per_case),
"usable_d60_boundary_probes": 0,
"verdict": "not_evaluable_by_construction",
"reason": (
"the registered answer policy needs an event dated on the same day as the D60 boundary "
"(the birth date); the v5 holdout has none, so group B adds no question and is identical "
"to group A. This is a design consequence of the registered rule, not a measurement that "
"D60 does not help."
),
"per_case": per_case,
}
def g5(cases: list[dict] | None = None) -> dict:
cases = _cases() if cases is None else cases
modes = (BASELINE,) + ALTERNATIVES
rows = []
for case in cases:
base_ayanamsa, base_sign = _ascendant(case, BASELINE)
row = {
"case_id": case["case_id"],
f"d60_{BASELINE}": base_sign,
f"ayanamsa_offset_arcminutes_{BASELINE}": 0.0,
}
for mode in ALTERNATIVES:
ayanamsa, sign = _ascendant(case, mode)
row[f"d60_{mode}"] = sign
row[f"ayanamsa_offset_arcminutes_{mode}"] = round((ayanamsa - base_ayanamsa) * 60.0, 2)
for mode in ALTERNATIVES:
row[f"changes_{mode}"] = row[f"d60_{mode}"] != row[f"d60_{BASELINE}"]
rows.append(row)
count = len(rows)
switches = {}
for mode in ALTERNATIVES:
offsets = sorted(row[f"ayanamsa_offset_arcminutes_{mode}"] for row in rows)
changed = sum(1 for row in rows if row[f"changes_{mode}"])
switches[f"{BASELINE}_to_{mode}"] = {
"changed_cases": changed,
"share": round(changed / count, 4) if count else None,
"ayanamsa_offset_arcminutes": {
"min": offsets[0] if offsets else None,
"median": offsets[len(offsets) // 2] if offsets else None,
"max": offsets[-1] if offsets else None,
},
}
pairwise = {}
for index, left in enumerate(modes):
for right in modes[index + 1:]:
changed = sum(1 for row in rows if row[f"d60_{left}"] != row[f"d60_{right}"])
deltas = sorted(
round(row[f"ayanamsa_offset_arcminutes_{right}"] - row[f"ayanamsa_offset_arcminutes_{left}"], 2)
for row in rows
)
pairwise[f"{left}_to_{right}"] = {
"changed_cases": changed,
"share": round(changed / count, 4) if count else None,
"ayanamsa_offset_arcminutes": {
"min": deltas[0] if deltas else None,
"median": deltas[len(deltas) // 2] if deltas else None,
"max": deltas[-1] if deltas else None,
},
}
return {
"baseline": BASELINE,
"switches": switches,
"pairwise": pairwise,
"threshold": G5_THRESHOLD,
"any_above_threshold": any(item["share"] > G5_THRESHOLD for item in switches.values())
or any(item["share"] > G5_THRESHOLD for item in pairwise.values()),
"cases": rows,
}
def run() -> dict:
cases = _cases()
precheck = same_day_precheck(cases)
noise = g5(cases)
return {
"scope": "d60_two_way_g2_g5",
"task": "docs/tasks/TASK-rectification-d60-two-way-20261028.md",
"fix_brief": "docs/tasks/TASK-rectification-d60-t5-fix-20261029.md",
"issue": 149,
"bug": "BUG-1497",
"preregistration": "docs/research/d60_two_way_preregistration_2026_10_28.json",
"dataset": {
"path": DATASET.relative_to(ROOT).as_posix(),
"sha256": hashlib.sha256(DATASET.read_bytes()).hexdigest(),
"cases": len(cases),
},
"g2_precheck": precheck,
"g3": {
"verdict": "trivially_equal",
"reason": "B adds no elimination, so the delivered range equals A and truth-in-range cannot drop",
},
"g4": {"verdict": "not_applicable", "reason": "no B-minus-A lift exists to test against placebos"},
"g5": noise,
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--json", action="store_true")
parser.add_argument("--out", default=None)
args = parser.parse_args()
payload = run()
text = json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
if args.json:
print(text, end="")
return 0
out = Path(args.out) if args.out else DEFAULT_OUT
out.write_text(text, encoding="utf-8", newline="\n")
print(out.relative_to(ROOT).as_posix())
return 0
if __name__ == "__main__":
raise SystemExit(main())
+145
View File
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
"""G1: compare the production D60 ascendant with an external engine (issue #149).
For every case of the v5 minute-rectification holdout this prints the D60
(rashi) sign of the ascendant from the production mapping and from PyJHora's
traditional Parasara shashtyamsa chart. The gate in
docs/tasks/TASK-rectification-d60-two-way-20261028.md asks for >=95% agreement
with at least one external engine; after BUG-1500 both count from the sign
itself and the expected result is 77/77.
The output is deterministic: no timestamps, sorted keys, fixed formatting, so
a rerun on another machine can be compared byte for byte.
Usage:
python scripts/research/d60_two_way_run.py # writes the results JSON
python scripts/research/d60_two_way_run.py --json # prints it to stdout
PyJHora is AGPL; it is imported here only, never copied into production code.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
SCRIPTS = ROOT / "scripts"
if str(SCRIPTS) not in sys.path:
sys.path.insert(0, str(SCRIPTS))
from scripts.jyotish_engine import compute_chart_data # noqa: E402
DATASET = ROOT / "references/real_case_calibration/minute_rectification_holdout_v5.json"
DEFAULT_OUT = ROOT / "docs/research/d60_two_way_results_2026_10_29.json"
GATE_RATE = 0.95
def _cases() -> list[dict]:
return json.loads(DATASET.read_text(encoding="utf-8"))["cases"]
def our_d60_ascendant(case: dict) -> tuple[float, int]:
birth = case["birth"]
year, month, day = (int(part) for part in birth["date"].split("-"))
hour, minute = (int(part) for part in birth["time"].split(":"))
chart, _asc_idx, _jd, _ayanamsa = compute_chart_data(
year,
month,
day,
hour,
minute,
birth["latitude"],
birth["longitude"],
birth["timezone_offset"],
node_mode="mean",
ayanamsa_name="raman",
)
import varga
longitude = float((chart.get("ascendant") or {})["degree_raw"])
return longitude, int(varga.calc_varga(longitude, 60)["sign_idx"])
def pyjhora_d60_ascendant(case: dict) -> int:
from jhora import utils
from jhora.horoscope.chart import charts
from jhora.panchanga import drik
birth = case["birth"]
year, month, day = (int(part) for part in birth["date"].split("-"))
hour, minute = (int(part) for part in birth["time"].split(":"))
drik.set_ayanamsa_mode("Raman")
jd = utils.julian_day_number((year, month, day), (hour, minute, 0))
place = drik.Place("case", birth["latitude"], birth["longitude"], birth["timezone_offset"])
chart = charts.divisional_chart(jd, place, divisional_chart_factor=60)
lagna = next(item for item in chart if str(item[0]) == "L")
return int(lagna[1][0])
def run() -> dict:
rows = []
for case in _cases():
longitude, ours = our_d60_ascendant(case)
theirs = pyjhora_d60_ascendant(case)
rows.append(
{
"case_id": case["case_id"],
"ascendant_longitude": round(longitude, 6),
"d60_sign_idx_production": ours,
"d60_sign_idx_pyjhora": theirs,
"matches_pyjhora": ours == theirs,
}
)
matches = sum(row["matches_pyjhora"] for row in rows)
count = len(rows)
return {
"scope": "d60_gate_g1_engine_reconciliation",
"task": "docs/tasks/TASK-rectification-d60-two-way-20261028.md",
"brief": "docs/tasks/TASK-rectification-d60-fix-20261029.md",
"issue": 149,
"bug": "BUG-1500",
"dataset": {
"path": DATASET.relative_to(ROOT).as_posix(),
"sha256": hashlib.sha256(DATASET.read_bytes()).hexdigest(),
"cases": count,
},
"profile": {
"ayanamsa": "raman",
"node_mode": "mean",
"pyjhora_ayanamsa_mode": "Raman",
"pyjhora_chart": "divisional_chart(divisional_chart_factor=60), traditional Parasara from sign",
},
"gate": {
"threshold": GATE_RATE,
"matches": matches,
"rate": round(matches / count, 4) if count else None,
"passed": bool(count) and matches / count >= GATE_RATE,
},
"cases": rows,
}
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--json", action="store_true", help="print instead of writing the default path")
parser.add_argument("--out", default=None)
args = parser.parse_args()
payload = run()
text = json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
if args.json:
print(text, end="")
return 0
out = Path(args.out) if args.out else DEFAULT_OUT
out.write_text(text, encoding="utf-8", newline="\n")
print(out.relative_to(ROOT).as_posix())
return 0
if __name__ == "__main__":
raise SystemExit(main())
+5 -2
View File
@@ -33,8 +33,11 @@ MINUTE_STEP = 1
# 原值: docs/research/reported_offset_upstream_sync8_2026_10_18.{freeze.json,json}
# 新值: docs/research/reported_offset_upstream_sync9b_2026_10_28.{freeze.json,json}
# 原因: sync9b(BUG-1494~1495)改了 scripts/varga.py,它在扩展身份里;报时窗口输出不变,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/reported_offset_upstream_sync9b_2026_10_28.freeze.json"
REPORT = ROOT / "docs/research/reported_offset_upstream_sync9b_2026_10_28.json"
# 原值: docs/research/reported_offset_upstream_sync9b_2026_10_28.{freeze.json,json}
# 新值: docs/research/reported_offset_d60_mapping_2026_10_29.{freeze.json,json}
# 原因: BUG-1500 修正生产 D60 映射,scripts/varga.py 变了(在扩展身份里);900 条回放不变,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/reported_offset_d60_mapping_2026_10_29.freeze.json"
REPORT = ROOT / "docs/research/reported_offset_d60_mapping_2026_10_29.json"
LEGACY_REPORT = ROOT / "docs/research/reported_offset_2026_09_20.json"
+5 -2
View File
@@ -30,8 +30,11 @@ DATASET = ROOT / "references/real_case_calibration/minute_rectification_holdout_
# 原值: docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.{freeze.json,json}
# 新值: docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.{freeze.json,json}
# 原因: sync9b(BUG-1494~1495)改了 scripts/varga.py,它在扩展身份里;切盘输出不变,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.freeze.json"
REPORT = ROOT / "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json"
# 原值: docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.{freeze.json,json}
# 新值: docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.{freeze.json,json}
# 原因: BUG-1500 修正生产 D60 映射,scripts/varga.py 变了(在扩展身份里);20 条回放不变,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.freeze.json"
REPORT = ROOT / "docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29.json"
LEGACY_REPORT = ROOT / "docs/research/sealed_holdout_rerun_2026_09_20.json"
ARCHIVE = ROOT / "docs/research/history/rectification_pre_cross_midnight_2026_09_20"
PRODUCTION_FILES = [
+3 -1
View File
@@ -90,7 +90,9 @@ def varga_map(si, pi, div):
if div==30: return _d30_map(si,pi)
if div==40: return ((0 if o else 6)+pi)%12
if div==45: return ((0 if o else 6)+pi)%12
if div==60: return (si+pi)%12 if o else (si+1+pi)%12
# D60 Shashtyamsa: every sign counts from itself (references/shodasavarga-complete-guide.md;
# PyJHora traditional Parasara "from sign" agrees 77/77 on the v5 recorded times, BUG-1500).
if div==60: return (si+pi)%12
if div==81:
outer_part = pi // 9
inner_part = pi % 9
+65
View File
@@ -0,0 +1,65 @@
"""G2 precheck and G5 noise floor for the D60 study (issue #149).
The committed results file must be reproducible byte for byte from the script;
the fast checks below verify the summary against the per-case rows without
touching the ephemeris.
"""
from __future__ import annotations
import json
from pathlib import Path
from scripts.research.d60_two_way_g2_g5 import (
DATASET,
DEFAULT_OUT,
ALTERNATIVES,
same_day_precheck,
)
ROOT = Path(__file__).resolve().parents[1]
def _committed() -> dict:
return json.loads(Path(DEFAULT_OUT).read_text(encoding="utf-8"))
def test_same_day_precheck_matches_the_committed_file() -> None:
committed = _committed()
live = same_day_precheck()
assert live["cases_with_same_day_events"] == committed["g2_precheck"]["cases_with_same_day_events"] == 0
assert live["same_day_events"] == committed["g2_precheck"]["same_day_events"] == 0
assert committed["g2_precheck"]["verdict"] == "not_evaluable_by_construction"
def test_g5_summary_matches_the_committed_rows() -> None:
committed = _committed()
rows = committed["g5"]["cases"]
assert len(rows) == committed["dataset"]["cases"] == 77
for mode in ALTERNATIVES:
changed = sum(1 for row in rows if row[f"d60_{mode}"] != row[f"d60_raman"])
assert committed["g5"]["switches"][f"raman_to_{mode}"]["changed_cases"] == changed
for key, switch in committed["g5"]["pairwise"].items():
left, right = key.split("_to_")
changed = sum(1 for row in rows if row[f"d60_{left}"] != row[f"d60_{right}"])
assert switch["changed_cases"] == changed, key
assert committed["g5"]["any_above_threshold"] is True
def test_payload_has_no_recorded_birth_times() -> None:
payload = _committed()
assert "true_minute" not in json.dumps(payload["g5"]["cases"])
for row in payload["g5"]["cases"]:
assert set(row) == {"case_id", "d60_raman", "d60_lahiri", "d60_kp", "d60_true_citra",
"ayanamsa_offset_arcminutes_raman", "ayanamsa_offset_arcminutes_lahiri",
"ayanamsa_offset_arcminutes_kp", "ayanamsa_offset_arcminutes_true_citra",
"changes_lahiri", "changes_kp", "changes_true_citra"}
def test_results_file_is_reproducible_byte_for_byte() -> None:
from scripts.research import d60_two_way_g2_g5 as module
payload = module.run()
text = json.dumps(payload, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
assert text == Path(DEFAULT_OUT).read_text(encoding="utf-8")
assert Path(DATASET).is_file()
+24
View File
@@ -0,0 +1,24 @@
"""G1 contract for the D60 two-way study (issue #149, BUG-1500).
The gate compares the production D60 ascendant with PyJHora for every v5 case.
It must agree on all of them now that both count from the sign itself; the
payload must stay free of recorded birth times so it can be published.
"""
from __future__ import annotations
import pytest
def test_g1_agrees_with_pyjhora_on_every_v5_case() -> None:
pytest.importorskip("jhora.horoscope.chart.charts")
from scripts.research.d60_two_way_run import run
payload = run()
assert payload["dataset"]["cases"] == 77
assert payload["gate"]["matches"] == 77
assert payload["gate"]["passed"] is True
for row in payload["cases"]:
assert row["matches_pyjhora"] is True
assert "true_minute" not in row
assert "birth_time" not in row
+36
View File
@@ -0,0 +1,36 @@
"""D60 Shashtyamsa counts from the sign itself for every sign (BUG-1500).
The production mapping used to add one sign for 1-based even signs, which put
the same ascendant one D60 sign away from PyJHora on 44 of 77 recorded times.
The guide (references/shodasavarga-complete-guide.md) and PyJHora both count
from the sign itself, odd and even alike.
"""
from __future__ import annotations
import pytest
from scripts.varga import calc_varga
def test_d60_first_part_starts_in_its_own_sign() -> None:
for sign in range(12):
for part in range(60):
longitude = sign * 30 + part * 0.5 + 0.25
assert calc_varga(longitude, 60)["sign_idx"] == (sign + part) % 12, (sign, part)
@pytest.mark.parametrize("sign", [1, 3, 5, 7, 9, 11])
def test_d60_even_signs_first_part_is_the_same_sign(sign: int) -> None:
# 1-based even signs: Taurus, Cancer, Virgo, Scorpio, Capricorn, Pisces.
result = calc_varga(sign * 30 + 0.25, 60)
assert result["sign_idx"] == sign
def test_d60_matches_pyjhora_shashtyamsa_for_all_signs_and_parts() -> None:
charts = pytest.importorskip("jhora.horoscope.chart.charts")
for sign in range(12):
for part in range(60):
degree = part * 0.5 + 0.25
their = int(charts.shashtyamsa_chart([["L", [sign, degree]]])[0][1][0])
assert calc_varga(sign * 30 + degree, 60)["sign_idx"] == their, (sign, part)
@@ -58,6 +58,11 @@ IDENTITY_FORBIDDEN_PREFIXES = (
# 原因: sync9b 改了扩展身份里的 scripts/varga.py,回放输出不变,ERR-110 另存新记录
"docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28",
"docs/research/reported_offset_upstream_sync9b_2026_10_28",
# 原值: 排除到 upstream_sync9b_2026_10_28
# 新值: 再排除 d60_mapping_2026_10_29 两份冻结路径(追加,不替换上面的)
# 原因: BUG-1500 修正生产 D60 映射,varga.py 变了,回放输出不变,ERR-110 另存新记录
"docs/research/sealed_holdout_rerun_d60_mapping_2026_10_29",
"docs/research/reported_offset_d60_mapping_2026_10_29",
"docs/research/history/",
"artifacts/",
)