# 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`。