Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LutgzyJqNhPpZy1nFsJtN3
6.4 KiB
TASK · API 单体拆类 · 修复单(issue #70,第 1 次打回)
- 日期:2026-10-16
- 被验提交:
c7350bcafbff64d3c526c2dbf3995c9845b3b66e(分支codex/api-server-service-extract-20261013) - 原任务书:
docs/tasks/TASK-api-server-service-extract-20261013.md - 执行方:Grok;在同一分支上追加提交(基于
c7350bcaf,不改写已推历史);若origin/staging已前进,用git merge origin/staging,不要 rebase - BUG 编号:无(仍属结构改造)
验收结论(Claude,Linux)
拆类本身通过;新增的金样测试未通过,因此整单打回。
| 项 | 结论 | 证据 |
|---|---|---|
| T2 纯移动 | 通过 | AST 对比:基线与本分支 215 个方法名集合相同、方法体逐个 ast.dump 相等;模块级函数与其他顶层语句全等;JyotishComputeService 200 个方法,JyotishAPIHandler 15 个 HTTP 方法 + server_version + docstring |
| T3 生产伪造归零 | 通过 | grep -rn "JyotishAPIHandler.__new__" scripts 0 命中 |
| T3 结果等价 | 通过(Claude 自证) | 基线工作树与本分支各跑 capture_mcp('career')(清缓存),逐字段比对只差 3 个 manifest_path 绝对路径(两个工作树目录名不同);基线连跑两次 0 差异;repairs、evidence 两路哈希两边相同 |
| T4 测试伪造下调 | 通过 | 17 个文件只改构造语句与类型注解;伪造合计 31 → 5 |
| T5 合同与守卫 | 通过(附一处文字要求,见 F3) | 两条新守卫在本机绿 |
test_api_server_security.py 零改动 |
通过 | git diff --stat 空 |
| 本机 API 冒烟 | 通过 | 基线与本分支并排:/api/health 200、/api/chart 虚构盘 200(只差时间戳字段)、非 JSON 400、text/plain 415、3 MB 请求体 400、未知路径 404、OPTIONS 200、Server: JyotishAPI/6.9.14 头,响应体逐字相同 |
| T1 金样测试 | 未通过 | 见 F1、F2 |
全量 pytest(-n 4)与基线逐名比对 |
未通过 | 本分支比基线多 2 条失败:test_api_service_extract_golden.py::test_api_service_extract_golden_matches_baseline(单独跑也红)、test_capture_commercial_astrology_e2e_contexts.py::test_capture_writes_runtime_contexts_without_required_layer_echo(单独跑绿,并行红,见 F2) |
F1 · 金样哈希含本机绝对路径,换机器必红(必做)
现象:本机单独跑 pytest tests/test_api_service_extract_golden.py,7 条哈希全部不等,如 http.career sha256 6a6ca4… != 0c8ef6… bytes 420555 != 441296。
根因:咨询工作流响应里有 external_parity_gate.manifest_path、real_case_calibration.holdout_replay_manifest.manifest_path、real_case_calibration.outcome_replay_manifest.manifest_path 等字段,值是运行机器上的绝对路径。canonical_text 只去掉了两个墙钟字段,没处理路径,所以金样只在采集它的那台 Windows 机器、那个目录下成立。CI 和任何其他检出都会红。
修法:
- 在
scripts/research/api_service_extract_golden.py的规范化里,把所有字符串值中的仓库根目录绝对路径(str(ROOT),以及 Windows 下的正斜杠 / 反斜杠两种写法)替换成固定占位符<ROOT>,并把其后的路径分隔符统一成/。不要按字段名白名单去删,避免以后新增路径字段又漏。 - 在基线(
origin/staging上本单开工时的 SHA,写进fixtureProvenance)重新采集金样,覆盖tests/golden/api_server_service_extract_v1.json。 - 在本分支上用
check_golden()对照,全部相等。
验收标准:Claude 在 Linux 上、任意检出目录下单独跑这条测试为绿;Grok 在 Windows 上同样为绿。PROGRESS 里贴两次采集(基线、本分支)的 8 个哈希。
F2 · 测试过程中删除共用排盘缓存目录,并行时打红别的测试(必做)
现象:全量 pytest -n 4 时 test_capture_commercial_astrology_e2e_contexts.py::test_capture_writes_runtime_contexts_without_required_layer_echo 变红;单独跑为绿,基线全量也为绿。
根因:clear_chart_cache() 对仓库内的 scratch/local/api_chart_cache 做 shutil.rmtree。全量测试多进程并行,其他测试正在读写同一个目录,被中途删掉。研究脚本手动跑时清缓存没问题,但放进 pytest 就成了共享状态破坏。
修法(二选一,推荐 a):
- a. 不删目录,改为在采集期间设置环境变量
JYOTISH_API_CHART_CACHE_TTL_SECONDS=0让排盘缓存不生效(现有测试tests/test_commercial_domain_calculation_contract.py已用这个办法),采集结束恢复原值。先确认 TTL 为 0 时确实既不读也不写缓存;若仍会写入,则同时用monkeypatch/ 临时目录把_api_chart_cache_dir指向tmp_path。 - b. 测试里用
monkeypatch.setattr(jyotish_api_server, "_api_chart_cache_dir", lambda: tmp_path / "cache"),研究脚本的clear_chart_cache只清这个临时目录。
验收标准:
- 金样测试里不再出现对仓库内
scratch/local/api_chart_cache的删除(grep -n rmtree只允许作用于临时目录)。 - 本分支全量
pytest -n 4的失败清单与基线逐名一致(Claude 复跑)。 - 金样结论不变(缓存不生效时与清空缓存时的输出相同;如有差异,在 PROGRESS 写明并以「缓存不生效」为准重采)。
F3 · 方法数常量旁的旧三栏被改写(必做,小)
tests/test_api_server_growth_contract.py 里 JYOTISH_API_HANDLER_METHOD_COUNT_BASELINE 上方原有的三栏(原值:218(删占位回退之前)/ 新值:217 / 原因:BUG-1341 …)被改成了 原值:217 / 新值:217 / 原因:…,丢了 BUG-1341 那次下调的记录。
修法:恢复原来三行原样;本单的说明(数值未变)如需保留,另起一行注释写在其后,不覆盖历史。
验收标准:git diff origin/staging -- tests/test_api_server_growth_contract.py 中,原有三栏三行不再出现在删除行里。
不要做
- 不改拆类本身(T2/T3/T4 已通过),不动
scripts/jyotish_api_server.py。 - 不改
tests/test_api_server_security.py。 - 不放宽金样比对(不许改成只比键路径或字节数)。
回报
在 issue #70 回报新 SHA,表格里写:金样单独跑结果(Windows)、全量 pytest 失败清单相对基线的差(若 Windows 能跑)、F3 的 diff 片段。