Files
vrsub/docs/代码审查问题跟踪.md
T

15 KiB
Raw Blame History

代码审查问题跟踪

本文件跟踪本次项目审查发现的问题、修复范围与验证结果。状态:待处理 / 处理中 / 已修复。只有完成实现与相关验证后才标记已修复;代码修改不代表已部署。

全部审查问题的修复统一在 fix/review-improvements 分支推进,验证完成后由用户合并到 master

缺陷清单

ID 优先级 问题 状态 验收标准
R01 P0 普通删除接口可能删除批量源视频目录;清理逻辑从输入路径推导删除范围 已修复 普通接口拒绝单独删除批量 run;手动与自动清理只删除该上传任务的私有目录;视频、旁挂字幕及其他任务文件不受影响
R02 P1 自适应线程池限流后可能扩容;退出标记位于积压队列尾部,缩容不及时 已修复 限流不增加并发;降低目标后不再超额提交;真实积压队列验证
R03 P1 最后节点执行时暂停再继续会覆盖有效下载 URI;批量缺产物仍清理并完成 已修复 收尾幂等,恢复后全部必需产物可下载;缺产物不清理工作空间
R04 P1 环形 DAG 可通过保存校验,执行失败后仍在 QUEUED 堵塞队列 已修复 保存/发布拒绝无效 DAG;历史无效任务进入 FAILED,不阻塞后续任务
R05 P1 翻译按固定四行解析 SRT;补齐行数不能保证文本与时间轴对应 已修复 合法多行 cue 正确解析;按稳定 ID 回填译文并校验缺失、重复项
R06 P1 OCR 跨空白帧合并相同字幕;临时请求失败被永久存为无文字 已修复 空白帧结束当前字幕段;无文字和可重试失败分开存档
R07 P2 抽帧/分块目录残留污染重跑;OCR/过滤存档无输入和参数指纹 待处理 输出减少时无旧文件混入;输入/有效参数变化时断点失效
R08 P2 批量任务创建与明细不原子;不区分工作流版本时的执行/收尾一致性 待处理(方案调整) 用户决定不区分工作流版本,不实施固定版本方案;工作线程只看到完整任务,收尾使用本次执行实际产物

优化与维护清单

下列项目为优化建议,收益需按真实负载验证,尚未承诺实施顺序。

ID 项目 状态 验收方向
O01 Whisper 模型缓存及上传/批量共享 GPU 并发额度 待处理 相同配置复用模型;初始化线程安全;显存有界
O02 Whisper 分块、LLM 翻译批次断点 待处理 中断后只补未完成部分;输入与参数身份匹配
O03 VAD 流式读取、向量化 RMS 待处理 与现有 RMS 结果一致;内存不随全片样本数增长;记录性能对比
O04 LLM 公共客户端、连接复用、统一限流重试 待处理 网络故障处理一致;提示词保留在各节点;避免重复计费与无界重试
O05 字幕纠错批量化、减少重复上下文生成 待处理 保留目标 ID;固定输入上下文;真实字幕质量验证
O06 合并媒体探测、减少 OCR 小文件,评估分段抽帧与 OCR 重叠执行 待处理 保持时间轴和落盘协议,测量 I/O 与吞吐变化
O07 统一 SRT 解析/序列化/时间戳,移除生产代码对 tests 包的依赖 待处理 正式安装包可运行;多行 cue、空字幕、时间精度回归通过
O08 统一运行状态、工作空间与 JSONL 存档公共能力 待处理 状态条件更新、文件归属明确、存档损坏可恢复
O09 后台线程停止与窗口统计可靠性 待处理 停止等待可中断;不丢弃仍存活线程;并发统计一致
O10 批量目录索引、聚合查询、数据库索引与轮询 待处理 避免每视频重复扫描目录;GET 不刷新状态更新时间;相关查询有界
O11 Whisper 解码耗时统计 待处理 消费 segments 生成器后计时,使用实际块时长计算实时倍率
O12 校正测试断言与文档漂移 待处理 成功验证包括产物可读/可下载;对齐测试可在正确结果下通过;文档与模型/断点实现一致

R01 修复记录

  • 根因:普通任务删除接口未区分 source=batch,直接递归删除 Path(input_uri).parent;自动清理器也使用输入路径推导删除目录。
  • 处理约定:普通删除接口拒绝批量 run(422),提示通过批量任务入口删除;上传任务只清理 <storage>/uploads/<run_id><storage>/runs/<run_id>。批量任务已有专用删除入口,保留源视频和视频旁成品。
  • 测试要求:使用 testdata/ 真实视频与字幕副本、临时数据库及私有存储;覆盖批量任务拒绝删除、正常上传清理、历史外部输入路径保护和自动清理路径保护。
  • 实现:普通删除接口 在删除前拒绝批量 run自动清理器 和普通接口均按私有目录布局定位清理范围。
  • 回归测试:test_run_deletion_safety.py,覆盖五种状态的批量 run、外部输入路径与旁挂字幕保护、其他任务目录保护。
  • TDD 红:uv run pytest tests/test_run_deletion_safety.py -q --tb=short7 failed;批量 run 被错误删除,两个外部路径用例复现媒体文件丢失。
  • TDD 绿及相关回归:uv run pytest tests/test_run_deletion_safety.py tests/test_apps_api.py tests/test_batch.py tests/test_maintenance.py -q73 passed7.73 秒;仅有既存 Starlette/httpx 弃用警告。
  • 状态:修复及验证完成,纳入 fix/review-improvements 分支;未部署。运行中的旧进程需加载新代码后才能获得保护。
  • 后续边界:普通列表仍会显示批量 run,但点击删除会收到批量入口提示;运行中删除的统一取消/状态协调属于 O08,未在本次展开。

