Files
Video-Tree-TRM5/research-wiki/plans/2026-07-16-preflight-wp1-asset-migration.md
T

254 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WP1 资产迁移 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 迁移 5 个遗漏的 TRM4 进化/动量模板到 TRM5,删除 2 个死字段,把加载器的静默空串兜底改为 fail-loud,解锁自进化引擎。
**Architecture:** 进化引导 prompt 是引擎的一部分(放项目根 `prompts/`,不参与版本化进化)。TRM4 五模板的输出 JSON 契约与 TRM5 解析代码已核实完全对齐,可直接拷贝。执行顺序:先迁移模板 → 删死字段(`consolidate_system`/`span_eval_user`,零消费)→ 加载器 fail-loud(顺序关键:先删死字段,fail-loud 才不会对不存在也不需要的模板报错)。
**Tech Stack:** Python 3.11、pytest、frozen dataclass`core/evolution/types.py`)。
**设计源**`research-wiki/designs/2026-07-16-preflight-fixes-design.md §4`
---
## 关键锚点(实现前必读)
| 用途 | 位置 |
|------|------|
| TRM4 源模板 | `/home/iomgaa/Projects/Video-Tree-TRM4/prompts/{evolve_skill,evolve_system,evolve_tool,evolve_rank,slow_momentum}.md` |
| evolve 加载器 | `app/harness/runner.py:2266-2280` `_load_evolve_prompts` |
| diagnose 加载器 | `app/harness/runner.py:2282-2299` `_load_diagnose_prompts` |
| 平行 diagnose 加载器 | `app/harness/video_split_cli.py:362-378` `_load_diagnose_prompts` |
| dataclass 定义 | `core/evolution/types.py:477-522``DiagnosePrompts` L494-501 / `EvolvePrompts` L518-522 |
| 死字段 `consolidate_system` 内联替代 | `core/evolution/evolve.py:997` `_CONSOLIDATE_SYSTEM`(消费点 L1036 |
| 死字段 `span_eval_user` 无消费 | diagnose 只用 `prompts.span_eval_system``core/evolution/diagnose.py:511`),user_prompt 内联构造 |
| 测试 fixture | `test_evolve.py:682` `consolidate_system="cons"``test_diagnose.py:753` `span_eval_user=""``test_evolution_types.py:352` `span_eval_user="p4"` / `:370` `consolidate_system="consolidate_tmpl"` |
## 核心算法保真校验
本计划不迁移/不改核心算法(ARCHITECTURE §6),只搬运模板文件 + 清理死字段 + 加 fail-loud。模板内容是 evolve 引擎(算法 #8)的输入数据,非算法逻辑本身;迁移已核实输出契约(`suggestions`/`edits`/`edits_extract`/`edits_verify`/`selected_indices`/`slow_update_content`)与 TRM5 解析代码逐字对齐。**保真检查点(Task 1 Step 4**:加载 evolve_tool.md 后确认其要求 LLM 返回 `edits_extract`+`edits_verify` 双键(对齐 `evolve.py:1433-1435`)。
---
## Task 1: 迁移 5 个 TRM4 模板
**Files:**
- Create: `prompts/evolve_skill.md``prompts/evolve_system.md``prompts/evolve_tool.md``prompts/evolve_rank.md``prompts/slow_momentum.md`(从 TRM4 拷贝)
- Test: `tests/unit/test_evolve_prompts_present.py`
- [ ] **Step 1: 写契约冒烟测试(先失败)**
`tests/unit/test_evolve_prompts_present.py`
```python
"""校验 5 个进化/动量模板存在且输出契约关键词与解析代码对齐。"""
from pathlib import Path
import pytest
_PROMPTS_DIR = Path("prompts")
@pytest.mark.parametrize(
"name, required_tokens",
[
("evolve_skill.md", ["suggestions", "edits"]),
("evolve_system.md", ["suggestions", "edits"]),
("evolve_tool.md", ["edits_extract", "edits_verify"]),
("evolve_rank.md", ["selected_indices"]),
("slow_momentum.md", ["slow_update_content"]),
],
)
def test_evolve_template_present_and_contract(name: str, required_tokens: list[str]) -> None:
path = _PROMPTS_DIR / name
assert path.exists(), f"缺模板: {path}"
text = path.read_text(encoding="utf-8")
assert text.strip(), f"模板为空: {path}"
for token in required_tokens:
assert token in text, f"{name} 缺输出契约关键词 {token!r}(与解析代码不对齐)"
```
- [ ] **Step 2: 运行确认失败(模板尚未迁移)**
Run: `conda run -n Video-Tree-TRM python -m pytest tests/unit/test_evolve_prompts_present.py -v`
Expected: 5 参数化用例全 FAIL`AssertionError: 缺模板: prompts/evolve_skill.md` 等;TRM5 当前无这 5 个模板)。
- [ ] **Step 3: 拷贝 5 个模板**
Run:
```bash
cp /home/iomgaa/Projects/Video-Tree-TRM4/prompts/evolve_skill.md prompts/evolve_skill.md
cp /home/iomgaa/Projects/Video-Tree-TRM4/prompts/evolve_system.md prompts/evolve_system.md
cp /home/iomgaa/Projects/Video-Tree-TRM4/prompts/evolve_tool.md prompts/evolve_tool.md
cp /home/iomgaa/Projects/Video-Tree-TRM4/prompts/evolve_rank.md prompts/evolve_rank.md
cp /home/iomgaa/Projects/Video-Tree-TRM4/prompts/slow_momentum.md prompts/slow_momentum.md
```
Expected: 5 文件存在于 `prompts/`
- [ ] **Step 4: 运行确认通过**
Run: `conda run -n Video-Tree-TRM python -m pytest tests/unit/test_evolve_prompts_present.py -v`
Expected: 5 参数化用例全 PASS。若 evolve_tool.md 缺 `edits_extract`/`edits_verify` 则契约不符——停止并逐行比对 TRM4 源。
- [ ] **Step 5: 保真检查点**
Run: `conda run -n Video-Tree-TRM python -c "print('edits_extract' in open('prompts/evolve_tool.md').read() and 'edits_verify' in open('prompts/evolve_tool.md').read())"`
Expected: `True`(对齐 `evolve.py:1433-1435``parsed["edits_extract"]`/`parsed["edits_verify"]`)。
- [ ] **Step 6: 提交**
```bash
git add prompts/evolve_skill.md prompts/evolve_system.md prompts/evolve_tool.md prompts/evolve_rank.md prompts/slow_momentum.md tests/unit/test_evolve_prompts_present.py
git commit -m "feat: migrate 5 evolve/momentum templates from TRM4 (algo #8)"
```
---
## Task 2: 删除 2 个死字段(consolidate_system / span_eval_user
**Files:**
- Modify: `core/evolution/types.py:494-501,518-522`
- Modify: `app/harness/runner.py:2279,2294`
- Modify: `app/harness/video_split_cli.py:374`
- Modify: `tests/unit/test_evolve.py:682``tests/unit/test_diagnose.py:753``tests/unit/test_evolution_types.py:352,370`
- [ ] **Step 1: 删 dataclass 字段与 docstring**
`core/evolution/types.py``DiagnosePrompts``span_eval_user`
- docstring 删行 ` span_eval_user: span 评估用户提示模板。`L487
- 字段删行 ` span_eval_user: str`L497
`EvolvePrompts``consolidate_system`
- docstring 删行 ` consolidate_system: appendix 压缩系统提示。`L515
- 字段删行 ` consolidate_system: str`L522
- [ ] **Step 2: 删加载器对死字段的 `_read` 行**
`app/harness/runner.py`
- `_load_evolve_prompts` 删行 ` consolidate_system=_read("consolidate_system.md"),`L2279
- `_load_diagnose_prompts` 删行 ` span_eval_user=_read("span_eval_user.md"),`L2294
`app/harness/video_split_cli.py`
- `_load_diagnose_prompts` 删行 ` span_eval_user=_read("span_eval_user.md"),`L374
- [ ] **Step 3: 删测试 fixture 对死字段的赋值 + 更新 docstring**
- `tests/unit/test_evolve.py:684` 删行 ` consolidate_system="cons",`
- `tests/unit/test_diagnose.py:753` 删行 ` span_eval_user="",`
- `tests/unit/test_evolution_types.py:352` 删行 ` span_eval_user="p4",`
- `tests/unit/test_evolution_types.py:370` 删行 ` consolidate_system="consolidate_tmpl",`
- `tests/unit/test_evolution_types.py:347` 的文档字符串"DiagnosePrompts 8 个模板字段"改为"7 个"`:364` 的"EvolvePrompts 5 个模板字段"改为"4 个"(删字段后数量变化)。
注:`test_evolution_types.py` 若有断言逐字段比对或字段计数,同步移除对两个死字段的断言(读该测试确认,删净引用)。上述行号以当前代码为准,实现前 `grep -n consolidate_system\|span_eval_user tests/unit/test_evolution_types.py` 复核。
- [ ] **Step 4: 运行相关测试确认通过**
Run: `conda run -n Video-Tree-TRM python -m pytest tests/unit/test_evolve.py tests/unit/test_diagnose.py tests/unit/test_evolution_types.py -q`
Expected: 全 PASS(无 `TypeError: unexpected keyword argument` / 无 `missing positional argument`)。
- [ ] **Step 5: 全库确认无残留引用**
Run: `conda run -n Video-Tree-TRM python -c "import subprocess; r=subprocess.run(['grep','-rn','consolidate_system\|span_eval_user','core/','app/','adapters/','tests/'],capture_output=True,text=True); print(r.stdout)"`
Expected: 空输出(`consolidate_appendix` 用内联 `_CONSOLIDATE_SYSTEM` 不算 `consolidate_system` 字段引用;若出现请确认非 dataclass 字段引用)。
- [ ] **Step 6: 提交**
```bash
git add core/evolution/types.py app/harness/runner.py app/harness/video_split_cli.py tests/unit/test_evolve.py tests/unit/test_diagnose.py tests/unit/test_evolution_types.py
git commit -m "refactor: drop dead prompt fields consolidate_system/span_eval_user"
```
---
## Task 3: 加载器 fail-loud(缺模板即报错)
**Files:**
- Modify: `app/harness/runner.py:2270-2272,2286-2288`
- Modify: `app/harness/video_split_cli.py:365-367`
- Test: `tests/unit/test_evolve_prompts_present.py`(追加)
- [ ] **Step 1: 追加 fail-loud 测试(直接调真实加载器)**
`tests/unit/test_evolve_prompts_present.py` 追加——直接驱动真实 loader(不复制 _read 逻辑),在无模板的空 cwd 下断言 `FileNotFoundError`
```python
def test_video_split_loader_fail_loud_on_missing(tmp_path, monkeypatch):
"""video_split_cli 的真实 diagnose 加载器缺模板必须 FileNotFoundError。"""
monkeypatch.chdir(tmp_path) # 空目录,无 prompts/*.md
from app.harness.video_split_cli import _load_diagnose_prompts
with pytest.raises(FileNotFoundError, match="缺进化/诊断模板"):
_load_diagnose_prompts()
def test_runner_evolve_loader_fail_loud_on_missing(tmp_path, monkeypatch):
"""runner 的真实 evolve 加载器缺模板必须 FileNotFoundError。"""
monkeypatch.chdir(tmp_path)
from app.harness.runner import Runner
r = object.__new__(Runner) # 绕过 __init__,仅测无状态加载器方法
with pytest.raises(FileNotFoundError, match="缺进化/诊断模板"):
r._load_evolve_prompts()
def test_runner_diagnose_loader_fail_loud_on_missing(tmp_path, monkeypatch):
"""runner 的真实 diagnose 加载器缺模板必须 FileNotFoundError。"""
monkeypatch.chdir(tmp_path)
from app.harness.runner import Runner
r = object.__new__(Runner)
with pytest.raises(FileNotFoundError, match="缺进化/诊断模板"):
r._load_diagnose_prompts()
```
> 这三个测试直接调真实 loader`_load_evolve_prompts`/`_load_diagnose_prompts` 无 self 状态依赖,`object.__new__` 可安全调用);修复前静默返回空串不抛,故 Step 2 前必 FAIL。
- [ ] **Step 2: 三处 `_read` 闭包改 fail-loud**
`app/harness/runner.py` `_load_evolve_prompts`L2270-2272)与 `_load_diagnose_prompts`L2286-2288),以及 `app/harness/video_split_cli.py` `_load_diagnose_prompts`L365-367),把:
```python
def _read(name: str) -> str:
p = Path("prompts") / name
return p.read_text(encoding="utf-8") if p.exists() else ""
```
改为:
```python
def _read(name: str) -> str:
p = Path("prompts") / name
if not p.exists():
raise FileNotFoundError(f"缺进化/诊断模板: {p}(请从 TRM4 迁移或检查 prompts/")
return p.read_text(encoding="utf-8")
```
runner.py 缩进 12 空格;video_split_cli.py 的 `_read` 缩进按其函数体,见 L365 为 8 空格——按各自现场缩进套用。)
- [ ] **Step 3: 运行测试确认通过**
Run: `conda run -n Video-Tree-TRM python -m pytest tests/unit/test_evolve_prompts_present.py -v`
Expected: 全 PASS。
- [ ] **Step 4: runner 其他行为回归(非 fail-loud 验证)**
fail-loud 已由 Step 3 的三个真实 loader 测试验证;此步仅确认模板迁移 + loader 改动未破坏 runner 其他行为。
Run: `conda run -n Video-Tree-TRM python -m pytest tests/unit/test_harness_runner.py -q`
Expected: 全 PASS(模板已迁移,真实加载走成功分支)。
- [ ] **Step 5: 提交**
```bash
git add app/harness/runner.py app/harness/video_split_cli.py tests/unit/test_evolve_prompts_present.py
git commit -m "fix: fail-loud on missing evolve/diagnose templates (no silent empty)"
```
---
## Self-Review(作者自查,执行者复核)
- [ ] 5 模板均已迁移且契约测试覆盖关键字段。
- [ ] `consolidate_system`/`span_eval_user` 在 core/app/tests 全库无残留字段引用。
- [ ] 三处 loaderrunner 两处 + video_split_cli 一处)均已 fail-loud。
- [ ] 执行顺序正确:Task 2(删死字段)先于 Task 3(fail-loud),避免对不需要的模板报错。
## 验收标准
1. `pytest tests/unit/test_evolve_prompts_present.py tests/unit/test_evolve.py tests/unit/test_diagnose.py tests/unit/test_evolution_types.py tests/unit/test_harness_runner.py` 全绿。
2. `grep -rn 'consolidate_system\|span_eval_user' core/ app/ tests/` 无 dataclass 字段残留。
3. `prompts/` 下 5 个新模板存在且非空。