# ECR-002 **Title:** 拆分 `web/services/runtime.py` + 加深 `/api/analyze` 契约测试 **Status:** Done (Reviewed) **Date:** 2026-08-06 **Change Level:** L3(行为冻结;若 golden 漂移则升 L2) ## Change 将仍偏大的 `web/services/runtime.py` 按职责拆为可维护子模块;加深 analyze API 契约/快照测试;可选拆分主站巨型 `chart_tv.js`(本轮未做)。 ## Motivation ECR-001 CODE_REVIEW 非阻断债务:runtime 过大、契约测试偏浅、chart_tv 单体。不处理会继续抬高 Web 改动风险。 ## Scope ### Allowed - 物理拆分 `web/services/runtime.py` → 包 `web/services/runtime/`(state / timeframes / market_data / indicators / analyze / serialize + 门面) - 加深 `web/tests/`:固定 fixture / mock 行情下的关键字段快照与契约 - 补 `TF_DF(..., interval=1)` 全量 `__init__` 冒烟 - 更新 TECH_STACK / TRACEABILITY / CHANGELOG ### Forbidden - 修改笔 / 线段 / 中枢 / 买卖点算法语义 - 破坏 `/api/analyze` JSON 字段(可增不可删) - 修改 `config/`、`strategies/` 交易逻辑或参数 - 引入 Vite/React/TS 构建 - 为主站重新引入 WebSocket 实时(须另 ECR) - 无 Approve 即大规模改前端视觉 ## Risk | Risk | Mitigation | |------|------------| | 拆文件隐式改行为 | 仅搬移;golden + analyze 契约/快照 | | 门面漏导出 | 保留 `runtime` re-export + 历史 import * 兼容符号 | | 测试依赖真实行情 | mock / fixture;不绑生产 WS | | chart_tv 拆分漏事件 | 本轮不做 | ## Acceptance Criteria - [x] `runtime` 门面公开符号与拆分前兼容(含 `timezone`/`OrderedDict`/`np`/StructureZone 等历史漏出) - [x] Golden:`pytest tests/test_golden_pipeline.py` 通过 - [x] Analyze 契约/快照测试通过且覆盖关键字段清单以上 - [x] TF_DF 全量 init 冒烟通过 - [x] `config/` / `strategies/` 无交易逻辑 diff - [x] IMPLEMENTATION_REPORT / TEST_REPORT / CHANGELOG / TRACEABILITY 更新 - [x] CODE_REVIEW Approve ## Rollback `git revert` 本 ECR 提交;门面保留期可整包回滚。 ## Risk Review - Path: `docs/RISK_REVIEW/ECR-002.md` — N/A(不改交易决策语义) ## Linked - IDEA: `docs/IDEA/IDEA-003-runtime-split.md` - PRODUCT_SPEC: `docs/PRODUCT_SPEC/ECR-002-runtime-split.md` - ENGINEERING_SPEC: `docs/ENGINEERING_SPEC/ECR-002-runtime-split.md` - ADR: 引用 ADR-001(包内再拆,无新顶层布局 ADR) - EXPERIMENT: N/A - TRACEABILITY: Yes - IMPLEMENTATION_REPORT: `docs/IMPLEMENTATION_REPORT/ECR-002.md` - TEST_REPORT: `docs/TEST_REPORT/ECR-002.md` ## Origin - `docs/CODE_REVIEW/ECR-001.md` Findings 1–3、5