diff --git a/docs/tasks/TASK-api-server-service-extract-fix-20261016-2.md b/docs/tasks/TASK-api-server-service-extract-fix-20261016-2.md new file mode 100644 index 00000000..b16c01b0 --- /dev/null +++ b/docs/tasks/TASK-api-server-service-extract-fix-20261016-2.md @@ -0,0 +1,47 @@ +# TASK · API 单体拆类 · 第二份修复单(issue #70,第 2 次打回) + +- 日期:2026-10-16 +- 被验提交:`a7fe7e9dd5f8a768ad25d2080f45db1e429f0d24`(分支 `codex/api-server-service-extract-20261013`) +- 前一份修复单:`docs/tasks/TASK-api-server-service-extract-fix-20261016.md` +- 原任务书:`docs/tasks/TASK-api-server-service-extract-20261013.md` +- 状态:**第 2 次打回,按循环规则等产品负责人拍板后再开工**(选项见 issue #70)。下文是选 A 时的做法;选 B 时由 Claude 改,Grok 不动。 +- BUG 编号:沿用 BUG-1359(Grok 已登记),补充本次根因,不新开号 + +## 验收结论(Claude,Linux) + +| 项 | 结论 | 证据 | +| --- | --- | --- | +| F1 路径换成 `` | 已做,但不足以让金样跨机器成立 | 见 G1 | +| F2 不删共用排盘缓存 | 通过 | 单独跑金样测试前后 `scratch/local/api_chart_cache` 都是 2 个文件;排盘缓存有效期为 0 时读写函数直接跳过 | +| F3 恢复 BUG-1341 三栏 | 通过 | 原三行恢复,本单说明另起一行 | +| 拆类本身(T2–T5) | 仍然通过 | 与上一轮相同,本轮未改 `scripts/jyotish_api_server.py` | +| **金样测试** | **未通过** | Linux 上单独跑仍红:7 条哈希不等,如 `http.career … bytes 420433 != 441192` | + +## G1 · 金样依赖后台线程的等待结果,机器快慢决定指纹(根因) + +**现象**:在 Linux 上,金样里 `vedastro_gateway` 是一个约 21 KB 的完整对象(`status=local_fallback`,含 `runtime_mode`、`gateway_status` 等 14 个键)。Grok 在 Windows 上采到的同一字段只有 4 个键(`scope`、`status`、`official_closure_reason`、`official_closure_state`),也就是「没等到」的占位包。两边字节差约 2 万。 + +**根因**:`defer_optional_external_evidence=True` 时,`scripts/vedastro_foreground.py` 的 `ForegroundVedastroSession` 把 VedAstro 网关放进后台线程池运行,`finish()` 只等 `_foreground_vedastro_join_seconds()`(环境变量 `JYOTISH_FOREGROUND_VEDASTRO_JOIN_SECONDS`)。等到了就用完整结果,等不到就用占位包。另外 `start()` 会先查 `scratch/local/vedastro_snapshot_cache`(`JYOTISH_VEDASTRO_SNAPSHOT_CACHE_DIR`),并在 `vedastro_snapshot_negative_cache` 写负缓存。所以金样同时取决于**机器速度**和**另外两个共用硬盘缓存的状态**。Grok 在同一台机器上采基线和分支,两边恰好都没等到,于是 8 个哈希一致;换一台机器就不成立。 + +这不是拆类引入的问题(基线代码同样如此),也不影响线上行为;只是这条金样从设计上就不可复现。 + +## 修法(选 A 时) + +1. 采集期间把 VedAstro 前台观察固定成确定结果,不许依赖等待时长: + - 用 `monkeypatch`(测试)或采集脚本里的上下文管理器,把咨询工作流实际调用的 `start_foreground_vedastro` 替换成返回「固定占位包」的会话(占位包用 `vedastro_foreground._blocked_foreground_vedastro(reason="foreground_optional_evidence_timeout")` 的现成结构)。替换要打在**调用方模块的属性**上(写作时是 `scripts/jyotish_api_server.py` 模块属性 `start_foreground_vedastro`,约第 2265 行按名字调用;开工 grep 复核),结束后恢复。 + - 同时把 `JYOTISH_VEDASTRO_SNAPSHOT_CACHE_DIR` 和 `JYOTISH_VEDASTRO_SNAPSHOT_NEGATIVE_CACHE_DIR` 指向临时目录,采集结束删除临时目录;不得读写仓库里的这两个目录。 +2. 采集脚本里再加一个自检:同一进程内分别设 `JYOTISH_FOREGROUND_VEDASTRO_JOIN_SECONDS=0` 和 `=` 上限各采一次 `mcp.career`,哈希必须相同;不同就报错,不写金样。 +3. 在基线(`fbf04f0b5f31cd8421bc4546840b1c833aaed810`)与本分支各采一次,8 个哈希相同后覆盖金样。 +4. 更新 BUG-1359 的根因、修复、验证三栏,写明第二次打回的原因。 + +## 验收标准 + +- Claude 在 Linux 上单独跑 `tests/test_api_service_extract_golden.py` 为绿;Grok 在 Windows 上为绿;两边金样哈希相同。 +- 全量 `pytest -n 4` 的失败清单与基线逐名一致。 +- 仓库内 `scratch/local/api_chart_cache`、`vedastro_snapshot_cache`、`vedastro_snapshot_negative_cache` 在测试前后文件列表不变。 +- 不放宽比对(不许改成只比键路径、字节数,或把 `vedastro_gateway` 从比对里删掉而不固定它)。 + +## 不要做 + +- 不改 `scripts/jyotish_api_server.py`、`scripts/vedastro_foreground.py` 的业务行为。 +- 不改 `tests/test_api_server_security.py`。