236 lines
12 KiB
Markdown
236 lines
12 KiB
Markdown
# 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: 拷贝 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 2: 写契约冒烟测试(先失败)**
|
||
|
||
`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 3: 运行确认通过(模板已在 Step 1 拷入)**
|
||
|
||
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 4: 保真检查点**
|
||
|
||
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 5: 提交**
|
||
|
||
```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 对死字段的赋值**
|
||
|
||
- `tests/unit/test_evolve.py:682` 删行 ` 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",`
|
||
|
||
注:`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,sys; r=subprocess.run(['grep','-rn','consolidate_system\|span_eval_user','core/','app/','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` 追加:
|
||
```python
|
||
def test_loader_fail_loud_on_missing_template(tmp_path, monkeypatch):
|
||
"""加载器遇缺失模板必须抛 FileNotFoundError,不静默返回空串。"""
|
||
monkeypatch.chdir(tmp_path) # 空目录下无 prompts/,_read 应 fail-loud
|
||
(tmp_path / "prompts").mkdir()
|
||
from app.harness.runner import Runner
|
||
|
||
# 直接测私有 _read 语义:借最小构造不便,改测行为——缺文件应 raise
|
||
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")
|
||
|
||
with pytest.raises(FileNotFoundError, match="缺进化/诊断模板"):
|
||
_read("evolve_skill.md")
|
||
```
|
||
|
||
> 说明:`_read` 是嵌套闭包不易直接导入,此测试固化期望语义(缺文件 raise + 消息含"缺进化/诊断模板");Step 2 把三处闭包改成同款实现,集成层由 `test_harness_runner.py` 现有加载路径覆盖。
|
||
|
||
- [ ] **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 加载路径回归**
|
||
|
||
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 全库无残留字段引用。
|
||
- [ ] 三处 loader(runner 两处 + 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 个新模板存在且非空。
|