feat(report): 完整数据版末尾增加独立年度方法参考

PyJHora 只在子进程里计算请求年及后两年。对话、校正和其余章节保持不导入时的结果。结果指纹不算这一章。

Windows 自测:隐私标记、导入扫描、结果指纹和 S7 退出码 0。阅读页、英文和年运章在此之前已通过。虚构盘 0 中英一起最高 59 秒。

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-23 20:13:28 +08:00
co-authored by Grok (agent loop)
parent 85e8adddbc
commit c644881a30
24 changed files with 1553 additions and 46 deletions
+33
View File
@@ -17149,6 +17149,7 @@
- 修复版本:本分支 `codex/special-lagnas-native-20261008`
- Claude 验收(2026-10-08,Linux):屏蔽 `jhora` 导入后跑 `cmd_full_reading`,乔布斯、奥巴马、虚构盘 × Lahiri / Raman 共 6 组,8 个点全部 `computed`、`source` 为 `native_special_lagna`,与 `fb8277bf` 调 PyJHora 的结果最大差 0°。Python 全量 62 条失败,与 `2df6ee72` 逐名相同;快速门通过;`tests/test_runtime_jhora_import_scan.py` 在快速门内,人为在 `native_special_lagnas.py` 加一行 `from jhora ...` 后该测试失败(变异检查)。年运资料包屏蔽 `jhora` 前后逐字节相同。
- 待问占星师:Vighati 上升按每分钟 15° 计(与 PyJHora 一致);按字面「每个 vighati 一个星座」应为每分钟 75°。
- 决策推翻(2026-10-22,issue #93,不改本条状态):产品决定生产镜像可以安装 PyJHora,但只给完整数据版最后一章「独立年度方法参考」用。调用放在单独的子进程里,父进程不加载它。八个特殊上升点仍走本条的本机算法,不改回进程内 PyJHora。AGPL 由产品接受。见 BUG-1427、BUG-1428。
## BUG-1274 | 中文报告把 Bhava Bala 译成年龄状态,并把 Planets 译成行星s
@@ -19350,3 +19351,35 @@
- 复发自:无
- 修复版本:分支 `codex/full-data-parity-1-20261021`。
## BUG-1427 | 装上 PyJHora 后,对话交叉验证会在接口进程里加载它
- 状态:resolved
- 首次发现:2026-10-23
- 最近更新:2026-10-23
- 影响面:对话编排里的外部引擎交叉验证。完整数据版最后一章不走这条路径。
- 用户现象:生产镜像一旦装上 PyJHora,对话在同一进程里探测并加载它。岁差和星历路径会被改掉,同一时刻的月亮经度不再稳定。
- 触发条件:镜像含 PyJHora,且对话走到交叉验证。
- 根因:产品路径用「能不能导入 jhora」决定要不要调用。装上之后探测成功,接着在接口进程里导入。
- 修复:产品报告固定写成今天没装 PyJHora 时的结果,不探测、不导入。命令行诊断工具仍按原样报告是否可用。
- 验证:`tests/test_pyjhora_annual_method_reference.py` 把探测函数换成会失败的替身,产品报告仍不调用它。`tests/test_unified_consultation_orchestrator.py` 的适配器状态仍是缺少 jhora 模块。`tests/test_pyjhora_adapter_diagnostics.py` 命令行行为不变。
- 防复发:上面几条。产品路径再调用探测,测试会失败。
- 相关记录:issue #93。BUG-1273、BUG-1428。
- 复发自:无
- 修复版本:分支 `codex/full-data-parity-3-20261022`。
## BUG-1428 | 装上 PyJHora 后,校正三引擎包会在接口进程里加载它
- 状态:resolved
- 首次发现:2026-10-23
- 最近更新:2026-10-23
- 影响面:校正用的三引擎对照包里的 PyJHora 一行。生时校正打分本身不走这条路径。
- 用户现象:生产镜像一旦装上 PyJHora,这行对照在接口进程里导入它,星盘其余数字可能被带着变。
- 触发条件:镜像含 PyJHora,且组装三引擎对照包。
- 根因:这一行直接导入 PyJHora。没装时得到「没有这个模块」;装上之后导入成功,计算发生在父进程。
- 修复:产品路径固定抛出「没有这个模块」,不执行导入。对照行仍是今天没装时的那一行。
- 验证:`tests/test_pyjhora_annual_method_reference.py` 检查这段源码没有导入语句,调用时得到模块缺失。封存合同测试 `tests/test_sealed_holdout_contract_freshness.py` 与 `tests/test_rectification_validation_integrity_gate.py` 仍通过。
- 防复发:上述源码断言。再写回进程内导入,测试会失败。
- 相关记录:issue #93。BUG-1273、BUG-1427。
- 复发自:无
- 修复版本:分支 `codex/full-data-parity-3-20261022`。
@@ -0,0 +1,87 @@
# PROGRESS — 完整数据版独立年度方法参考(#93)
基线是已合入 #91 的 `origin/staging` `85e8adddbc9c14e31c687c91ad8666afe3290e64`。#92 没有合入 staging。没有收到「照上游原样」,D6 用默认:当地时间,Patyayini / Tajika 用「年龄 + 1 年」,Mudda 仍用年龄。
## 做了什么
完整数据版报告最后多了一章「独立年度方法参考」。这一章在单独的子进程里用 PyJHora 算请求年及后两年。父进程不加载 PyJHora。对话卡、校正和前面的本机年运仍按没装 PyJHora 时的结果。标准报告没有这一章。
某一年某一张表算不出来时,该表写「未获得结果」,不把内部原因印进报告。
## 换路径开关
| 编号 | 处理 |
| --- | --- |
| S1 | 产品路径不启动子进程,仍返回原来的年运结果。研究脚本明确要求时才计算。测试里的旧替身只有 4 个参数,不会把整章打成未判定。 |
| S2 | 对话交叉验证不探测、不导入。命令行诊断仍可报告是否装了。 |
| S3 | 校正三引擎对照固定返回「没有这个模块」,不在接口进程里导入。 |
| S4 | 部署文件不设置 `JYOTISH_YEAR_LORD_PYJHORA_REFERENCE`。Dockerfile 与工作流没改。 |
| S5 | 没有新增被禁止的那两个模块。 |
| S6 | 诊断脚本会显示 PyJHora 可用。它们不在产品路径上,没改。 |
| S7 | 见下面的测试。装上之后这些用例会真跑,不再跳过。 |
## 装与不装
同一进程里,虚构盘 0 连续 5 次:去掉本章后的中文、英文各自哈希不变。父进程没有加载 jhora。英文汉字为 0。
把「找不到 jhora」的拦截放进子进程后,再用同一个进程哈希种子重跑虚构盘 0、1、9:去掉本章后的中文和英文与装上时逐字相同。资料包去掉新键、生成时刻和缓存时刻后,只剩报告引用号。引用号来自结果指纹。结果指纹现在不把这一章算进去,所以装与不装的引用号一致。
不固定哈希种子时,虚构盘 0 的太阳相位力量会差 0.01,虚构盘 1 的第一条王者格句子会换成另一条。这是既有代码用集合遍历,顺序随进程变化,不是这一章引入的。同一进程里的 5 次中文哈希相同。本轮没有改那两处旧代码。
开工前的「改代码之前」对照没有量成。当时的测量停在星历下载,不能当作装与不装的差异清单。上面是改完之后的对照。
## 两种年份口径(虚构盘)
文档口径是本轮采用的默认。上游口径是世界时、并且年份不加 1。只列回归时刻和 Mudda 第一段起点,没有出生资料。小数小时已折成秒。
| 虚构盘 | 岁差回读 | 交点 | 文档口径回归 | 上游口径回归 | 文档口径 Mudda 起点 | 上游口径 Mudda 起点 | 这次子进程秒数 |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 0 | RAMAN,一致 | 平交点 | 2026-07-19 08:55:02 | 2025-07-18 23:19:06 | 2026-07-08 02:01:59 | 2026-07-10 19:12:54 | 50.057 |
| 1 | LAHIRI,一致 | 平交点 | 2026-07-01 06:18:58 | 2025-06-30 21:05:13 | 2026-06-17 18:10:07 | 2026-06-21 00:36:03 | 52.986 |
| 9 | RAMAN,一致 | 平交点 | 2026-05-08 23:36:33 | 2025-05-09 00:22:13 | 2026-04-29 06:01:58 | 2026-04-23 10:30:48 | 50.567 |
这三次为了对照多算了一遍上游口径,所以比正式出报告的那一次更慢。虚构盘 0 上,正式计算复用同一次年盘,三次复用都与再算一次相同(此前已测)。
## 时长(Windows,虚构盘 0,5 次)
中文先渲染会把中文句子写进资料包,接着的英文会被判成有汉字而整份撤回。计时已改成英文使用渲染前的副本。下表是改完之后的数。第一次作废的英文时长不采用。
| 项目 | 中位 | 最大 |
| --- | --- | --- |
| 只出中文 | 54.873 秒 | |
| 只出英文(含同一次排盘) | 47.344 秒 | |
| 中英一起 | 57.034 秒 | 59.013 秒 |
排盘约 45.183 秒,中文排版 9.690 秒,英文排版 2.161 秒。中文约 821290 字,英文约 1358880 字。本章中文约 38313 字,英文约 44551 字。
虚构盘 1 中英一起 78.568 秒,虚构盘 9 为 85.168 秒。三张都低于 180 秒。Linux 是否仍低于 180 秒由 Claude 复测。
## 镜像
本地镜像 `jyotisha-api:parity3-20261023`,`docker image inspect` 的 Size 为 932044815 字节。本机没有更早的 `jyotisha-api` 镜像,无法写增量。`docker history` 里安装依赖的那一层约 345MB。容器内可以导入 jhora、swisseph、geocoder、geopy。`pip show pyswisseph` 为 2.10.3.2。`pip check` 无冲突。Dockerfile 没改。
`docker stats` 按让步没测。子进程工作集在这台 Windows 上的采样一直停在约 4.4MB,空进程也是这个数,不能当成峰值。峰值留给 Linux 复测。
## 改过的断言
| 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| 阅读页三处泄漏检查 | 全文不得出现 PyJHora | 先去掉「独立年度方法参考」再查 | 这一章必须写来源 |
| 英文泄漏检查 | 英文全文不得出现 PyJHora | 先去掉 Independent Annual Method Reference 再查 | 同上 |
## 本轮跑过的检查
- 结果指纹不包含这一章:通过。
- 四参数替身仍能接到年运,不把整章打成未判定:通过。
- 阅读页、英文版、完整数据章、子进程门禁:在加上结果指纹排除之前已通过(约 291 秒那一轮,外加更早的三张盘真算约 288 秒)。
- 封存合同与校正完整性:在四参数修复之前的那一轮通过。本轮没重跑。
- 全量 pytest 和快速门没跑,留给 Claude。
- 隐私标记、导入扫描、结果指纹,以及 S7 的 Ashtakavarga 与三份大运对照:退出码 0,约 33 秒。
## 偏离
- T0 到 T6 放在同一次提交。章节标题测试要等渲染和依赖同时在,拆开会红。
- 没装的环境用启动时拦截 `jhora`,没有另建一套虚拟环境。
- 子进程超时是 120 秒。45 秒会在这台机器上把已经算完的三年掐掉。
- 没做容器内存曲线。
- 开工前的基线对照没有形成可用数字。
+1 -1
View File
@@ -526,7 +526,7 @@
| `TASK-full-data-parity-2-20261021.md` | — | #92 完整数据版补齐(二):研究型推运附录(Tithi Ashtottari、Yoga / Nakshatra Pravesha、Karana 等,口径换成我方真恒星)、四种星座大运第三层、Kalachakra 第三层(简化模型)、Niryaana Shoola 子运只在有书面出处时做、D81 / D108 / D144 研究型分盘;全部标研究口径,不进对话卡与校正;不设大小上限 | 待执行 | `codex/full-data-parity-2-20261021` |
| `TASK-goel-jaimini-strength-20261022.md` | `PROGRESS-goel-jaimini-strength-20261022.md` | #94 搬上游公开的 Goel Jaimini 强度与 Brahma / Maheshwara / Rudra(4 个上游原样文件,按 #81 决策 A 先例根目录预算 448→452;来源串改书目引用);只做计算、不改报告;冻结身份不变 | 已合入 staging | `codex/goel-jaimini-strength-20261022` |
| `TASK-chart-subject-table-fix-20261022.md` | `PROGRESS-chart-subject-table-fix-20261022.md` | **#86 第 1 次打回**:报告所有表被强制单行(打印跑出纸面);保存他人复制了档案页代码且已分叉;点编辑框内边距会丢修改 | 已合入 staging | `codex/chart-subject-table-20261021` |
| `TASK-full-data-parity-3-20261022.md` | — | #93 完整数据版补齐(三):「独立年度方法参考」正式环境调 PyJHora(子进程隔离;装上后其余输出逐字节不变,7 个换路径开关钉死);输入默认用本地时间与正确年份(D6 待产品确认) | 待领取(等 #91 合入) | `codex/full-data-parity-3-20261022` |
| `TASK-full-data-parity-3-20261022.md` | `PROGRESS-full-data-parity-3-20261022.md` | #93 完整数据版补齐(三):「独立年度方法参考」正式环境调 PyJHora(子进程隔离;装上后其余输出逐字节不变,7 个换路径开关钉死);输入默认用本地时间与正确年份(D6 默认,未收到「照上游原样」) | 待验收 | `codex/full-data-parity-3-20261022` |
| `TASK-synastry-staging-fix-fix-20261022.md` | `PROGRESS-synastry-staging-fix-fix-20261022.md` | **#85 第 1 次打回**(T7~T11 主体通过):新地址没登记进路由清单致快速门红;CHANGELOG 与 T11 矛盾;侧栏点亮测试是空断言 | 已合入 staging | `codex/synastry-staging-fix-20261021` |
| `TASK-report-english-han-leak-fix-20261022.md` | `PROGRESS-report-english-han-leak-fix-20261022.md` | **#89 第 1 次打回**:改了冻结的校正打分文件 `jaimini.py`;测试的 PyJHora 屏蔽没传到子进程(测的不是生产那份报告,也是慢的原因);缺英文时留空藏住漏洞 | 已合入 staging | `codex/report-english-han-leak-20261021` |
| `TASK-full-data-parity-1-fix-20261022.md` | `PROGRESS-full-data-parity-1-fix-20261022.md` | **#91 A 段第 1 次打回**:新六章 69 节里 16 节在三张虚构盘上整节「未判定」,其中 12 节数据在资料包里、是读错了字段;测试抓不到整节未判定;新六章绕过了报告口径替换;中文附录悄悄丢列和瑜伽条目要量出来 | 已合入 staging | `codex/full-data-parity-1-20261021` |
@@ -0,0 +1,11 @@
# 完整数据版「独立年度方法参考」真机验收
用虚构盘或公开名人盘。不要把真实出生资料写进记录。
1. 打开一份完整数据版报告,翻到最后。最后一章标题是「独立年度方法参考」。
2. 这一章有请求年、后一年、再后一年。每年都能看到来源是 PyJHora,以及 Mudda 两张表、Patyayini、Tajika。
3. 某一格算不出来时,那一格写「未获得结果」,整份报告仍然能打开。
4. 切换到英文。同一章标题是 Independent Annual Method Reference。英文里没有汉字。来源行是 Source: PyJHora。
5. 导出 `.md`。最后一章仍在文件末尾。
6. 打开一份这次更新之前生成的旧报告。它仍然能从列表打开,内容不因为这章而打不开。
7. 打开一份标准报告(不是完整数据版)。没有「独立年度方法参考」这一章。