R02 修复记录

  • 根因:report_failure() 用降低后的最大值直接调用扩缩容,导致当前 1 并发扩为 19;缩容哨兵追加在 FIFO 积压队列尾部,存量任务仍按旧并发执行。
  • 实现:adaptive_pool.py 改为标准 ThreadPoolExecutor 复用线程,map 按目标额度有界提交并串行收集结果。移除自建工作队列与退出哨兵,限流更新和提交共享锁。
  • 限流语义:只保持或降低当前额度;已发出的请求允许完成,后续提交遵守新额度;错误窗口不扩容,干净窗口逐步恢复上限。有效上限跨重试 map 保留,每批重新统计窗口与真实单任务耗时。
  • 兼容行为:map 按输入顺序返回结果,worker 异常仍作为结果返回;cancel 仍只抑制进度回调,OCR 自行检测暂停。线程执行器在 map 结束时回收。
  • TDD 红:3 个新增复现测试全部失败,分别观测到限流后目标 19、缩容后后续实际并发 4、错误窗口仍增加额度。
  • TDD 绿及调用方回归:uv run pytest tests/test_adaptive_pool.py tests/test_llm_filter.py tests/test_ocr_flow.py tests/test_subtitle_ocr_order_threading.py -q --tb=short85 passed51.60 秒;包含真实 14236 帧顺序数据、OCR 暂停、过滤限流重试。
  • 补充重试额度用例后:uv run pytest tests/test_adaptive_pool.py -q22 passed0.27 秒。连续限流后的第二轮 map 保持 1 并发,进度序号重新从 1 开始。git diff --check 通过。
  • 状态:修复及验证完成,纳入 fix/review-improvements 分支;未部署。尚未对真实服务配额下的吞吐做性能结论;已发出请求的终止依赖节点自身超时。

R03 修复记录

  • 根因:最终产物原地改名后,节点输出 URI 未同步,恢复时旧路径覆盖有效最终记录;批量放置对缺失产物直接跳过,随后仍清理并标记完成。
  • 实现:scheduler.py 保留节点原文件,把命名成品复制至 run 的 finals 别名目录;时间戳固定取 run 创建时间,重复收尾路径稳定。缺少最终引用或文件时进入 FAILED。
  • 兼容:旧版本已经改名但最终别名记录仍有效时复用该路径,不再覆盖为失效节点 URI;原始与最终文件均丢失时明确报错。
  • 文件操作:storage.py 提供同目录临时文件复制和原子替换,失败清理临时文件、保留源及原目标。batch.py 先预检全部必需成品,复制成功后才清理 run 和工作空间;中途失败保留断点供重试。
  • TDD 红:新增/强化的 8 个场景失败,覆盖暂停恢复链接、旧改名记录、多别名同源、缺少输出引用/文件、批量缺产物清理、节点原始 URI 保留及复制故障。
  • 相关回归:uv run pytest tests/test_finalization.py tests/test_scheduler.py tests/test_batch.py tests/test_apps_api.py tests/test_db.py -q --tb=short97 passed3.22 秒。
  • 补充批量复制故障及安全回归:uv run pytest tests/test_finalization.py tests/test_maintenance.py tests/test_run_deletion_safety.py -q --tb=short22 passed,5.83 秒。真实视频/字幕验证写满故障后旧成品和工作空间完整,故障解除可成功放置并清理;API 下载验证原始文件与两个最终别名均可读取。仅有既存 Starlette/httpx 弃用警告。
  • 状态:修复及验证完成,纳入 fix/review-improvements 分支;未部署。原子性为单文件级,多文件中途失败允许部分完整成品已经更新,重试会重新放置;不承诺断电持久性。
  • 剩余边界:R08 按用户决定调整为不区分工作流版本,固定版本方案取消;版本机制调整及任务原子创建另行实施。此修复不会自动重建已经丢失的历史成品。

