Compare commits

...
Author SHA1 Message Date
jesse-uxandGrok (agent loop) cbe665107f test(freeze-guard): keep the sync8 freeze paths in the forbidden list (issue #159)
The sync9b edit replaced the two sync8 entries in
IDENTITY_FORBIDDEN_PREFIXES instead of appending after them, so the guard
covered two records instead of four while still passing. Restore the
sync8 pair under its own comment and keep the sync9b pair after it.

The freshness test passes again (9) and the frontend confirmation-gate
test for the moved sealed report passes (8).

Co-Authored-By: Grok (agent loop)
2026-10-28 17:01:31 +08:00
Jesse_ChenandClaude 8015e8efb7 docs(tasks): upstream sync 9 batch B first rejection (agent loop, issue #159)
The freshness test's IDENTITY_FORBIDDEN_PREFIXES list is append-only;
the branch replaced the two sync8 entries instead of adding the sync9b
ones after them, which weakens the identity guard. Restore them.

Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
2026-10-28 16:47:37 +08:00
jesse-uxandGrok (agent loop) 5c5f333d4d fix(varga): port the five sarpa ranges and the 22nd drekkana house (BUG-1494, BUG-1495, issue #159)
Upstream 50847e57, ported semantically:

- Sarpa Drekkana now accepts the five classical ranges (Cancer 2/3,
  Scorpio 1/2, Pisces 3) and partitions on the raw longitude instead of
  the rounded display degrees.
- The 22nd Drekkana is the eighth house of D3 (+7), not +21 zodiacal
  ten-degree divisions.

scripts/varga.py is part of the extended frozen identity, so the sealed
holdout and the reported-offset sweep were re-frozen under ERR-110:
20/20 sealed trials and 900/900 sweep trials match the sync8 records on
every compared field, and the metrics, summary and widening geometry are
unchanged.

Tests: the upstream varga/ sarpa files are added under
tests/test_upstream_sync9b_*.py; the stale +21 assertion and the sarpa
definition string are updated with the original/new/reason columns in
PROGRESS.

Co-Authored-By: Grok (agent loop)
2026-10-28 16:25:45 +08:00
Jesse_ChenandClaude 2243220841 docs(tasks): upstream sync 9 batch B brief (agent loop, issue #159)
Product chose A on #159: change the frozen varga.py for the five Sarpa
drekkanas and the 22nd drekkana, and refreeze only on identical 20/900
rectification scores. Narayana AD strength (B2) is deferred: our code
has no strength-profile family for it to propagate.

Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
2026-10-28 15:46:21 +08:00
22 changed files with 45374 additions and 137 deletions
+7
View File
@@ -1,5 +1,12 @@
# 印度占星 Skill 更新日志
## 2026-10-28 — 两处分盘敏感点按来源修正
- Sarpa Drekkana 从三段补成书上的五段:巨蟹第 3 段、天蝎第 2 段以前漏掉,现在会标出来;正好落在 10 度边界上的盘不再划到上一段。
- 第 22 号 Drekkana 改为 D3 的第 8 宫(以前多移了 14 个星座)。这个点目前还没接进完整解读的敏感点表,所以报告上看不到差别。
- 生时校正 20 条密封案例与 900 个报时窗口,名次与分钟误差与上一份回放逐条相同。
- Skill 版本不变(BUG-1494、BUG-1495,issue #159)。
## 2026-10-28 — 两人同时做校正或生成报告时不再互相拖慢
- 排盘服务把最重的三类计算(生时校正打分、24 小时分块扫描、长报告参考)放到两个独立的工作进程里。两个人同时算时,各自的等待时间和一个人单独算差不多(以前接近翻倍)。结果不变。
+31
View File
@@ -20416,3 +20416,34 @@
- 关联:ERR-111(特征指纹随哈希种子变)、BUG-1482(#132 让模块能按名字被子进程找到)。
- 复发自:无
- 修复版本:分支 `codex/heavy-compute-processes-20261028`。
## BUG-1494 | Sarpa Drekkana 少两段,边界还按四舍五入后的度数判段
- 状态:resolved(代码 + 回归测试;待部署)
- 首次发现 / 最近更新:2026-10-28 / 2026-10-28(issue #159,上游 `50847e57`)
- 影响面:完整解读里的 Sarpa Drekkana 标记。`scripts/varga.py`。
- 现象:只认 Cancer-2、Scorpio-1、Pisces-3 三段。Raman《Hindu Predictive Astrology》Drekkana 章是五段,Cancer-3 与 Scorpio-2 漏掉。判段还先把星座内度数四舍五入到 4 位再整除,边界附近会划到上一段。
- 触发条件:行星或上升落在被漏掉的两段,或经度正好在 10 度边界附近(如 100.0、220.0、360.0)。
- 根因:`SARPA_DREKKANA_SIGNS` 一个星座只记一个段号;`int(round(deg,4)/10)+1` 让 99.99999 与 100.0 之类的边界口径不稳。
- 修复:每星座改成段号元组(Cancer 2/3、Scorpio 1/2、Pisces 3),用原始经度 `int((lon % 30) / 10) + 1` 判段,`definition` 改成五段文字。生时校正不读这两个函数。
- 验证:`tests/test_upstream_sync9b_sarpa_precision.py`(6 条边界参数化)、`tests/test_upstream_sync9b_varga_bphs.py`(36 段全枚举与五段区间断言)、`tests/test_varga_bphs.py` 通过。密封校正 20 条与报时窗口 900 条与上一份记录逐条相同。
- 防复发:36 段全枚举 + 区间边界测试;判段只用原始经度,不再用显示用的四舍五入度数。
- 关联:BUG-1495。
- 复发自:无。
- 修复版本:分支 `codex/upstream-sync9b-20261028`。
## BUG-1495 | 第 22 号 Drekkana 按 21 个十度分段取,多移了 14 个星座
- 状态:resolved(代码 + 回归测试;待部署)
- 首次发现 / 最近更新:2026-10-28 / 2026-10-28(issue #159,上游 `50847e57`)
- 影响面:`scripts/varga.py::calc_22nd_drekkana`。全仓只有单元测试直接调用它;完整解读的敏感点表目前没有生产者写 `drekkana_22nd`(`_calc_sensitive_points` 只产 bhrigu_bindu 与 sarpa_drekkana),所以这一项目前不会出现在报告里。这是既有接线缺口,本单不接线,也不把「注册了」写成「已计算」。
- 现象:结果取 D3 星座 +21。《Crux of Vedic Astrology》p.329:第 22 号 Drekkana 是 D3 的第 8 宫,即 +7。
- 触发条件:调用 `calc_22nd_drekkana`。
- 根因:把「在黄道上数 21 个十度分段」当成「在 D3 里移 21 个星座」。
- 修复:改 `+7`;`offset_from_lagna_drekkana` 仍是 22,输出字段名不变。
- 验证:`tests/test_upstream_sync9b_varga_bphs.py` 的固定反例(射手 D3 起,第 8 宫为巨蟹)与 36 段独立枚举(不调用生产偏移)通过;`tests/test_varga_bphs.py` 同步改成固定反例。密封 20 条 + 报时 900 条与上一份记录逐条相同。
- 防复发:独立枚举测试用「数满 22 个十度分段再映射 D3」的旁路口径,不复用生产公式。
- 关联:BUG-1494。
- 复发自:无。
- 修复版本:分支 `codex/upstream-sync9b-20261028`。
@@ -0,0 +1,118 @@
{
"record_version": "reported-offset-native-candidate-date-v3",
"frozen_at_utc": "2026-10-28T08:19:09.924155+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": "b44505aa0034e486fcfc29c8611a9559333a97c1005f92e6a5356bd855122205",
"implementation_sha256_prefix": "b44505aa0034e486",
"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": "7a727418651321d1b9073588587050c4dc6292587748cf35734dd76cefb0effe",
"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": "6fa0b0c335ac0cdc25ee887d432ae2f1f6487c665aed9665ad5cc0bc6ef0283b",
"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": "8ecc381dfaa3c0e6bea058cfa44c606aabdb1086c137f16da82ee5a3bf5ccc91",
"scripts/research/sealed_holdout_rerun.py": "ebcdae760f2b76c81d5d0c8e2bf347cff4c81cca9074f27ae94b6734408ccd42",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "8ff96b9fc8346ca249abff6109434b6ed57fa150e1a9854d4f73bdf317568368"
},
"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": "8ecc381dfaa3c0e6bea058cfa44c606aabdb1086c137f16da82ee5a3bf5ccc91",
"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": "7a727418651321d1b9073588587050c4dc6292587748cf35734dd76cefb0effe",
"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": "6fa0b0c335ac0cdc25ee887d432ae2f1f6487c665aed9665ad5cc0bc6ef0283b",
"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": "8ecc381dfaa3c0e6bea058cfa44c606aabdb1086c137f16da82ee5a3bf5ccc91",
"scripts/research/sealed_holdout_rerun.py": "ebcdae760f2b76c81d5d0c8e2bf347cff4c81cca9074f27ae94b6734408ccd42",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "8ff96b9fc8346ca249abff6109434b6ed57fa150e1a9854d4f73bdf317568368"
},
"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-28T08:19:06.008600+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": "b44505aa0034e486fcfc29c8611a9559333a97c1005f92e6a5356bd855122205",
"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": "ebcdae760f2b76c81d5d0c8e2bf347cff4c81cca9074f27ae94b6734408ccd42",
"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,45 @@
# 22nd Drekkana: division count versus D3 house count
## Source
- `references/book_corpus/books/Crux of Vedic Astrology – Timing of Events (Sanjay Rath) (z-library.sk, 1lib.sk, z-lib.sk).md`
- Topic: 22nd Drekkana geometry. Corpus page 340, printed page 329.
- Lines 13809–13812: `house on the physical body. Incidentally, the 22nd`
`decanate is also the 8th house in the Drekkana`
`(D-3) chart while the 64th Navamsa is the 4th`
`house from the Moon in the Navamsa chart. The`
- Located by full-corpus search and read using `search_jyotish_books.py --read-unit 340`.
- This review verifies a traditional geometric definition, not health or lifespan prediction.
## Defect and correction
The producer added 21 to the D3 sign index. That confuses a count of zodiacal
ten-degree divisions with a count of signs in the divisional chart. Use D3
ascendant +7 modulo12, the eighth house inclusive.
The old test repeated the same +21 error. Replace it with a fixed Sagittarius
to Cancer counterexample and an independent 36-part zodiac enumeration. Across
each part, count 22 inclusively on the original zodiac, then apply the standard
Parashari D3 mapping to the resulting part. Test starts, interiors and ends.
The 64th Navamsa formula is unchanged: D9 Moon +63 modulo12 equals its fourth
house, as the same source states. `offset_from_lagna_drekkana=22` is an ordinal
label, not the number of D3 signs added.
No customer information is retained here. Recompute sensitive-point consumers
and use a new verified frozen pin before claiming the published report changed.
## Sarpa classification: missing two divisions
Raman, `Hindu Predictive Astrology -- Bangalore Venkat Raman, B V Raman -- 1981 -- IBH Prakashana -- isbn13 9788119394883 -- c9102b89e2f8f7c358a913f7d07d7c39 -- Anna’s Archive.md`:
- Corpus p.279, L10960–10962 explicitly counts five serpent divisions.
- Cancer second and third: p.280, L11013–11020.
- Scorpio first and second: pp.281–282, L11062–11074.
- Pisces third: p.283, L11129–11131.
- Search used `search_jyotish_books.py serpent --book <registered filename>`.
The old map accepted one division per sign and omitted Cancer-3 and Scorpio-2.
It now allows multiple divisions per sign. Independent tests cover all 36
divisions and their boundaries against the source's three degree intervals.
This classifies chart geometry; it does not establish a medical outcome.
@@ -0,0 +1,68 @@
# PROGRESS · 上游同步第九轮乙批(2026-10-28)
- 分支:`codex/upstream-sync9b-20261028`;基线 `origin/staging` `12eb7018`
- issue:#159(#141 乙批);产品 10-28 选 **A**:允许改冻结文件 `scripts/varga.py`
- 上游:`732642856/yinduzhanxing` main `50847e57`(10-16),按语义移植
- 结论:B1 两项完成;密封校正 20 条与报时窗口 900 条与上一份记录逐条相同,已按 ERR-110 另存新冻结;B2(Narayana 小运强度口径)按决策记录不做
## 做了什么
| 项 | 上游 | BUG | 改了什么 |
| --- | --- | --- | --- |
| T1 Sarpa 五段 + 原始经度判段 | `50847e57` | BUG-1494 | `SARPA_DREKKANA_SIGNS` 由单段号改段号元组;`calc_sarpa_drekkana` 去掉四舍五入、先取模;`definition` 改五段 |
| T2 第 22 号 Drekkana 改 D3 第 8 宫 | `50847e57` | BUG-1495 | `calc_22nd_drekkana` 由 `+21` 改 `+7`,字段名与序号 22 不变 |
| T4 上游配套文档 | `50847e57` | — | 原路径放入 `docs/research/sensitive_point_drekkana_count_review_2026_10_14.md` |
| T3 重新冻结 | — | — | 两份新冻结记录 + 两份回放报告(ERR-110),旧记录逐字节保留 |
生产文件只有 `scripts/varga.py` 一个;`git diff --stat` 见下。
## 与任务书的偏离
1. **红线 2 的「先不带 `--freeze` 跑」做不到**:`scripts/varga.py` 在冻结记录的扩展身份里,拿 sync8 的冻结记录回放会在打分前被身份闸门拦下(`frozen_record_mismatch:extended_identity`)。改成 ERR-110 的做法:仓库内建临时冻结记录 → 回放 → 与 sync8 逐条比 → 全部相同后才写正式记录。临时记录 `docs/research/.tmp_sweep_sync9b.freeze.json` 用完已删除,未提交。
2. **报时窗口脚本必须用仓库内路径**:报告里写 `freeze_record_path`(`relative_to(ROOT)`),所以正式记录直接放 `docs/research/`;比较轮的临时记录也在仓库内。
3. **改了前端一个测试文件**:`frontend/tests/rectification-confirmation-gate.test.ts` 写死当前密封报告路径,合同指针一挪就会红。只改这个路径与三栏注释,不动任何产品代码;与第八轮同做法的先例一致。
## 跑过的命令
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 上游两个测试文件 | `.venv\Scripts\python -m pytest tests/test_upstream_sync9b_varga_bphs.py tests/test_upstream_sync9b_sarpa_precision.py -o addopts="" -q` | 23 passed |
| 既有分盘测试一起 | 上一行再加 `tests/test_varga_bphs.py` | 39 passed |
| CLI 敏感点(任务书写 `-k "sarpa or drekkana or special"`) | `.venv\Scripts\python -m pytest tests/test_cli_smoke.py -k "sarpa or drekkana or special"` | 0 条被选中(35 deselected,退出码 5);`-k` 只匹配测试名,改用实际测试名 `-k sensitive_point_modules`:1 passed、34 deselected |
| 分盘 + CLI 敏感点合并 | 4 个文件/节点一起跑 | 40 passed |
| 密封校正 20 条 | `scripts/research/sealed_holdout_rerun.py`(新冻结记录) | `trial_count` 20;8 个字段(`true_rank`、`opaque_true_rank`、`minute_error`、`would_confirm`、`false_confirmation`、`insufficient_evidence_rejected`、`candidate_count`、`event_count`)不一致 0;`metrics` 相同;`changed_trial_count` 仍是 8 |
| 报时窗口 900 条 | `scripts/research/reported_offset_sweep.py --json`(新冻结记录) | `trial_count` 900;trial 全字段不一致 0;`summary` 与 `widening_geometry` 相同;`changed_trial_count` 仍是 581 |
| 冻结契约 | `tests/test_sealed_holdout_contract_freshness.py` | 9 passed |
| 确认门合同 | `tests/test_rectification_confirmation_and.py` | 10 passed |
| 其余分盘测试 | `pytest tests/test_varga*.py` | 53 passed、9 failed;9 条全在 `test_varga_vedastro_mode.py`(D2 起 Ascendant 星座不符)。在基线 `12eb7018` 的一次性工作树上同样 9 failed,与 Sarpa / 22nd 无关,不算本单 |
| 正式记录生成 | `scripts/research/*.py --freeze` 两份 + 回放两份 | `sealed_holdout_rerun_upstream_sync9b_2026_10_28.{freeze.json,json}`、`reported_offset_upstream_sync9b_2026_10_28.{freeze.json,json}` |
Python 快速门、前端 tsc / lint / build、`npm test`、`test:db` 没跑:没有改前端产品代码,没有动表。
## 断言三栏
| 位置 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| `tests/test_varga_bphs.py::test_22nd_drekkana_counts_forward_from_lagna_drekkana` | `expected = (drekkana_ref(asc_lon) + 21) % 12` | 固定 `3`(巨蟹),保留 `offset_from_lagna_drekkana == 22` | 旧断言把「+21」的错口径抄进了测试;换成书上的固定反例(射手 D3 起,第 8 宫为巨蟹) |
| `tests/test_cli_smoke.py::test_full_reading_exposes_sensitive_point_modules` | `definition == "Cancer-2, Scorpio-1, Pisces-3"` | `definition == "Cancer-2, Cancer-3, Scorpio-1, Scorpio-2, Pisces-3"` | BUG-1494 改的就是这个定义字符串;仍逐字比对,没有放宽 |
| `tests/test_sealed_holdout_contract_freshness.py` 排除前缀 | 排除到 `upstream_sync8_2026_10_18` | 新增 `upstream_sync9b_2026_10_28` 两条,原有条目全部保留 | ERR-110 另存新冻结,旧记录留在清单外;第 1 次打回时补回被误删的 sync8 两条 |
| `frontend/tests/rectification-confirmation-gate.test.ts` 读取与断言路径 | `…upstream_sync8_2026_10_18.json` | `…upstream_sync9b_2026_10_28.json` | 合同当前指针移到新报告;注释补第 11 条三栏 |
| `scripts/research/sealed_holdout_rerun.py`、`reported_offset_sweep.py` 的 `FREEZE` / `REPORT` | `…upstream_sync8_2026_10_18` | `…upstream_sync9b_2026_10_28` | 同上,ERR-110 |
## 发现但没改
- 完整解读的敏感点表没有 `drekkana_22nd` 的生产者:`_calc_sensitive_points` 只产 `bhrigu_bindu` 与 `sarpa_drekkana`。所以第 22 号 Drekkana 修好后,报告里暂时看不到变化;这是既有接线缺口,本单不接线(也不把「有函数」写成「报告里已计算」)。
- `frontend/tests/fixtures/report-density-fictional-engine.json` 里还有两处旧 `definition` 字符串。它是前端 fixture,本单不改前端产品代码,留给前端轮次或验收方判断。
## 环境缺口
- Windows 跑 Python 测试要 `PYTHONUTF8=1`,否则子进程按 GBK 编码,遇到警告符号会 `UnicodeEncodeError`,看起来像引擎崩了。
- 前端测试没跑(任务书不要求,且本单没改前端产品代码)。
## 第 1 次打回(2026-10-28)
- 被验 SHA:`5c5f333d4d93fb691c10790988d3d4c986ac1bd3`;修复单 `docs/tasks/TASK-upstream-sync9b-fix-20261028.md`
- 错在哪:改 `IDENTITY_FORBIDDEN_PREFIXES` 时把第八轮的两条**替换**掉了,清单从 4 条变成 2 条;测试照样通过,但守门变弱(第八轮的冻结记录混进打分身份也不会再被发现)
- 改了什么:把第八轮两条加回原来的注释下面,第九轮乙批两条保留 —— 现在清单同时含 sync8 与 sync9b 共 4 条;本文件「断言三栏」对应行改成「新增两条、原有全部保留」
- 跑过:`tests/test_sealed_holdout_contract_freshness.py` 9 passed;`frontend/tests/rectification-confirmation-gate.test.ts` 8 passed(`node node_modules/tsx/dist/cli.mjs --test tests/rectification-confirmation-gate.test.ts`,工作树里 `frontend/node_modules` 已存在,没有重跑 `npm ci`)
- 没有重跑上游两个测试文件和校正 20 / 900:本次不改计算代码
+1
View File
@@ -544,3 +544,4 @@
| — | `PROGRESS-session-shell-116-20261028.md` | **#116 侧栏会话菜单搬进外壳**:每个页面都能「…」和拖动(直接执行,BUG-1467) | 已推 staging | `codex/session-shell-116-20261027` |
| `TASK-home-crash-saved-people-20261027.md` | `PROGRESS-home-crash-saved-people-20261027.md` | **#115 首页崩溃**:存过别人的账户一进首页就「页面出错了」——人物列表的资料缺两个字段,启程引导一读就报错;入口补齐默认值(BUG-1464) | 待验收 | `codex/home-crash-saved-people-20261027` |
| `TASK-upstream-sync9-20261028.md` | `PROGRESS-upstream-sync9-20261028.md` | **第 1 次打回(快速门 1 败:Darakaraka 旧测试锁错值,见 `TASK-upstream-sync9-fix-20261028.md`)** · **#141 上游同步第九轮**:甲批九项已做完并推 `codex/upstream-sync9-20261028`;校正 20 条和 900 条与上一份回放逐条相同;乙批仍等 #137 | 待验收 | `codex/upstream-sync9-20261028` |
| `TASK-upstream-sync9b-20261028.md` | `PROGRESS-upstream-sync9b-20261028.md` | **第 1 次打回(冻结契约排除清单删了第八轮两条,见 `TASK-upstream-sync9b-fix-20261028.md`)** · **#159 上游同步第九轮乙批(产品选 A)**:Sarpa Drekkana 补成五段、第 22 号 Drekkana 改为 D3 第 8 宫;改冻结文件 `varga.py`,校正 20 + 900 与上一份逐条相同后按 ERR-110 重新冻结。Narayana 小运强度口径(B2)不做,另问产品 | 待验收 | `codex/upstream-sync9b-20261028` |
@@ -0,0 +1,76 @@
# TASK · 上游同步第九轮乙批:Sarpa Drekkana 与第 22 号 Drekkana(2026-10-28)
- 日期:2026-10-28
- 来源:issue #159(#141 乙批)。产品 10-28 选 **A**:改冻结文件,生时校正 20 条 + 900 条分数逐条相同才重新冻结。
- 执行方:**Grok(Windows + Docker)**,分支 `codex/upstream-sync9b-20261028`,只推这个分支(本任务书就是该分支第一个提交)
- 验收:Claude(Linux)
- BUG 编号:开工时按 `docs/BUG_HISTORY.md` 全文件取最大号 +1(写作时 staging 最大号 BUG-1492;另一会话仍在占号,开工当时再核对)。本单预计 2 个号。
## 1. 基线
- 基线 commit:`origin/staging` `12eb7018`(#141 甲批与 #137 都已在其中)。
- 上游:`732642856/yinduzhanxing` main 的 `50847e57`(10-16)。按语义移植,不整文件覆盖。
## 2. 事故实证(上游测试放到 `12eb7018` 上跑)
| 项 | 上游测试结果 | 我方现状 | 来源 |
| --- | --- | --- | --- |
| B1a Sarpa Drekkana | `test_varga_bphs.py` 3 败 14 过;`test_sarpa_drekkana_precision.py` 4 败 2 过 | `scripts/varga.py::SARPA_DREKKANA_SIGNS` 只有 Cancer-2、Scorpio-1、Pisces-3 三段;`calc_sarpa_drekkana` 先把度数四舍五入到 4 位再算第几个 Drekkana,边界附近会划错 | Raman《Hindu Predictive Astrology》Drekkana 章:五段(Cancer-2、Cancer-3、Scorpio-1、Scorpio-2、Pisces-3) |
| B1b 第 22 号 Drekkana | 同上 | `scripts/varga.py::calc_22nd_drekkana` 取 D3 星座 +21 | 《Crux of Vedic Astrology》p.329:是 D3 的第 8 宫,即 +7。数 21 个十度分段 ≠ 在 D3 里移 21 个星座 |
下游:`jyotish_engine.py` 完整解读的特殊点(`calc_sarpa_drekkana`)→ 前端报告事实表 `report-fact-tables.ts` 的 Sarpa Drekkana 行;第 22 号 Drekkana 进完整解读的敏感点。
## 3. 根因
前八轮同步与 #141 甲批都没有取上游 main 10-16 的这一提交(#141 甲批因冻结文件把它留到乙批)。
## 4. 决策记录
1. **产品 10-28 在 #159 选 A**:允许改冻结文件 `scripts/varga.py`;改完跑生时校正 20 条 + 900 条,**逐条相同**才重新冻结为 `upstream_sync9b_2026_10_28`,沿用第八轮 `79f6ac52` 的做法。有任何一条不同:停,不重新冻结,回报「需拍板」。
2. **B2(Narayana 小运强度口径)本单不做。** 规划时核实:上游 `6859b263` 只是把已选的 `strength_profile` 往下传,但这个强度口径家族(`rath_*`、`pvr_*` 等)来自上游 09-27 的 `5b57949c`,我方从未移植;默认口径下结果不变。是否移植整套口径另由产品决定(已在 #159 说明)。
3. 用户可见变化已知并接受:部分盘 Sarpa Drekkana 标记会多出来(Cancer 第 3、Scorpio 第 2 段);第 22 号 Drekkana 的星座会变。
## 5. 硬红线
1. 只改 `scripts/varga.py` 里 `SARPA_DREKKANA_SIGNS`、`calc_sarpa_drekkana`、`calc_22nd_drekkana` 三处;`varga.py` 其他函数逐字节不变(PROGRESS 贴 `git diff --stat` 与函数级 diff 说明)。
2. 生时校正 20 条(`scripts/research/sealed_holdout_rerun.py`)+ 900 条(`scripts/research/reported_offset_sweep.py --json`):先不带 `--freeze` 跑出结果、与 `docs/research/*upstream_sync8_2026_10_18.json` 逐条比;**全部相同**后才按脚本自带的 `--freeze` 写新冻结记录(不覆盖旧记录)。
3. 不改其他冻结文件;不改 `.gitea/workflows/**`、数据库、前端。
4. 上游断言数值不得放宽;接口名不同只改调用方式。
5. 公开仓库:测试只用公开或虚构出生资料。
## 6. 任务分解
| 任务 | 内容 | 验收标准 |
| --- | --- | --- |
| T1 | Sarpa 五段 + 不经四舍五入判段(`50847e57`) | 上游两个测试文件中 Sarpa 相关全过;`definition` 字段改为五段 |
| T2 | 第 22 号 Drekkana +7(`50847e57`) | 上游相关断言过;完整解读里该敏感点的字段名不变 |
| T3 | 校正回放与重新冻结(红线 2) | 20/20、900/900 相同;新 `.freeze.json` 两份 + 回放 JSON 两份;`tests/test_sealed_holdout_contract_freshness.py` 全过 |
| T4 | 上游配套文档 `docs/research/sensitive_point_drekkana_count_review_2026_10_14.md` 原路径放入;BUG_HISTORY 2 条、CHANGELOG、PROGRESS、`docs/tasks/README.md` 状态板 | — |
## 7. 让步顺序
T1、T3、T4 必做;T2 若与我方敏感点结构冲突,回报原因、不硬改。
## 8. 验收命令
| 检查 | Grok 自跑 | Claude 验收 |
| --- | --- | --- |
| 上游两个测试文件(放 `tests/test_upstream_sync9b_*.py`) | 必跑 | 复验 |
| `tests/test_varga*.py`、`tests/test_cli_smoke.py -k "sarpa or drekkana or special"`、`tests/test_sealed_holdout_contract_freshness.py` | 必跑 | 复验 |
| 校正 20 + 900 回放 | 必跑 | 复验 |
| 前端 `report-fact-tables.test.ts` | 不跑(未改前端) | 跑 |
| Python 快速门 | 不跑 | 以 Claude 为准 |
## 9. 开工前置命令
```
git fetch origin
git worktree add .worktrees/upstream-sync9b-20261028 codex/upstream-sync9b-20261028
python scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45
grep -o 'BUG-[0-9]\+' docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1
git fetch upstream main && git show 50847e57
```
## 10. 真机
`docs/testing/upstream-sync9b-20261028.md`。
@@ -0,0 +1,45 @@
# TASK · 上游同步第九轮乙批 · 第 1 次打回(2026-10-28)
- 原任务书:`docs/tasks/TASK-upstream-sync9b-20261028.md`(issue #159)
- 被验 SHA:`5c5f333d4d93fb691c10790988d3d4c986ac1bd3`(分支 `codex/upstream-sync9b-20261028`)
- 执行方:Grok,同一分支继续提交;不新开 BUG 号
## 1. 验收结果
| 检查 | 结果 |
| --- | --- |
| 回报 SHA 是分支最新提交,可快进到当前 `origin/staging` | 是 |
| `varga.py` 改动 | 与上游 `50847e57` 一致,只改了任务书点名的三处 |
| 上游测试 + `test_varga_bphs.py` + 冻结契约 + 敏感点冒烟(Linux) | 49 过 |
| 生时校正 20 条 + 900 条(Linux 复跑) | 与第八轮记录逐条相同 |
| 旧冻结记录 | 逐字节未动 |
| 两处偏离(临时记录回放、前端测试路径) | 认可,与第八轮做法一致 |
| 任务书里 `-k "sarpa or drekkana or special"` 选中 0 条 | 这是任务书写错了,你改用真实测试名是对的 |
## 2. 失败项:冻结契约测试的排除清单被删了两条
`tests/test_sealed_holdout_contract_freshness.py::IDENTITY_FORBIDDEN_PREFIXES` 这份清单历来是**追加**的(每次重新冻结都「再排除」新路径,旧路径留着)。本分支把第八轮的两条:
```
"docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18",
"docs/research/reported_offset_upstream_sync8_2026_10_18",
```
**替换**成了第九轮乙批的两条,第八轮那段注释还在、条目没了。这条测试守的是「冻结记录文件不能混进打分身份」,删掉以后第八轮的记录混进去也不会报错——测试仍然通过,但守门变弱了。
## 3. 要做的
1. 把上面两条第八轮路径加回去,放在原来那段注释下面;第九轮乙批两条保留在其后。即清单同时含第八轮与第九轮乙批共 4 条。
2. PROGRESS「断言三栏」这一行改写为「新增两条、原有全部保留」。
3. 跑 `tests/test_sealed_holdout_contract_freshness.py`,回报通过数。
4. 前端:在工作树 `frontend/` 里 `npm ci` 后跑 `npm test -- tests/rectification-confirmation-gate.test.ts`(或该仓等价的单文件命令),回报结果。
## 4. 验收命令
| 检查 | Grok 自跑 | Claude 验收 |
| --- | --- | --- |
| `tests/test_sealed_holdout_contract_freshness.py` | 必跑 | 复验 |
| `frontend/tests/rectification-confirmation-gate.test.ts` | 必跑 | 复验 |
| 上游两个测试文件、校正 20 + 900 | 不必重跑(本次不改代码) | 复验 |
完成后照旧回报新的 head SHA。
+9
View File
@@ -0,0 +1,9 @@
# 真机走查 · 上游同步第九轮乙批(issue #159)
用虚构或公开出生资料,在 staging 上看:
| # | 操作 | 应该看到 |
| --- | --- | --- |
| 1 | 生成一份完整报告,翻到特殊点 / 敏感点表 | Sarpa Drekkana 行正常显示;没有空白或「undefined」 |
| 2 | 同一张盘看第 22 号 Drekkana | 有星座,不报错 |
| 3 | 发起一次生时校正,走到出结果 | 和以前一样能走完(校正打分没有变) |
@@ -111,8 +111,11 @@ const diagnosticReport = JSON.parse(readFileSync(
// 原值(10):docs/research/sealed_holdout_rerun_scoring_perf_2026_10_13.json
// 新值(10):docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.json
// 原因(10):sync8(BUG-1380~1390)改了冻结身份文件,输出不变,ERR-110 另存新记录。确认门行为与阈值不变。
// 原值(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 另存新记录。确认门行为与阈值不变。
const currentTreeRerun = JSON.parse(readFileSync(
new URL("../../docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.json", import.meta.url),
new URL("../../docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json", import.meta.url),
"utf8",
)) as {
frozen_record: { implementation_sha256: string };
@@ -260,9 +263,10 @@ test("sealed holdout aggregates match the v3 report and still block confirmation
// 原值(7):…upstream_sync6_2026_10_07.json / 新值(7):…ephemeris_nutation_2026_10_08.json / 原因(7):章动修正与 scoring-12 重新冻结(ERR-110,BUG-1275)。
// 原值(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 另存新记录。
assert.equal(
productHoldout.current_tree_scorer.source_report,
"docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.json",
"docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.json",
);
assert.equal(currentTreeRerun.official_valid_independent_blind, false);
assert.equal(productHoldout.current_tree_scorer.matches_metrics_scorer, false);
+130 -115
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-18",
"evaluated_on": "2026-10-28",
"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": "bf8981b5c41702f9b333444deee2ab7378b9e98b111240e85ea62e6aae02fda8",
"implementation_sha256": "b44505aa0034e486fcfc29c8611a9559333a97c1005f92e6a5356bd855122205",
"extended_identity": {
"historical_artifacts_manifest_sha256": "6102a26a840be207b5858b3a4c0509274468ae9071e86d308cbbac7371d6864e",
"production_scoring_files": [
@@ -52,7 +52,7 @@
"scripts/shadbala.py",
"scripts/varga.py"
],
"production_scoring_sha256": "c2c23bcbde5de58e519ae1d6545620edd0f738ce8dc2e872e659b598137a728f",
"production_scoring_sha256": "7a727418651321d1b9073588587050c4dc6292587748cf35734dd76cefb0effe",
"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": "9df579bdacd7dec43abd92c9abc1831771feb800fc29e6864dc315d083d52a03",
"research_implementation_sha256": "6fa0b0c335ac0cdc25ee887d432ae2f1f6487c665aed9665ad5cc0bc6ef0283b",
"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": "e10537ca2caba3a4e6a8d2460265543b0cca55935afa8004108e45bef4bc3de7",
"scripts/research/sealed_holdout_rerun.py": "7945353014b93b6d7641f278779111d85b1773293781343b802a9b4b655ca4b5",
"scripts/research/reported_offset_sweep.py": "8ecc381dfaa3c0e6bea058cfa44c606aabdb1086c137f16da82ee5a3bf5ccc91",
"scripts/research/sealed_holdout_rerun.py": "ebcdae760f2b76c81d5d0c8e2bf347cff4c81cca9074f27ae94b6734408ccd42",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "c1f06967c3d4d214edadff139c24aa31e59fb628477174235abe14f799a99076"
"scripts/varga.py": "8ff96b9fc8346ca249abff6109434b6ed57fa150e1a9854d4f73bdf317568368"
},
"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_sync8_2026_10_18.json",
"source_report": "docs/research/sealed_holdout_rerun_upstream_sync9b_2026_10_28.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-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",
"implementation_sha256": "b44505aa0034e486fcfc29c8611a9559333a97c1005f92e6a5356bd855122205",
"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": "7a727418651321d1b9073588587050c4dc6292587748cf35734dd76cefb0effe",
"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": "6fa0b0c335ac0cdc25ee887d432ae2f1f6487c665aed9665ad5cc0bc6ef0283b",
"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": "8ecc381dfaa3c0e6bea058cfa44c606aabdb1086c137f16da82ee5a3bf5ccc91",
"scripts/research/sealed_holdout_rerun.py": "ebcdae760f2b76c81d5d0c8e2bf347cff4c81cca9074f27ae94b6734408ccd42",
"scripts/shadbala.py": "334dc9d8e4292f0c95d40fd4c29285aa89b9e49d4f187fb9498f4bb0ad93bdfc",
"scripts/varga.py": "8ff96b9fc8346ca249abff6109434b6ed57fa150e1a9854d4f73bdf317568368"
},
"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 sync9b (ERR-110, BUG-1494 to BUG-1495). Trials and metrics match the 2026-10-18 upstream sync8 report. Versus the 2026-09-20 historical report, changed_trial_count stays 8. Not a release metric. Prior sync8 report and freeze preserved byte-for-byte.",
"report_sha256": "ef20e751a746a4ec3b368d6860123602172a9af9195a97ec5f4d3c2cdf4823ce",
"freeze_record_sha256": "32cad06f25c84891a24725110c9737489b8d79ed7c2d33ae959cb8eb16798dab",
"replay_started_at_utc": "2026-10-28T08:19:06.261911+00:00",
"replay_finished_at_utc": "2026-10-28T08:19:09.621910+00:00",
"previous_fixed_protocol_rerun": {
"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",
"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",
@@ -212,106 +312,6 @@
"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."
}
},
"previous_fixed_protocol_rerun": {
"evaluated_on": "2026-10-03",
"report_path": "docs/research/sealed_holdout_rerun_astrologer_rulings_batch1_2026_10_03.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_astrologer_rulings_batch1_2026_10_03.freeze.json",
"implementation_sha256": "114c60c45fa35a77bb6bfe2c177bbcc90b2e0748e2a33e61975f7393802f96f2",
"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": "788745f7b7aba1d551a73a67a56daff3e730c1d408cd77dde155e410ad9d00bb",
"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": "fa74b52f52ca7beeb1c6c6647b11ef075c16bcb6fadb656196770d91004cd0ad",
"file_sha256": {
"scripts/active_rectification_event_engine.py": "cdc0e68edc770a2a1810fbdb68cbfd46dcd50b267c739c496fcc078c5e26b5b4",
"scripts/active_rectification_events.py": "03e333ccf1103caf685dfe50fe890ab1793e945037085f50ce834a4a3b232222",
"scripts/ashtakavarga.py": "9bfc0b8a06af6122fa6c3881706e64f28b9ba58b53d98ff55957d4741d820f3f",
"scripts/dasha_analyzer.py": "5e53b1b4d4c7414c08dd0e7716f120a63c70ec3428ec93547f64d55c580da0e1",
"scripts/divisional_charts_extended.py": "73bd50a83ac444830940184d0988cea621855f91db76a3f1a232014b992eacea",
"scripts/domain_calculation_service.py": "9ee955874eea806c7b56f4246d90009c02ee8318b8f3dfe1d7132b1c0b4262e1",
"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": "7ff2c3238cd113b11b815e14b41967bd8e486ff62e36650e55613b9c79d1bfe3",
"scripts/rectification/api_service.py": "e316ced0f3796d0378a0fe1aad950ee25922ae8afd53add578ed59ca8b2f0f79",
"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": "0afba494aa12899621173c3cc941c6c1d0be9cec0bdf4c4a1c9bcd004ab22de8",
"scripts/rectification/decision_policy.py": "80e8de4680d19a052213bb821d2a9c94143a2962235aeb27f6ad81374d2e60d5",
"scripts/rectification/event_probes.py": "9bbadc246e6b8e94bb047522c3e5645613f508b3473ef40b38a207c77fdad58c",
"scripts/rectification/refinement_packet.py": "dbeea5aa780889785ce850f3881e8b7f67bb44594e9bc382c65b2e730884a2f4",
"scripts/rectification/scoring_service.py": "4f13c6a78d2dda55454ac20e4091fce280e3626ecfe8a9d723217ef3ebc05d02",
"scripts/research/cluster_width_lib.py": "1d8f2ffa7795d62069deebb2de8e16749317037d4ed3f24a2c0092676e5cfcc6",
"scripts/research/probe_supply_after_six.py": "098a5b4398d6f8d996917d809c2fc922ad64031d3b70660f8ef7c876aba92438",
"scripts/research/reported_offset_sweep.py": "f63c1c58d334e083577736397b4acc00757550fa3b863b02784c9d6f0f018c80",
"scripts/research/sealed_holdout_rerun.py": "1178ebfb9dd61d4aefe9961d83f19e7a943a4ca3de9fa2efffff6f8ba8c09161",
"scripts/shadbala.py": "e949ff1cc925ccbc9a25b68981091d1d621b80a5b3839a3b3ade655d082424d6",
"scripts/varga.py": "4331de5a25ea08729af91aae863943c4223183937f419d52dc63fd6fe7f27be6"
},
"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 2026-10-03 astrologer rulings batch 1 re-freeze. Superseded by the 2026-10-07 upstream sync 6 re-freeze (ERR-110: scripts/varga.py, scripts/divisional_charts_extended.py, scripts/narayana_dasha.py and scripts/rectification/scoring_service.py bytes changed by the PVR 6.2 D5/D6/D8/D11 maps and the scoring-11 identity, BUG-1260/1264). Shadow trial fields versus the 2026-09-20 historical report are unchanged (changed_trial_count 0). Report and freeze preserved byte-for-byte.",
"report_sha256": "b39b53c1f2aa0ad6ac363b4c359116c30bc89b446cb670e6172c8cee5ccc5efd",
"freeze_record_sha256": "c1c11e7abc03b9174aeb1e0b280f550808f887818f578e5d10ad667e0da67e24",
"replay_started_at_utc": "2026-10-03T06:53:04.851491+00:00",
"replay_finished_at_utc": "2026-10-03T06:53:07.509845+00:00",
"previous_fixed_protocol_rerun": {
"report_path": "docs/research/sealed_holdout_rerun_upstream_sync5_2026_10_02.json",
"freeze_record_path": "docs/research/sealed_holdout_rerun_upstream_sync5_2026_10_02.freeze.json",
"superseded_reason": "Upstream sync round 6 (ERR-110). Prior sync5 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_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",
"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-28T08:19:10.206540+00:00",
"replay_finished_at_utc": "2026-10-28T08:23:34.348635+00:00",
"boundary": "Previously exposed reported-offset sensitivity after upstream sync9b (ERR-110, BUG-1494 to BUG-1495). Summary and trials match the 2026-10-18 upstream sync8 report. Versus the 2026-09-20 historical report, changed_trial_count stays 581 of 900. Not a release metric. No tuning. 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",
"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",
@@ -350,12 +372,5 @@
"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."
}
},
"previous_reported_offset_replay": {
"report_path": "docs/research/reported_offset_astrologer_rulings_batch1_2026_10_03.json",
"report_sha256": "480eb771c2c7e5a300589561dc66be950a711ffa205a8fa370db6a11f1e04270",
"freeze_record_path": "docs/research/reported_offset_astrologer_rulings_batch1_2026_10_03.freeze.json",
"freeze_record_sha256": "6be6a997f610c341aecc1f782fa27a5b86b66d43d00fcfa10750c81189c34748",
"superseded_reason": "Upstream sync 6 (ERR-110: scripts/varga.py, scripts/divisional_charts_extended.py, scripts/narayana_dasha.py and scripts/rectification/scoring_service.py). 5 of 900 trials differ from the batch1 replay (delivery_width_minutes on 4, top_1_minute_error on 1). Versus the 2026-09-20 historical report, changed_trial_count is 235 (batch1 was 230). Prior report and freeze preserved byte-for-byte."
}
}
+5 -5
View File
@@ -30,11 +30,11 @@ from scripts.research.sealed_holdout_rerun import (
OFFSETS = (-30, -20, -15, -10, -8, -5, -3, 0, 3, 5, 8, 10, 15, 20, 30)
RADII = (15, 30, 60)
MINUTE_STEP = 1
# 原值: docs/research/reported_offset_scoring_perf_2026_10_13.{freeze.json,json}
# 新值: docs/research/reported_offset_upstream_sync8_2026_10_18.{freeze.json,json}
# 原因: sync8(BUG-1380~1389)改了 ashtakavarga / dasha_analyzer / narayana_dasha,输出不变,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/reported_offset_upstream_sync8_2026_10_18.freeze.json"
REPORT = ROOT / "docs/research/reported_offset_upstream_sync8_2026_10_18.json"
# 原值: 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"
LEGACY_REPORT = ROOT / "docs/research/reported_offset_2026_09_20.json"
+5 -5
View File
@@ -27,11 +27,11 @@ from scripts.minute_rectification_feature_facts_v4 import build_feature_fact_row
from scripts.minute_rectification_holdout_validator import validate
DATASET = ROOT / "references/real_case_calibration/minute_rectification_holdout_v3.json"
# 原值: docs/research/sealed_holdout_rerun_scoring_perf_2026_10_13.{freeze.json,json}
# 新值: docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.{freeze.json,json}
# 原因: sync8(BUG-1380~1389)改了 ashtakavarga / dasha_analyzer / narayana_dasha,输出不变,ERR-110 另存新记录
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.freeze.json"
REPORT = ROOT / "docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18.json"
# 原值: 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"
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 = [
+12 -8
View File
@@ -246,11 +246,12 @@ def calc_64th_navamsa(moon_lon: float) -> Dict:
def calc_22nd_drekkana(lagna_lon: float) -> Dict:
"""Compute the 22nd Drekkana from the Lagna's Drekkana position.
Traditional counting is inclusive, so the 22nd point is +21 signs from the
Lagna Drekkana anchor.
Crux of Vedic Astrology, printed p.329 (corpus page 340), identifies
this as the eighth house in D3. Counting 21 ten-degree divisions is
not the same as moving 21 signs in the D3 chart.
"""
base = calc_varga(lagna_lon, 3)
sign_idx = (base['sign_idx'] + 21) % 12
sign_idx = (base['sign_idx'] + 7) % 12
return {
'base_drekkana_sign_idx': base['sign_idx'],
'base_drekkana_sign': base['sign'],
@@ -279,16 +280,19 @@ def calc_bhrigu_bindu(moon_lon: float, rahu_lon: float) -> Dict:
}
SARPA_DREKKANA_SIGNS = {'Cancer': 2, 'Scorpio': 1, 'Pisces': 3}
# Raman, Hindu Predictive Astrology, Drekkanas chapter, corpus pp.279–283:
# five serpent divisions, including both Cancer-3 and Scorpio-2.
SARPA_DREKKANA_SIGNS = {'Cancer': (2, 3), 'Scorpio': (1, 2), 'Pisces': (3,)}
def calc_sarpa_drekkana(lon: float) -> Dict:
"""Classify Sarpa Drekkana using the classical water-sign sensitive drekkanas."""
lon = lon % 360
base = calc_varga(lon, 3)
sign = _sn(_si(lon))
degree_in_sign = round((lon % 30), 4)
drekkana_number = int(degree_in_sign / 10) + 1
expected = SARPA_DREKKANA_SIGNS.get(sign)
drekkana_number = int((lon % 30) / 10) + 1
expected = SARPA_DREKKANA_SIGNS.get(sign, ())
return {
'longitude': round(lon % 360, 4),
'sign': sign,
@@ -297,8 +301,8 @@ def calc_sarpa_drekkana(lon: float) -> Dict:
'drekkana_number': drekkana_number,
'd3_sign': base['sign'],
'd3_sign_idx': base['sign_idx'],
'is_sarpa_drekkana': bool(expected == drekkana_number),
'definition': 'Cancer-2, Scorpio-1, Pisces-3',
'is_sarpa_drekkana': drekkana_number in expected,
'definition': 'Cancer-2, Cancer-3, Scorpio-1, Scorpio-2, Pisces-3',
}
def dignity(planet, sign_idx):
+1 -1
View File
@@ -701,7 +701,7 @@ def test_full_reading_exposes_sensitive_point_modules() -> None:
assert sensitive["bhrigu_bindu"]["sign"]
assert isinstance(sensitive["sarpa_drekkana"], dict)
for payload in sensitive["sarpa_drekkana"].values():
assert payload["definition"] == "Cancer-2, Scorpio-1, Pisces-3"
assert payload["definition"] == "Cancer-2, Cancer-3, Scorpio-1, Scorpio-2, Pisces-3"
assert payload["is_sarpa_drekkana"] is True
@@ -53,6 +53,11 @@ IDENTITY_FORBIDDEN_PREFIXES = (
# 原因: sync8 改了冻结身份文件,输出不变,ERR-110 另存新记录
"docs/research/sealed_holdout_rerun_upstream_sync8_2026_10_18",
"docs/research/reported_offset_upstream_sync8_2026_10_18",
# 原值: 排除到 upstream_sync8_2026_10_18
# 新值: 再排除 upstream_sync9b_2026_10_28 两份冻结路径(追加,不替换上面的)
# 原因: 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",
"docs/research/history/",
"artifacts/",
)
@@ -0,0 +1,16 @@
"""Classification must use raw longitude, never rounded display degrees."""
import pytest
from scripts.varga import calc_sarpa_drekkana
@pytest.mark.parametrize('longitude,part,is_sarpa', [
(99.99999, 1, False), (100.0, 2, True),
(219.99999, 1, True), (220.0, 2, True),
(359.99999, 3, True), (360.0, 1, False),
])
def test_sarpa_partition_uses_unrounded_longitude(longitude, part, is_sarpa):
row = calc_sarpa_drekkana(longitude)
assert row['drekkana_number'] == part
assert row['is_sarpa_drekkana'] is is_sarpa
assert 1 <= row['drekkana_number'] <= 3
+225
View File
@@ -0,0 +1,225 @@
#!/usr/bin/env python3
"""Regression tests for BPHS divisional chart mappings."""
from __future__ import annotations
import pytest
pytest.importorskip(
"hypothesis",
reason="hypothesis is not installed; see requirements-dev.txt. "
"The guard keeps this file collectable: without it the whole file "
"fails to collect and its tests vanish from the run instead of failing.",
)
from hypothesis import given
from hypothesis import strategies as st
from varga import (
SIGNS,
calc_22nd_drekkana,
calc_64th_navamsa,
calc_bhrigu_bindu,
calc_all_vargas,
calc_sarpa_drekkana,
calc_varga,
varga_map,
)
def navamsa_ref(lon: float) -> int:
sign_index = int((lon % 360) / 30) % 12
degree_in_sign = (lon % 360) - sign_index * 30
part_index = int(degree_in_sign / (30 / 9))
if sign_index % 3 == 0:
start = sign_index
elif sign_index % 3 == 1:
start = (sign_index + 8) % 12
else:
start = (sign_index + 4) % 12
return (start + part_index) % 12
def dasamsa_ref(lon: float) -> int:
sign_index = int((lon % 360) / 30) % 12
degree_in_sign = (lon % 360) - sign_index * 30
part_index = int(degree_in_sign / 3)
start = sign_index if sign_index % 2 == 0 else (sign_index + 8) % 12
return (start + part_index) % 12
def drekkana_ref(lon: float) -> int:
sign_index = int((lon % 360) / 30) % 12
degree_in_sign = (lon % 360) - sign_index * 30
part_index = int(degree_in_sign / 10)
return (sign_index + part_index * 4) % 12
def chaturthamsa_ref(lon: float) -> int:
sign_index = int((lon % 360) / 30) % 12
degree_in_sign = (lon % 360) - sign_index * 30
part_index = int(degree_in_sign / (30 / 4))
return (sign_index + part_index * 3) % 12
@given(st.floats(min_value=0, max_value=359.999999, allow_nan=False, allow_infinity=False))
def test_navamsa_matches_bphs_reference(lon: float) -> None:
result = calc_varga(lon, 9)
assert result["sign_idx"] == navamsa_ref(lon)
assert result["sign"] == SIGNS[navamsa_ref(lon)]
assert 0 <= result["degree_in_sign"] < 30
@given(st.floats(min_value=0, max_value=359.999999, allow_nan=False, allow_infinity=False))
def test_dasamsa_matches_bphs_reference(lon: float) -> None:
result = calc_varga(lon, 10)
assert result["sign_idx"] == dasamsa_ref(lon)
assert result["sign"] == SIGNS[dasamsa_ref(lon)]
assert 0 <= result["degree_in_sign"] < 30
@given(st.floats(min_value=0, max_value=359.999999, allow_nan=False, allow_infinity=False))
def test_drekkana_uses_same_plus_four_plus_eight(lon: float) -> None:
result = calc_varga(lon, 3)
assert result["sign_idx"] == drekkana_ref(lon)
@given(st.floats(min_value=0, max_value=359.999999, allow_nan=False, allow_infinity=False))
def test_chaturthamsa_matches_pyjhora_parashara_reference(lon: float) -> None:
result = calc_varga(lon, 4)
assert result["sign_idx"] == chaturthamsa_ref(lon)
assert result["sign"] == SIGNS[chaturthamsa_ref(lon)]
assert 0 <= result["degree_in_sign"] < 30
def test_chaturthamsa_reference_boundary_examples() -> None:
assert [varga_map(0, part, 4) for part in range(4)] == [0, 3, 6, 9]
assert [varga_map(8, part, 4) for part in range(4)] == [8, 11, 2, 5]
assert [varga_map(11, part, 4) for part in range(4)] == [11, 2, 5, 8]
def test_varga_map_boundary_examples() -> None:
assert varga_map(0, 0, 9) == 0 # Aries Navamsa starts Aries
assert varga_map(1, 0, 9) == 9 # Taurus Navamsa starts Capricorn (9th from sign)
assert varga_map(2, 0, 9) == 6 # Gemini Navamsa starts Libra (5th from sign)
assert varga_map(1, 0, 10) == 9 # Taurus Dasamsa starts Capricorn
assert varga_map(0, 2, 3) == 8 # Aries third Drekkana = Sagittarius
def test_rudramsa_d11_is_supported_by_native_varga_map() -> None:
assert varga_map(0, 0, 11) == 0
assert varga_map(0, 10, 11) == 10
# PVR 6.2.11: anti-zodiacal seed from Aries, zodiacal parts.
assert varga_map(1, 0, 11) == 11
assert varga_map(1, 10, 11) == 9
result = calc_varga(35.0, 11)
assert result["sign"] == "Aries"
assert 0 <= result["degree_in_sign"] < 30
def test_native_varga_map_supports_declared_high_value_vargas() -> None:
for div in (2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 24, 60, 81, 108, 144):
result = calc_varga(35.0, div)
assert result["sign"] in SIGNS
assert 0 <= result["degree_in_sign"] < 30
def test_default_varga_batch_includes_declared_vargas() -> None:
charts = calc_all_vargas({"Moon": 35.0}, 10.0)
for key in ("D5_Panchamsa", "D6_Shashthamsa", "D8_Ashtamsa", "D11_Rudramsa", "D81_Navamsa-Navamsa", "D108_Dwadasamsa-Navamsa", "D144_Dwadasamsa-Dwadasamsa"):
assert key in charts
assert charts["D11_Rudramsa"]["Moon"]["sign"] == "Aries"
def test_navamsa_matches_user_jhora_pdf_reference_chart() -> None:
"""Regression from private_chart_reference.pdf: JHora-style D9 table for public sample birth datetime San Francisco."""
expected = {
132.355025: "Cancer", # Ascendant 12 Leo 21'18.09"
3.5226611111111112: "Taurus",
311.78995555555554: "Capricorn",
91.33091388888889: "Cancer",
338.5488: "Virgo",
163.83150833333335: "Taurus",
340.5554638888889: "Libra",
304.3033805555556: "Scorpio",
231.04509444444443: "Capricorn",
51.045094444444445: "Cancer",
}
for longitude, expected_sign in expected.items():
assert calc_varga(longitude, 9)["sign"] == expected_sign
def test_64th_navamsa_counts_forward_from_moon_navamsa() -> None:
moon_lon = 42.3
result = calc_64th_navamsa(moon_lon)
expected_sign_idx = (navamsa_ref(moon_lon) + 63) % 12
assert result["sign_idx"] == expected_sign_idx
assert result["sign"] == SIGNS[expected_sign_idx]
assert result["offset_from_moon_navamsa"] == 64
def test_22nd_drekkana_counts_forward_from_lagna_drekkana() -> None:
asc_lon = 25.5
result = calc_22nd_drekkana(asc_lon)
# Sagittarius D3 rising: its eighth house is Cancer (Crux p.329).
expected_sign_idx = 3
assert result["sign_idx"] == expected_sign_idx
assert result["sign"] == SIGNS[expected_sign_idx]
assert result["offset_from_lagna_drekkana"] == 22
def test_22nd_drekkana_independent_zodiac_partition_count() -> None:
# Enumerate all 36 zodiacal ten-degree divisions, then count 22 inclusively.
# This oracle does not add an offset to the calculated D3 sign.
for division in range(36):
target = (division + 21) % 36
target_rasi, target_part = divmod(target, 3)
expected = (target_rasi + 4 * target_part) % 12
for within in (0.0, 0.001, 5.0, 9.999):
result = calc_22nd_drekkana(division * 10 + within)
assert result['sign_idx'] == expected
def test_bhrigu_bindu_uses_rahu_to_moon_arc_midpoint() -> None:
result = calc_bhrigu_bindu(270.5, 160.2333333333)
assert result["longitude"] == 215.3667
assert result["sign"] == "Scorpio"
assert result["degree_in_sign"] == 5.3667
def test_bhrigu_bindu_handles_wraparound_across_zero_aries() -> None:
result = calc_bhrigu_bindu(10.0, 350.0)
assert result["longitude"] == 0.0
assert result["sign"] == "Aries"
assert result["degree_in_sign"] == 0.0
def test_sarpa_drekkana_detects_classical_sensitive_ranges() -> None:
cancer_second = calc_sarpa_drekkana(105.0)
scorpio_first = calc_sarpa_drekkana(215.0)
pisces_third = calc_sarpa_drekkana(355.0)
safe_aries = calc_sarpa_drekkana(15.0)
assert cancer_second["is_sarpa_drekkana"] is True
assert cancer_second["sign"] == "Cancer"
assert cancer_second["drekkana_number"] == 2
assert scorpio_first["is_sarpa_drekkana"] is True
assert scorpio_first["sign"] == "Scorpio"
assert scorpio_first["drekkana_number"] == 1
assert pisces_third["is_sarpa_drekkana"] is True
assert pisces_third["sign"] == "Pisces"
assert pisces_third["drekkana_number"] == 3
assert safe_aries["is_sarpa_drekkana"] is False
def test_sarpa_contains_all_five_book_ranges_and_no_others() -> None:
# Zodiac degree intervals transcribed from Raman, not the production map.
intervals = ((100, 120), (210, 230), (350, 360))
for segment in range(36):
for offset in (0.0, 0.001, 5.0, 9.999):
longitude = segment * 10 + offset
expected = any(start <= longitude < end for start, end in intervals)
assert calc_sarpa_drekkana(longitude)['is_sarpa_drekkana'] == expected
+2 -1
View File
@@ -175,7 +175,8 @@ def test_64th_navamsa_counts_forward_from_moon_navamsa() -> None:
def test_22nd_drekkana_counts_forward_from_lagna_drekkana() -> None:
asc_lon = 25.5
result = calc_22nd_drekkana(asc_lon)
expected_sign_idx = (drekkana_ref(asc_lon) + 21) % 12
# Sagittarius D3 rising: its eighth house is Cancer (Crux p.329).
expected_sign_idx = 3
assert result["sign_idx"] == expected_sign_idx
assert result["sign"] == SIGNS[expected_sign_idx]
assert result["offset_from_lagna_drekkana"] == 22