edit | blame | history | raw

B 站博主动态采集辅助工具 HOLD/5 最小修复设计 V002

1. 修订身份与适用范围

  • 事项:DEV-PROJECT-INFO-BILI-DYNAMIC-COLLECTOR-MVP-20260804-001
  • 需求:REQ-BILI-DYNAMIC-COLLECTOR-20260804-001
  • 基线:CODE-DESIGN-PROJECT-INFO-BILI-DYNAMIC-COLLECTOR-MVP-HOLD5-REPAIR-V001.md
  • 基线字节数:11917
  • 基线 SHA-256:16C14FB2751A0EAB63F76371E75D0569FF8EF5B47FDD8724BE861314B6062733
  • 前序结论:HOLD/1,唯一未闭环项为 F1_DESIGN_RERUN_PREFLIGHT_ORDER_CONFLICT
  • 本修订性质:仅补充 V001 第 4.2、5、8 节之间的执行顺序;V001 已通过的重型分类、精确选择器、manifest 秘密字段检查、规范原生 handoff 及所有范围边界继续冻结。

本修订 PASS 前,代码、示例配置、测试和 fixture 继续保持冻结;不运行网络、浏览器、下载,不接触 F:\video 或正式 ana-data

2. 冻结的 move-completed 两阶段预检顺序

move-completed 对整个 mapping 批次采用下列固定顺序。任何阶段失败都在复制、目标创建、源删除和 manifest 追加之前结束。

2.1 阶段 A:选择器解析、实体唯一性与终态投影

  1. 读取并验证完整 mapping 结构和秘密字段。
  2. 对每一行解析所有已提供的 dynamic_idopus_idbvidsource_url;每个选择器都必须存在、唯一命中,且同一行的全部选择器必须命中同一实体。source_url 继续执行 V001 的 registered-host 规范化。
  3. 在全批次检查 entity 唯一性;同一实体出现两次即 E_ENTITY_DUPLICATE。该检查不依赖 source_file 是否仍存在。
  4. 读取该实体最新有效 manifest 状态,并将该行分类为:
  • TERMINAL_MOVED:最新状态是 VIDEO_MOVEDCOMPLETE
  • TERMINAL_RETAINED:最新状态是 VIDEO_MOVED_SOURCE_RETAINED
  • ACTIVE_MOVE:最新状态是 TODO_QUEUEDMOVE_FAILED,或没有移动终态。
  1. 终态投影直接使用 manifest 中已经持久化的可信字段,不重新要求源文件存在:
  • TERMINAL_MOVED 返回 ALREADY_MOVED、exit 0,并复用已记录的 local_filesha256
  • TERMINAL_RETAINED 返回 VIDEO_MOVED_SOURCE_RETAINED、exit 4,并复用已记录的 local_filesha256failure_reason;即使保留源后来被人工删除,告警也保持粘性;
  • 两类终态均不 stat/resolve source_file,不参与物理源重复检查,不创建、删除或改写文件,不追加 manifest 事件。

2.2 阶段 B:仅对 ACTIVE_MOVE 做源与目标预检

只有 ACTIVE_MOVE 行进入以下预检:

  1. source_file 必须存在且为允许下载根目录中的普通文件;逐级拒绝链接、junction/reparse,检查稳定年龄与扩展名。
  2. 形成物理 source identity:优先 (st_dev, st_ino);inode 为 0 时使用 normcase(resolve(strict=True))
  3. 对全部 ACTIVE_MOVE 行检查 source identity 唯一性;重复即 E_SOURCE_DUPLICATE
  4. 计算目标路径并检查全批目标唯一、既有目标不覆盖以及根目录安全。
  5. 阶段 A 或阶段 B 任一错误均使本次调用正式目标新增数为 0、manifest bytes 不变、所有源文件不变。预检错误不追加 MOVE_FAILED;只有完整两阶段预检通过后发生的真实运行时事务失败才可按 V001 记录失败事件。

终态行可以与活动行共存于同一批次。终态行仍参与 entity 唯一性检查,但不参与 source identity/目标写入集合;活动行全部通过阶段 B 后才允许逐项进入 V001 已冻结的 copy/fsync/hash/atomic link/manifest/delete 事务。

3. 精确终态矩阵

manifest 最新状态 当前源文件 分类 输出状态 exit manifest 变化
VIDEO_MOVED / COMPLETE 不存在或存在 TERMINAL_MOVED ALREADY_MOVED 0
VIDEO_MOVED_SOURCE_RETAINED 存在 TERMINAL_RETAINED VIDEO_MOVED_SOURCE_RETAINED 4
VIDEO_MOVED_SOURCE_RETAINED 后来被人工删除 TERMINAL_RETAINED VIDEO_MOVED_SOURCE_RETAINED 4
TODO_QUEUED / MOVE_FAILED / 无终态 存在且通过预检 ACTIVE_MOVE 按事务结果 0/4/3 仅运行时事务可追加
TODO_QUEUED / MOVE_FAILED / 无终态 不存在或不安全 ACTIVE_MOVE 输入/安全错误 2/3

批次汇总规则保持不变:只要投影或新事务结果中包含一个 retained-source,整体为 COMPLETE_WITH_RETAINED_SOURCE、exit 4;否则按既有成功/失败规则汇总。

4. 新增非真空入口测试合同

在 V001 第 8 节基础上必须新增以下实际 CLI 入口回归,全部使用 TemporaryDirectory、小型非媒体字节文件和秘密无关的净化 JSON:

  1. 正常成功后源已删除重跑:首次移动成功并确认源不存在;保存目标/hash/manifest bytes;相同 mapping 重跑,断言 exit 0、item=ALREADY_MOVED,目标/hash/manifest bytes 完全不变,目录无新增临时文件。
  2. retained 源仍存在重跑:注入源删除失败得到 exit 4;相同 mapping 重跑,断言 exit 4、item=VIDEO_MOVED_SOURCE_RETAINED,复用原 local_file/sha256/failure_reason,源、目标和 manifest bytes 不变。
  3. retained 源被人工删除后重跑:在第 2 项之后于临时目录人工删除保留源;相同 mapping 重跑,断言仍 exit 4 且复用原可信字段,目标/hash/manifest bytes 不变,无新事件。
  4. 活动同源/同实体混合批次:保持 V001 的 selector 不一致、同一物理源映射两实体、同实体两行反例;断言全批次零业务副作用。终态行不掩盖活动行的选择器错误,也不进入物理同源检查。

测试必须从 CLI/main() 入口进入,不得只调用内部分类函数。三种重跑均须比较调用前后 manifest 原始 bytes,而非只比较事件数量。

5. 实施与复审门禁

V001 与 V002 组合为唯一实施合同。V002 限定设计 PASS 后,开发员才可一次性实现五项 HOLD 修复,并运行目标测试与 project 回归;全程不得联网、打开浏览器、触发下载、写 F:\video 或正式 ana-data。实现完成后只向原 dev.reviewer.project 提交一次限定实现复审。