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

13 KiB
Raw Permalink Blame History

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 dataclasscore/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-522DiagnosePrompts L494-501 / EvolvePrompts L518-522
死字段 consolidate_system 内联替代 core/evolution/evolve.py:997 _CONSOLIDATE_SYSTEM(消费点 L1036
死字段 span_eval_user 无消费 diagnose 只用 prompts.span_eval_systemcore/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.mdprompts/evolve_system.mdprompts/evolve_tool.mdprompts/evolve_rank.mdprompts/slow_momentum.md(从 TRM4 拷贝)

  • Test: tests/unit/test_evolve_prompts_present.py

  • Step 1: 写契约冒烟测试(先失败)

tests/unit/test_evolve_prompts_present.py

"""校验 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 参数化用例全 FAILAssertionError: 缺模板: prompts/evolve_skill.md 等;TRM5 当前无这 5 个模板)。

  • Step 3: 拷贝 5 个模板

Run:

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-1435parsed["edits_extract"]/parsed["edits_verify"])。

  • Step 6: 提交
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:682tests/unit/test_diagnose.py:753tests/unit/test_evolution_types.py:352,370

  • Step 1: 删 dataclass 字段与 docstring

core/evolution/types.pyDiagnosePromptsspan_eval_user

  • docstring 删行 span_eval_user: span 评估用户提示模板。L487
  • 字段删行 span_eval_user: strL497

EvolvePromptsconsolidate_system

  • docstring 删行 consolidate_system: appendix 压缩系统提示。L515

  • 字段删行 consolidate_system: strL522

  • 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: 提交
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

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_promptsL2270-2272)与 _load_diagnose_promptsL2286-2288),以及 app/harness/video_split_cli.py _load_diagnose_promptsL365-367),把:

        def _read(name: str) -> str:
            p = Path("prompts") / name
            return p.read_text(encoding="utf-8") if p.exists() else ""

改为:

        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: 提交
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 个新模板存在且非空。