# 训练前修复分支 final whole-implementation review

> 2026-07-16。分支 `feat/preflight-train-fixes`，4 工作包 33 个实现 commit。SDD 每 task 三审 + 本次 Codex 跨 task 整分支终审（gpt-5.4 xhigh）。
> 覆盖矩阵：21 项确认缺陷 + 接线 2 项 + WP1 死字段清理**全部实现落地**（Codex 逐项核对 file:line 证据）。核心算法保真（#4/#5/#6/#7/#8/#9/#10/#12）、依赖方向（core 不依赖 app/adapters）、loguru、原子写、死字段无残留——全部 verified OK。

## 执行结果汇总

| WP | 内容 | commit 数 | Codex 三审结果 |
|----|------|----------|---------------|
| WP1 | 模板迁移 + 死字段 + fail-loud | 3 | 无任何问题（模板 cmp TRM4 逐字节一致） |
| WP2 | 切分与接线（tier/功效/seed/覆盖保护） | 7 | 无 Critical；2 Important（--force 备份健壮性）已修 |
| WP4 | 韧性与持久化（10 项） | 11 | 无 Critical；2 Important（全 INFRA/parse_error 护栏）已修 |
| WP3 | 训练循环与进化（9 项，5 算法保真区） | 12 | 无 Critical；2 Important（单元计数/全过滤 fail-fast）已修 |

全量 1523 tests passed，ruff 全绿。

## Final review 发现与处置

### C-1（必须，runbook）——.env 未同步导致 train 启动崩溃
`.env:65` 仍 `REDIS_CACHE_TTL=0`，WP4 Task 2 的 fail-loud 会在 `main.py` / `video_split_cli` 构建 Redis 缓存时抛 ValueError，训练进不到 `runner.train`。`.env.example` 已改 86400 但 `.env`（gitignore）需**手动**改。→ 训练前 runbook 第一步：`REDIS_CACHE_TTL` 改为正整数（如 86400）。

### I-3 / I-4（真实缺陷，✅ 已修）
| # | 缺陷 | 首跑是否触发 | 处置（commit） |
|---|------|:---:|------|
| I-4 | 显式 task_types 子集不过滤冻结全局 pools → 训练非请求题型 | 全 12 类首跑**不触发** | ✅ `ee69721`：`_filter_untrainable_types` 候选集先与 task_types 取交集，非请求题型剔除，fail-fast 保留 |
| I-3 | gate INFRA 护栏分子按 record、分母按 unit，AR pair 误触发 gate_guard_err | 全 single 首跑**不触发** | ✅ `b3ba11c`：INFRA 分子改按 unit 数；顺带修正 2 个既有护栏测试的 mock 不真实性（per-record 与 summary 不一致，真实推理不会发生），保真套件全绿 |

> M-2（`6911c83`）：`INFRA_STOP_REASONS` 提为 core 公共常量、app import。**残留 future work**：`app/harness/video_split_cli.py` 仍有第三份独立副本（本次 scope 外），待后续 dedup。

### I-1 / I-2（技术论证：实际影响可控，记录不强修）
| # | Codex 关切 | 论证 | 首跑建议 |
|---|-----------|------|---------|
| I-1 | cache_salt 未贯穿工具内 LLM/VLM（observe_frame VLM、summarizer） | 工具内是**确定性子程序**——同帧→同 VLM 描述、同轨迹→同 summary，重放语义正确甚至期望；需跨 epoch 重采样的 agent **决策** LLM（主 loop chat）已正确注入 run_id 盐 | 改 .env 后可跑；若谨慎可首跑关 Redis 缓存 |
| I-2 | 基线臂 miss 新鲜推理注入 epoch salt，不符固定快照 | BaselineCache（`baseline_cache.json`）**跨 run 持久**：快照一旦建立即稳定，epoch salt 只作用于"首次建立快照的那一次采样"（本就要采一次），中断重跑命中持久缓存 | 影响限于首次采样，可接受 |

> 若后续要彻底贯彻 P1-1（把 cache_salt 显式化、基线臂传 None、工具内也隔离），记 future work——需把 Task 9 的"inference 内部用 run_id"重构为"调用方显式传 cache_salt"，风险中等。

### Minor（future work / 顺手）
- **M-2**：INFRA stop-reason 集合在 core/app 各一份 → 已派 app import core 常量消除漂移。
- **M-1**：`_atomic_write_json` 在 pools.py/workspace.py 两份等价实现（行为一致，可抽共享 helper）。
- **M-3**：部分 analyses JSON（非 checkpoint/manifest/pools）仍直接 write_text（不破坏续跑主状态）。

## 训练前 runbook（结合本分支）

1. **改 `.env`：`REDIS_CACHE_TTL=0` → `86400`**（C-1，不改则启动崩）。
2. 备份 `workspaces/video-split/` 冻结产物。改 `config/video_split.yaml` 已含 `val_ratio: 0.4`（WP2），重跑 `build_video_split.sh`（诊断命中缓存秒级重切）→ 核对 val 错题≥20 / T2 入 diag / tier 感知生效。
3. 建 seed：`extract_run_db(infer_adhoc, dedupe_per_question=True)` + `init_seed('adhoc-baseline', pools_json=…, split_manifest=…)`（WP2 接线）。
4. 新建 `config/train_videomme.yaml` + `scripts/train_videomme.sh`：`epochs=3`、`early_stop_patience=2`（epoch 语义 WP3）、`run_holdout_eval=true`（去重版 WP3）、`trainable_min_units=8`（WP3 新字段，必填）、全 12 类（避免 I-4）、其余 gate/batch 沿用 default.yaml。
5. tmux 启动 `CUDA_VISIBLE_DEVICES=0 bash scripts/train_videomme.sh`。预检会自动剔除微型题型（OCR/Spatial/Temporal Perception 等 5 类），打印剔除清单。
