① 状态板校正:09-15~16 这 10 份任务书的实现早已合入 staging 并经逐单 验收,状态板却仍写「待领取 / 待验收」。改成「已验收」并补上落点 SHA 与验收要点;顺带补齐 8 个 PROGRESS 列。防复发写进「命名与归档」: 实现合入的同一次推送必须同时改状态板那一行。 ② 新增 TASK-home-state-lowering-batch2-20260916(不占 BUG 号): 第一批f8e607c2已验收(useState 66→52、useRef 41→39、散装 rectification* 归零)。本单搬剩下三簇 session*10 / profile*6 / synastry*4,目标 52→≤36;并修第一批尾巴—— createRectificationShellSetters 每帧新身份多出的那条 exhaustive-deps warning(119→120),正解是稳住 setter 身份而不是塞进 deps。 ③ 新增 TASK-api-server-backdoor-close-20260916(不占 BUG 号): 实测四处 __new__ 的传递闭包只有 8 方法 / 314 行且 0 个碰 HTTP 上下文, 占全类 4%。所以关后门不必捆绑 2,000+ 行体量搬运。产品拍板阶段 2/3 不立单,由3b17c1b2换好的门禁长期推进。原 decomposition 单标为已取代。 ④ 新增 RECONCILE-20260916:另外 7 份 09-10~14 的单没有 PROGRESS、但 引用的 BUG 号都是 resolved,无法从 README 判断,列成一页纸让执行方 回填;另附三条确定没做的证据、两条未闭环状态、BLK-001 仍红。 纯文档推送,不触发门禁、不发布镜像、不部署。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
9.1 KiB
TASK · 关掉 JyotishAPIHandler.__new__ 后门(314 行纯搬运)
- 日期:2026-09-16
- 基线 commit:
origin/staging@4f643aa0 - 执行分支:
codex/api-server-backdoor-close-20260916 - 落点:
scripts/jyotish_api_server.py、新建的scripts/下模块、scripts/consultation_workflow_service.py、scripts/capture_report_blocked_repairs_golden.py、scripts/local_accuracy_report.py、tests/test_api_server_growth_contract.py - 取代
TASK-api-server-decomposition-20260916的阶段 1;该单其余阶段的处置见 §3.2 - 与
TASK-consultation-residual-hotspots-20260916(vedastro_*/yoga_engine)、TASK-home-state-lowering-batch2-20260916(纯前端)无文件重叠,三单可并行 - 规模:8 个方法 / 314 行搬进独立模块。纯搬运,零行为变化。
1. 为什么把范围缩到 314 行
原任务书四个阶段(拆 __new__ → 抽 ≥150 行方法 → do_POST 改路由表 → 重新冻结)方向是对的,但它把「关后门」和「体量搬运」捆在了一起。我按调用链实测算了阶段 1 的传递闭包(从四处伪造实际借用的方法出发,跟着 self._x() 一路追):
| 数量 | |
|---|---|
| 需要搬的方法 | 8 个 |
| 合计行数 | 314 行 |
其中真的碰 HTTP 上下文(self.headers / wfile / rfile / path / client_address) |
0 个 |
占 JyotishAPIHandler 全类(225 方法 / 8,219 行)的比例 |
4 % / 4 % |
关后门只需要一次 314 行的纯搬运,而且这 8 个方法一个都不碰 HTTP,没有隐藏耦合。
四处伪造实际借用的入口方法只有 5 个:
| 位置 | 借用的方法 |
|---|---|
scripts/consultation_workflow_service.py:20 / :27 |
_compute_vedastro_gateway_archives、_high_rigor_vedastro_official_summary、_interpretation_source_runtime_coverage |
scripts/capture_report_blocked_repairs_golden.py:59 |
_compute_consultation_workflow |
scripts/local_accuracy_report.py:141 |
_compute_synastry |
2. 事故实证
handler = JyotishAPIHandler.__new__(JyotishAPIHandler) # 不跑 __init__ 的空壳
__new__ 绕过 BaseHTTPRequestHandler.__init__,造出来的对象没有 headers / wfile / rfile / client_address。今天能跑,只是因为被借用的这 8 个方法碰巧没碰它们——我逐个查过,0 个碰。
这是一颗类型检查看不见的地雷:任何人往这 8 个方法(或它们调用的任何方法)里加一行 self.headers.get(...),MCP 与两个离线脚本就会在运行时 AttributeError,而单元测试与 tsc 都发现不了。
更根本的是依赖方向反了:consultation_workflow_service.py 的 docstring 自称是「shared consultation workflow boundary for API and MCP callers」,实际却反过来依赖 HTTP 单体文件,只为借它身上的方法。
全仓依赖该模块的文件有 43 个(scripts/、tests/、mcp_server.py)。
3. 决策记录
产品 2026-09-16 拍板:
- 只做「关后门」这一件事,不做体量搬运。 原任务书的阶段 2(抽 7 个 ≥150 行方法,2,073 行)与阶段 3(78 个
elif改路由表)本轮不做。理由:那是 2,000+ 行的大搬运、零用户价值,而tests/test_api_server_security.py有 3,841 行断言绑在这个类上——风险与收益不匹配。 - 阶段 2/3 不另立单,改由门禁长期推进。
3b17c1b2已把增长冻结的主门从行数换成「类方法数不得增长 +__new__计数不得增长」。这意味着以后任何想往这个类里加方法的改动都会被拦,只能往外搬——换口径本身已经替代了一次性大搬运的必要性。这条写进docs/tasks/README.md的状态板备注,避免下一轮有人又提。 - 纯搬运,零行为变化。
tests/test_api_server_security.py的 3,841 行断言一条不许改。 - 收尾把
__new__计数基线收到 0。 这是本单唯一不可伪造的成功判据。
4. 硬红线
grep -rn "JyotishAPIHandler.__new__" --include=*.py .(排除skills/*/versions/**)必须零命中,并且这条断言要写进tests/test_api_server_growth_contract.py,基线从 4 收到 0。tests/test_api_server_security.py一条断言不许改。 若它红了,说明不是纯搬运——回去改实现,不是改断言。- 不得顺手搬阶段 2/3 的方法。 类方法数会因本单下降,把新值写进合同测试即可;不得为了多降一点而扩大范围。
- 搬出去的模块不得再反向 import
jyotish_api_server——那等于把后门换了个地方开。要有一条断言钉住这个方向。 - 本单会与
TASK-consultation-external-evidence-cache-20260915(已合入e61535f4)的改动共处同一文件:它在execute_consultation_workflow里加了走缓存模块的分支。照常搬运,不得把它改回去。 - 不得顺手升级依赖、不得顺手修不在本单里的 warning。
5. 任务分解
5.1 先自己把闭包算一遍
不要抄本任务书的 8 个方法。开工时用同样的方法重算(从 5 个入口方法出发,跟着 self._x() 追传递闭包,并标出哪些碰 HTTP 上下文),结果写进进度记录。代码可能已经漂移。
- 验收:进度记录里有闭包清单、行数、以及「碰 HTTP 上下文的有几个」。
- 验收:若重算出来有方法碰 HTTP 上下文,停手,把那几个列出来先问——本单的前提是它们都不碰。
5.2 把闭包搬进独立模块
按职责放进 scripts/ 下的新模块(建议按 vedastro 证据 / 咨询工作流 / 合盘分组,不要一股脑塞一个文件)。JyotishAPIHandler 里对应位置改成薄调用。
- 验收:
scripts/jyotish_api_server.py的类方法数下降,新值写进合同测试。 - 验收:新模块不 import
jyotish_api_server,有断言。
5.3 三个调用方改成直接 import
consultation_workflow_service.py(两处)、capture_report_blocked_repairs_golden.py、local_accuracy_report.py 改成直接 import 新模块,删掉 JyotishAPIHandler.__new__ 与对 jyotish_api_server 的 import。
- 验收:三个文件都不再 import
jyotish_api_server。 - 验收:MCP 侧(
mcp_server.py:741/:4749经由consultation_workflow_service)仍然可用——至少一条端到端断言。
5.4 合同测试收基线
tests/test_api_server_growth_contract.py:__new__ 计数基线 4 → 0;类方法数基线更新为收尾实测值;行数粗护栏 baseline 重设为收尾实测 + 300。同步更新文件顶部 docstring 的日期与说明。
- 验收:人为加回一处
JyotishAPIHandler.__new__必须让测试变红(贴反向验证)。 - 验收:人为加一个类方法必须变红(贴反向验证)。
- 验收:该文件既有的三条断言(
AGENTS.md必须含must not grow/thinly registered、该测试必须在CORE_PYTEST_TARGETS与快速门里)仍绿。
5.5 记录
本单不产生 Bug 记录(结构改造,不是缺陷),不进 CHANGELOG.md(无用户可感知变化)。进度记录里必须有:闭包清单、搬前/搬后的类方法数与行数、两次反向验证结果。
同轮把原 TASK-api-server-decomposition-20260916 在状态板上标成已取代(阶段 1 由本单完成;阶段 2/3 不立单,由门禁长期推进)。
6. 让步顺序
- 5.1 不得砍——闭包没重算就动手,等于拿本任务书的旧数字赌代码没漂。
- 5.2 + 5.3 是主体,必须一起做(只搬不改调用方,后门还在)。
- 5.4 不得砍——
__new__计数收到 0 是本单唯一的成功判据。 - 5.5 不得砍。
7. 开工前置命令
git fetch origin --prune
git worktree add -b codex/api-server-backdoor-close-20260916 \
.worktrees/api-server-backdoor-close-20260916 origin/staging
cd .worktrees/api-server-backdoor-close-20260916
git status -sb | head -1
# 重算基线
grep -rn "JyotishAPIHandler.__new__" --include=*.py . | grep -v "skills/.*/versions/"
grep -cE '^ (async )?def ' scripts/jyotish_api_server.py
wc -l scripts/jyotish_api_server.py
python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45 # AGENTS §9
开工前必读:docs/research/pre_work_error_ledger.md(AGENTS §9);原 TASK-api-server-decomposition-20260916.md(它对根因的分析仍然有效,只是范围被本单收窄)。
验收命令:
.venv/bin/python -m pytest tests/test_api_server_security.py tests/test_api_server_growth_contract.py \
tests/test_consultation_consumer_context.py tests/test_vedastro_gateway.py
.venv/bin/python scripts/run_quality_gate.py --profile quick
8. BUG 编号起点
本单不占 BUG 号。基线 4f643aa0 上最大号 BUG-733;734/735 已被 TASK-consultation-residual-hotspots-20260916 预占。
9. 不在本单范围
- 阶段 2(抽 ≥150 行业务方法)与阶段 3(
do_POST路由表)——不立单,由门禁长期推进 execute_consultation_workflow里的任何业务逻辑改动- 外网探测与 yoga 编译缓存(见
TASK-consultation-residual-hotspots-20260916)