feat(review): 医生核对包入口;CEUS 运行目录的读取收进 runs

- 新模块 review(组织层,只依赖 library、answers、runs):把一次构建和它装入的
  CEUS 运行整理成医生可读的文件夹(CSV 带 BOM、说明与报告转 PDF、图片视频逐字节拷贝),
  入口 scripts/review_pack.py + config/review_pack.yaml。任务书 03。
- 读 CEUS 运行目录(failed.csv、结果目录、关键帧文件)从 build 挪进 runs,build 与
  review 都经它读;failed.csv 读取在边界上收严(步号须为整数、视频号不重复、列数固定)。
- library、answers 补只读函数;import-linter 增 review 契约。
- 文档:guides/医生核对包.md(过一轮硕士生阅读),结构.md 第三至八部分同步。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 06:04:19 -04:00
parent 14d6f8e153
commit c7373efde2
23 changed files with 1718 additions and 83 deletions
+13 -4
View File
@@ -1,5 +1,6 @@
"""测试用假 CEUS 运行目录:布局照 `scripts/ceus_quant.py` 写出的(failed.csv、snapshot/、
`<视频号>/summary.json`、`<视频号>/keyframes/<槽位>.png`),数值全部编造,不调显卡。
`<视频号>/summary.json`、`<视频号>/keyframes/<槽位>.png`、`<视频号>/tic.png`、`<视频号>/overlay.mp4`),
数值全部编造,不调显卡。tic.png 和 overlay.mp4 只是带视频号的几个字节(核对包按字节拷贝,不打开)。
summary.json 故意带上 tic.json 不该有的字段(视频号、视频 SHA-256、分割缓存键、帧号、拟合参数、
失败原因代码、推注时间、紫圈检出率),用来测 build 只按白名单挑字段。视频 SHA-256 和推注时间照
@@ -12,12 +13,14 @@ import json
from pathlib import Path
from typing import Any
import yaml
from PIL import Image, PngImagePlugin
from fake_delivery import VIDEO_BYTES
from fake_delivery import REPO_ROOT, VIDEO_BYTES
SLOTS = ("B0", "D1", "D2", "D3", "D4", "F1", "F2")
CURVES = ("roi_all", "roi_perf", "roi_pan", "background_circle")
CEUS_YAML = REPO_ROOT / "config" / "ceus.yaml"
UNLOCATED_REASON = "拟合曲线上没有 D4 时刻(编造的原因)"
@@ -112,8 +115,12 @@ def write_run(
槽位,`failed` 是 failed.csv 的行。"""
(run_dir / "snapshot").mkdir(parents=True)
(run_dir / "snapshot" / "snapshot.json").write_text("{}", encoding="utf-8")
ceus_yaml = f"paths:\n delivery_dir: {json.dumps(str(delivery_dir), ensure_ascii=False)}\n"
(run_dir / "snapshot" / "ceus.yaml").write_text(ceus_yaml, encoding="utf-8")
# 快照里的 ceus.yaml 照仓库里的那份,只把交付包路径换成这份假交付包。
ceus_yaml = yaml.safe_load(CEUS_YAML.read_text(encoding="utf-8"))
ceus_yaml["paths"]["delivery_dir"] = str(delivery_dir)
(run_dir / "snapshot" / "ceus.yaml").write_text(
yaml.safe_dump(ceus_yaml, allow_unicode=True), encoding="utf-8"
)
with (run_dir / "failed.csv").open("w", encoding="utf-8", newline="") as handle:
writer = csv.writer(handle)
writer.writerow(("video_id", "step", "reason"))
@@ -124,4 +131,6 @@ def write_run(
(run_dir / video_id / "summary.json").write_text(content, encoding="utf-8")
for shade, slot in enumerate(located):
keyframe_png(run_dir / video_id / "keyframes" / f"{slot}.png", shade * 30)
(run_dir / video_id / "tic.png").write_bytes(f"fake tic.png {video_id}".encode())
(run_dir / video_id / "overlay.mp4").write_bytes(f"fake overlay.mp4 {video_id}".encode())
return run_dir