merge full-data parity (三) independent annual method reference into staging (issue #93, BUG-1430/1431 renumbered to 1442/1443)
Independent Staging Quality Gate / validate (push) Successful in 20m17s
Independent Staging Quality Gate / publish (push) Successful in 9m16s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LutgzyJqNhPpZy1nFsJtN3
This commit is contained in:
Jesse_Chen
2026-10-26 22:28:00 +08:00
co-authored by Claude Opus 5.5
29 changed files with 1739 additions and 57 deletions
@@ -0,0 +1,159 @@
# 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 次打回(2026-10-23)
合并了当时的 `origin/staging`(含修复单 `4d0e398ab`)。没有重做上一轮已经通过的隔离和三年表。
这一章现在算进结果指纹。不再先摘掉、绑定后再放回去。两份只差这一章内容的资料包,指纹不再相同。报告里有这一章时,按同一份资料包重算,能对上。
比较「去掉这一章之后,装与不装是否逐字相同」时,先把下面两行换成同一个占位符 `FINGERPRINT`,再比:
- `- 报告 ID: \`...\``
- `- 计算结果摘要: \`...\``
这两行来自结果指纹。指纹把这一章算进去之后,它们本来就会变。其余行不抹。
标准版在已经知道「不是完整数据版」之后,不再去算这一章。完整数据版仍在写入指纹之前挂上这一章,所以指纹里有它。直接生成完整数据资料包的旧入口默认仍会算,阅读页和扫描不变。
部署说明不再写出年主对照开关的变量名,只说不要打开这个开关。
子进程超时仍是 120 秒。这是上限,不是目标。前端整份报告最多等 180 秒;120 秒加上其余排盘和排版,在 Linux 上实测整份约 20 秒,没有顶到 180 秒。这台 Windows 电脑上中英一起最高约 59 秒,也没有顶到。
### 改过的断言
| 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| 结果指纹是否包含这一章 | 两个标记的指纹相同 | 两个标记的指纹不同,本章仍留在资料包里 | 交付包里有这一章时,重算必须对得上(BUG-1442;1429 已由研究章日出占用) |
编号:BUG-1442。本分支原先写成 BUG-1429,合并 staging 时改号。
## 这一轮跑过的检查
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 修复单点名的测试,去掉两次真算 PyJHora | 指纹、合同、阅读页、英文版、年主、Tajika、增长、卫生等 | 退出码 0,约 460 秒 |
| 三张虚构盘真算 PyJHora,以及父进程月亮位置不变 | 两个隔离测试 | 退出码 0,129 秒 |
| 200 张英文扫描 | 扫描里不启动 PyJHora 子进程 | 退出码 0,1362 秒 |
| 全量 pytest 和快速门 | 未跑 | 留给验收 |
| 前端 | 本轮没改页面 | 没跑 |
依赖的 staging 提交是合并进来的 `4d0e398ab`。
## 第 2 轮(2026-10-24)
产品选 B。合并了当时的 `origin/staging`(`0f66d92d4`)。没有重做上一轮已经通过的隔离和三年表,也没有改报告计算。
两处测试替身补上 `**_kwargs`,和已经改过的 4 处一样:
- `tests/test_reader_appendix_language.py`
- `tests/test_report_density_facts.py`
`tests/` 里其余替换这个函数的替身,本来就能接收额外参数,没有再改。原有断言没有改。
合并之后,研究章仍在六章后面、口径替换前面。独立年度方法参考仍在口径替换后面,避免来源那一行被删掉。六章测试同时认这两段后加的标题。
### 改过的断言
| 测试 | 原值 | 新值 | 原因 |
| --- | --- | --- | --- |
| 六章后面的二级标题 | 本分支只认六章再加最后的年度方法参考 | 六章之后先是研究章,最后仍是年度方法参考 | 合并 #92 后研究章插在中间 |
编号:BUG-1443。指纹那条改为 BUG-1442,因为 BUG-1429 已是研究章在 1970 年以前的日出记录。
## 第 2 轮跑过的检查
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 两条打回的测试 | `pytest` 点名这两条 | 2 通过,退出码 0 |
| 六章、年度方法参考、计算合同、阅读页泄漏、结果性能 | 同上五个测试文件,阅读页只跑泄漏相关两条 | 72 通过,3 跳过,退出码 0。3 条跳过是计算合同里原有的「产品树未附带」,不是本轮新跳过 |
| 200 张英文扫描 | `pytest tests/test_report_english_sweep.py::test_two_hundred_fictional_charts_have_clean_english` | 1 通过,退出码 0。扫描不真起 PyJHora |
| 全量 pytest 和快速门 | 未跑 | 留给验收 |
| 前端 | 本轮没改页面 | 没跑 |
依赖的 staging 提交是 `0f66d92d4d6545972202f209c63c87959d44b87e`。
+2 -2
View File
@@ -528,8 +528,8 @@
| `TASK-full-data-parity-2-fix-20261023.md` | `PROGRESS-full-data-parity-2-20261021.md` | **#92 第 1 次打回**:其余全过(Linux 生成约 18 秒、英文汉字 0);T5 已用 10 张虚构盘做完离线对照,不一致的体系在标题下写明差在哪一类 | 已合入 staging | `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-fix-20261023.md` | `PROGRESS-full-data-parity-3-20261022.md` | **#93 第 1 次打回**:功能、隔离、速度都过(Linux 约 20 秒,worker 约 60 MB);结果指纹排除本章致重算对不上(违反 D2)、源码合同测试没跟改、自己的新测试与 deploy README 打架 | 待执行 | `codex/full-data-parity-3-20261022` |
| `TASK-full-data-parity-3-20261022.md` | `PROGRESS-full-data-parity-3-20261022.md` | #93 完整数据版补齐(三):「独立年度方法参考」正式环境调 PyJHora(子进程隔离;装上后其余输出逐字节不变,7 个换路径开关钉死);输入默认用本地时间与正确年份(D6 默认,未收到「照上游原样」) | 已合入 staging | `codex/full-data-parity-3-20261022` |
| `TASK-full-data-parity-3-fix-20261023.md` | `PROGRESS-full-data-parity-3-20261022.md` | **#93 第 2 次打回**:两处测试替身补上额外参数(BUG-1443)。指纹记录在合并后改称 BUG-1442 | 已合入 staging | `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` |