R05 / R06 修复记录

  • 顺序:按用户要求先完成 R05,再完成 R06;R03 已提交为 3a61291
  • R05:新增 nodes/srt.py 按 cue 解析 BOM/CRLF、多行及空正文,坏字幕明确报错;翻译以全局位置 ID 的 JSON 条目请求,校验 ID 集合、类型、唯一性及正文。乱序按 ID 回填,结构错误最多尝试 3 次,耗尽 failed,取消末尾合并/补空策略。空 cue 保留时间轴且不请求模型,原有幻觉清洗继续执行。
  • R05 TDD:12 个新回归用例先失败;相关节点/清洗/专名/翻译测试 93 passed、1 skipped、18 deselected(排除 Whisper)。最后调整提示词统一“条目”措辞后翻译对齐测试 13 passed(含真实短句 LLM 校准),0.76 秒。
  • R06:空帧终止当前字幕段;失败/异常不写成功存档,失败帧在收紧的并发下重试一次,仍失败则节点 failed,已成功帧断点保留。新存档 status=completed 表示成功(含无文字),status=skipped 表示超长输出按既有规则跳过。
  • 旧存档兼容:非空结果继续复用,无状态旧空串因无法区分超时与无文字而重新 OCR;不自动重跑已完成的历史任务。
  • R06 TDD:4 个新回归先失败,覆盖跨空帧合并、failed 响应、抛异常和旧空串恢复。全量数据修正后 1942 条,旧 1666 条文件未修改;测试比较真实单线程、4/16 线程与断点结果,并逐采样点检查字幕不跨空白。基线必须走完整节点路径(包含超长过滤),不以原始 OCR 文本冒充成功存档。
  • 最终组合验证:uv run pytest tests/test_ocr_recovery.py tests/test_ocr_flow.py tests/test_subtitle_ocr_order_threading.py tests/test_integration_subtitle_ocr.py tests/test_translation_line_alignment.py tests/test_hallucination_mask.py tests/test_proper_nouns.py -q --tb=short --show-capture=no71 passed、1 skipped58.69 秒;跳过项缺少历史专名素材,真实 LLM 与真实 OCR 集成通过。git diff --check 通过。
  • 状态:R05/R06 工作区已修复,尚未提交、未部署。模型语义是否正确仍需内容质量评估,ID 校验保证程序不会因列表乱序或漏项贴错时间。
  • R08 决策:用户计划不区分工作流版本,取消固定版本修复方案;版本机制调整、执行/收尾一致性及批量原子创建保留待办,本轮未实施数据库迁移。

R04 修复记录

  • 根因:①保存路径只做结构校验(WorkflowDefinition.validate():名称/版本/节点 ID 唯一/边引用存在),环形依赖结构合法因而被写库并发布;②execute_run 的 DAG 解析、校验与拓扑排序在 try之外,环检测抛出的异常直接冒到 _loop 被吞掉,任务状态从未离开 QUEUED——next_queued_run 每轮拾起同一条队首记录,后续任务永久堵塞。
  • 修复 1(保存/发布):routers/workflows.py_validate_definition 在校验后调用 topological_sort,环形 DAG(含自环)以 "workflow contains a cycle" 转 422;创建/校验/发布三个入口共用该函数,publish 额外重新校验最新版本定义,历史遗留的环形版本无法进入应用中心。校验先于任何写库,被拒请求不产生工作流或版本记录。
  • 修复 2(历史无效任务):scheduler.pyfrom_dict / validate / topological_sort 移入 try,任何预检异常都立刻把 run 置 FAILED 并记录错误后返回,队首随即前移,不再堵塞后续任务。
  • 方案边界:环检测放在入口校验(保存/发布)而非 WorkflowDefinition.validate(),因此 WorkflowDefinition.validate() 保持只做结构校验、SDK 协议模型不变;批量任务在工作流级校验仍放行环形定义,由调度器把每个视频的 run 判 FAILED(保留既有"单视频失败不中断整批"语义,test_batch_worker_cycle_fails_video_not_job 未改动仍通过)。批量的 run 现在由调度器直接置 FAILED 并回填错误,不再依赖异常冒泡。
  • TDD 红:新增 5 个回归用例先失败——创建带环工作流返回 200、校验接口返回 200、发布历史环形版本返回 200、环形任务执行后仍停在 QUEUED(队首堵塞)、缺 name 的非法定义同样卡住队列。
  • TDD 绿及相关回归:uv run pytest tests/test_workflow_api.py tests/test_scheduler.py -q29 passed1.07 秒;uv run pytest tests/test_batch.py tests/test_apps_api.py tests/test_seed.py tests/test_models.py tests/test_registry.py tests/test_api.py tests/test_finalization.py -q95 passed2.59 秒。
  • 全量回归:uv run pytest -q402 passed、5 skipped84.03 秒;仅既存 Starlette/httpx 弃用警告。git diff --check 通过。
  • 状态:修复及验证完成,纳入 fix/review-improvements 分支工作区(与 R05/R06 未提交改动共存);未部署。历史遗留的环形已发布工作流不会被自动取消发布,仍可创建任务,但任务会立即 FAILED 且不堵塞队列;如需清理线上遗留数据需另行确认后执行。

审查基线

  • 修复前全套测试:uv run pytest369 passed、6 skipped76.75 秒。
  • 隔离复现已确认:源视频目录误删、限流后 1 → 19 并发、队列积压时缩容滞后、暂停恢复后成品 URI 失效、环形 DAG 阻塞队首、多行 SRT 损坏、OCR 跨空白合并、重用抽帧目录留下旧尾帧。
  • 本文件中的“已修复”只表示当前工作区实现及验证完成;部署状态需另行记录。