feat(build): 任务书 02 第四阶段代码——build 装入 CEUS 结果

- build.yaml 加必填字段 ceus_run(CEUS 运行目录或 null)。
- 不为 null 时按视频号找结果;在 failed.csv 里或缺结果目录的整例跳过,记 C15;关键帧图沿用 C14 检查。
- 资料库超声一路加 keyframes/<槽位>.png(去附加数据重编码)和 tic.json(白名单逐字段构造:
  四条曲线的拟合成败与 R²、灌注指标、紫圈曲线是否可用、7 个槽位的定位与视频时间或原因)。
- manifest 的 CEUS 来源写运行号;泄露扫描已覆盖 tic.json,补命中测试。
- 真实构建等配准改完、全量 CEUS 运行之后再做。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 05:55:57 -04:00
parent e78d1b50b8
commit c582fe426f
15 changed files with 683 additions and 35 deletions
+14 -2
View File
@@ -28,7 +28,7 @@ def _assert_no_finished_build(tmp_path: Path) -> None:
def _run(tmp_path: Path, root: Path, code_maps: dict[str, dict[int, str]] | None) -> None:
run_build(write_config(tmp_path, root, 7, code_maps), REPO_ROOT, NOW)
run_build(write_config(tmp_path, root, 7, code_maps, None), REPO_ROOT, NOW)
def test_t1_missing_summary_table(tmp_path: Path) -> None:
@@ -111,7 +111,7 @@ def _write_yaml(tmp_path: Path, body: str) -> Path:
return path
_BASE = "delivery_dir: d\nlibrary_root: l\nanswers_root: a\nalias_seed: 1\n"
_BASE = "delivery_dir: d\nlibrary_root: l\nanswers_root: a\nalias_seed: 1\nceus_run: null\n"
def test_config_decode_true_needs_code_maps(tmp_path: Path) -> None:
@@ -152,12 +152,24 @@ def test_config_relative_paths_resolve_against_repo_root(tmp_path: Path) -> None
assert config.library_root == Path("/repo/l")
assert config.answers_root == Path("/repo/a")
assert config.code_maps is None
assert config.ceus_run is None
body = _BASE.replace("ceus_run: null", "ceus_run: runs/ceus/r")
path = _write_yaml(tmp_path, body + "decode_codes: false\ncode_maps: null\n")
assert load_build_config(path, Path("/repo")).ceus_run == Path("/repo/runs/ceus/r")
def test_config_ceus_run_missing(tmp_path: Path) -> None:
body = _BASE.replace("ceus_run: null\n", "")
path = _write_yaml(tmp_path, body + "decode_codes: false\ncode_maps: null\n")
with pytest.raises(ValidationError, match="ceus_run"):
load_build_config(path, tmp_path)
def test_committed_config_is_valid() -> None:
config = load_build_config(REPO_ROOT / "config" / "build.yaml", REPO_ROOT)
assert config.decode_codes is False
assert config.code_maps is None
assert config.ceus_run is None
def test_config_duplicate_key(tmp_path: Path) -> None: