Files
UHD_Media_Tool/docs/plan/11-requirements-coverage.md
T
2026-09-28 21:52:25 +08:00

312 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 需求覆盖矩阵与后续计划
2026-09-28。对照 REQ v0.7(`../../media_automation_requirements_architecture_v0.7.md`)逐条核对 main HEAD `57346d4` 的实现。证据来自代码 grep、测试文件与已有验收文档(`04`、`07`、`08`、`10-v0.2.1-check.md`),没有跑新的测试。
标记:
- **已做**:代码与自动化测试都在,mock 环境下行为符合 REQ。
- **部分**:只做了其中一段,缺口写在最后一列。
- **未做**:没有对应实现。
- **待真实环境验证**:代码完成,只在 mock(RSS / 站点 / TMDB / qB / Emby / camofox / fake 模型)下验证过,没有连过用户的真实服务。
所有"已做"都隐含一个前提:**没有连过真实 PT 账号、qB、Emby、camofox 和真实模型上游**。下文"待真实环境验证"只标那些核心价值就在真实交互上的条目。
进行中(不在 main,不计入本文统计):`c2a` 分支(工作区 `/opt/uhd_media_tool-c2a`)在做跨进程限流与缓存(PG 令牌桶、`UNLOGGED` 缓存表、TMDB 响应缓存、图片代理,见 `00` §9 最后两条);检查子代理的 `10-v0.2.1-check.md` 尚未提交。
## 1. R01–R32 覆盖矩阵
统计:已做 18,部分 11,未做 0,待真实环境验证 3(R26、R30、R32)。"部分"里 R06、R24、R31 同时也需要真实环境验证。
| 编号 | 需求 | 状态 | 证据 | 缺口 |
| --- | --- | --- | --- | --- |
| R01 | 多个 RSS 并存 | 已做 | `feed_source` / `observation`;`ingest.test`「三个 Feed 看到同一资源只建一条 source_release」「窗口零重叠 → feed.gap_suspected」;`docs/runbook/sites.md` | 没有并发 ingest 的测试(现有用例是顺序抓取) |
| R02 | 综艺正片齐全,附加内容可选 | 部分 | `release-parser` 输出 `contentType`(main / extra / performance_only…)与 `segment`(upper / lower / full);`content_unit.content_type` 列;订阅覆盖矩阵显示分段 | 没有"上 + 下 = 一期正片"的覆盖计算,没有节目级"附加内容全部收录"配置,完整性不按正片覆盖判定 |
| R03 | TMDB 滞后不阻断 | 已做 | 临时季 / 集单元(`resolve.test`「剧集:建 series 作品与临时季/集单元」);总集数账本 0025;`e7-tv-series`「总集数未知,Slot 不判满足」 | 一对多 / 多对一编号关系(`unit_relation`)没有建表 |
| R04 | 按规则收录双版本 | 部分 | 每作品多 Slot、Slot × 单元预留(`e9-continuous-series`);订阅"自动补全其他版本";`require_distinct_asset` 列与表单开关 | `checkDistinctAssets`(`domain/slot/completion.ts`)没有接进服务端,同一文件仍可同时满足两个 Slot |
| R05 | 根据 PT 每日新增自动收录 | 已做 | 策略 `newTitle` 规则与 `new_title` 模式(`rules-api.test`「new_title:not_new_release」);新作品 / 追更 / 升级三种模式(`domain/acquisition/mode.ts`) | 没有"每日汇总"视图 |
| R06 | 部分 PT 需要浏览器 | 部分 | camofox BrowserProvider(`packages/adapters/src/browser`)、会话 / 租约、凭证服务端注入、验证码转待处理(`browser-api.test`、`browser-e2e.test`);`docs/runbook/browser.md` | 站点适配器 HTTP 失败后不会自动切到浏览器(REQ §4.4);只对 mock camofox 验证过 |
| R07 | 保持最终路径结构 | 已做 | `path_binding_active_key`;`organize-move.test`「路径绑定固定:译名变化后新集仍进旧目录」;命名模板对已有绑定只用于新目录(`docs/design/naming-template.md` 样例 24) | — |
| R08 | 不绑定 TMDB 身份 | 已做 | 本地 UUID;`external_identity` (provider, entity_type, external_id) 部分唯一;合并保留 `merged_into_id` 跳转(`resolve.test`「合并重复作品」) | — |
| R09 | 数据库存映射并定期校验 | 部分 | 资产对账 `reconcileLibrary`(哨兵 + 增量 stat,suspected → confirmed);元数据 6 小时刷新;`vertical.test`「资产对账」 | 没有 Identity Reconciler(外部对象存在性 / 类型核对)和 Server Reconciler(本地资产 ↔ Emby);备份恢复只有人工演练 |
| R10 | 必要时 Agent 辅助刮削 | 部分 | `identity.resolve`、`catalog.lookup` 能力;待识别事项自动调查(`e5-auto-investigate`);字段锁 | 没有字段级 `metadata.apply` 能力;NFO / 图片写入返回 `not_implemented`(`file-manager/probe.ts`) |
| R11 | 以 MP / MovieClaw 实现为基线迁移 | 已做 | `docs/porting/`(识别、刮削、转移、订阅、站点框架、Rust 逻辑差分、许可账本 `license-and-provenance.md`);`scripts/mp-sync` 差分脚本 | MP 多文件 / 整季包 / 目标冲突的运行对照(REQ §14.1.1)只到源码层 |
| R12 | Pi Agent 作为推理内核 | 已做 | `@earendil-works/[email protected]`,`AgentRuntimePort`,显式白名单(`agent/test/runtime.test`);ADR-003 | — |
| R13 | 公开 API / MCP | 已做 | 195 个端点定义(`packages/contracts/src/api.ts`)+ OpenAPI;Streamable HTTP MCP(`modules/mcp`,`test/mcp/mcp.test`);27 个能力 | — |
| R14 | qB 标签管理 | 已做 | 提交打管理标签、已有种子接管只补标签(`vertical.test`「already_exists」);`e8-tag-removal` 去标签 / 任务消失 | — |
| R15 | Copy / Move 与缓存清理 | 已做 | `verifyAndImport`、跨卷 Copy→核验→删源、EXDEV 不降级、fsproxy 看门狗;`vertical.test`「缓存清理」「H&R 未满足时 Move 变冲突」 | 硬链接工作流、蓝光原盘整目录未做(REQ 本身不把硬链接作主流程) |
| R16 | 条件选片与 Agent 偏好选片 | 部分 | 确定性 `evaluateAcquisition`、规则组分级优先级与逐级 trace | Agent 主观选片(偏好判断、独立预算、选片理由)没有实现;Agent 只能在会话里按用户委托提交 |
| R17 | 自动执行为主、按操作授权 | 已做 | 策略发布即生成持续授权;服务端授权器(`authorize.ts`);`approvals.test`;e1 / e7 无逐次确认 | — |
| R18 | 旧库分范围接管 | 部分 | 库根 `management_mode`(register_only / managed);资产对账;文件管理可逐项识别整理 | 没有首次全库扫描登记、没有"启用前预览影响"、没有作品级覆盖;`scanIncremental` 出错仍返回 complete |
| R19 | 控制台与 Agent 双入口 | 已做 | 同一能力注册表服务 Web / Agent / MCP;Agent 抽屉带页面上下文;凭证与原站接管走专用 UI | — |
| R20 | 偏好标签编辑与学习 | 部分 | 偏好标签作为规则展示形态,抑制记录(`rules-api.test`、`rule-groups.test`「Agent 不能加回(409)」);修订历史 | "重复反馈调整软排序"的学习没有;标签不参与订阅评估(`CHANGELOG` 0.1.0 已知限制 3) |
| R21 | 下载缓存硬阈值 | 已做 | 按 `cache_volume_key` 汇总多 qB 同卷(`services/volumes.ts`);`vertical.test`「硬阈值……低于恢复水位只恢复阈值暂停项」 | 未纳管任务的占用与不暂停没有测试(AT42) |
| R22 | 跨季综合召回 | 部分 | TMDB + `title_alias` pg_trgm 召回;待识别池可按原始标题检索;`identity_unresolved` 有界复查 | 同名重启、简称变化、特别篇与下一季的区分没有专项逻辑和样本;没有召回率 / 误关联报告 |
| R23 | 整理记录公开接口 | 已做 | `/organization-records`、`/organization-records/changes`(游标,含状态更新);scope `organize.read` / `organize.execute`;`vertical.test`「整理记录 API」 | — |
| R24 | Emby 兼容辅助查询 | 部分 | 多实例并行查询,失败为 unknown(`emby.test`、`inventory/media-servers.test`) | 库存结果不参与收录决策("已有则满足目标");没有 server_mapping 对账;没连过真实 Emby / Jellyfin |
| R25 | 站点缓存优先 | 已做 | 站点独立启停、快照、实时补查并发合并(`sources-identity/api.test`);全局搜索短缓存 | 限流器是进程内的,跨进程令牌桶在 c2a 进行中 |
| R26 | Pi 原生能力配置 | 待真实环境验证 | 上游 / 模型 / 思考档位 / 上下文预算 / 压缩 / 子会话开关;41 个 provider + 8 种订阅登录 | 只有 fake 与 OpenAI 兼容本地端点有自动化覆盖 |
| R27 | 禁止默认自动换源 | 已做 | 无进展只记证据 + 待处理(`downloads.ts`);恢复白名单不含换源(`e6-auto-recover`「换源被拒」) | 用户委托换源没有"替换计划"把新提交与原任务处置绑在一起 |
| R28 | 单管理员、多服务实例 | 已做 | 管理员登录 + TOTP / Passkey;API Key 四档 scope,可撤销;多 qB / 多 Emby / 路径映射 | — |
| R29 | 交互执行模式 | 已做 | 会话默认执行,`agent.plan` 步骤清单、`agent.propose_options`、内联审批、"先给方案"(`e12-interaction`) | — |
| R30 | PT 站点工作台 | 待真实环境验证 | 站点页整理视图:列表 / 搜索 / 详情 / 库存叠加 / 统一下载入口;全局搜索 | 四个主力站没有连过真实账号;观众站定义无 H&R 选择器 |
| R31 | 同会话原站接管 | 部分 | 原站视图:截图轮询 + 坐标点击 / 输入 + 接管租约,交还后强制重读页面(`browser-api.test`) | 画面是 1.5 秒截图轮询,不是实时流;同一标签页人 / Agent 连续操作没在真实 camofox 上核验(`browser.md` §6 清单全空) |
| R32 | 可配置浏览器后端 | 待真实环境验证 | `BrowserProvider` 合同 + camofox 实现;按站点 / 账号隔离 profile | 用户 camofox 的 fork / 版本 / 地址未提供;只实现 camofox 一种 |
## 2. §2.1 五原则
| 原则 | 保障点 | 已知违背或风险 |
| --- | --- | --- |
| 身份≠名字,路径≠外部 ID | `external_identity_accepted_key`(`0005_identity.ts`);本地 UUID 主键;合并留 `merged_into_id`;`resolve.test`「人工纠错映射:旧映射退役留修订」 | domain 匹配仍要求本地候选带 externalId(W1 建议项,未修) |
| 已建立的路径绑定不随元数据重算 | `path_binding_active_key`;命名模板只在首次建绑定时生成目录;`organize-move.test`「路径绑定固定」;文件管理显式 move 才修订绑定(`file-manager/write.test`) | 无 |
| 模型不是业务事实唯一来源 | 服务端授权器忽略模型声称的"已同意"(`e2`「没有授权:download.submit 被拒」);汇报取自整理记录,模型文本标"未经核查";审批只接受管理员会话 | 能力统计把挂起重放算成失败(`10-v0.2.1-check` #4),只影响统计 |
| 失败≠不存在 | 对账库根离线只标 unavailable;TMDB 失败记 `lookup_failed`;Emby 失败为 unknown;文件管理根离线返回 503 不返回空列表(`browse.test`) | `scanIncremental` 出错仍返回 complete(旧库接管会用到,目前服务端未调用) |
| 清理按明确授权 | `assertSafeToDeleteData`(已入库、无失败文件、无引用、保留期与 H&R);只读对账 / 总开关关闭时拒绝自动 execute;回收站代替直接删除,永久删除默认关闭 | 部分文件入库后不整种清理(AT29)只有代码保障,没有测试 |
## 3. §15 分期对照
**结论:当前版本相当于"M0 大部分 + M1 全部(仅 mock 环境)+ M2 约三分之一"。** 不是 M2 首版候选:REQ §15.3 明确 M2 才构成覆盖全部核心痛点的首版,而综艺分段覆盖、双版本组合校验、旧库接管、Agent 选片与规则学习都还没做,四站与浏览器也没连过真实环境。
### M0
| 项 | 状态 | 证据 / 缺口 |
| --- | --- | --- |
| 固定 Deno / Pi / PG / OpenWorkflow 版本与骨架 | 已做 | Deno 2.9.7、pi 0.87.1、openworkflow 0.10.1、PG 16;ADR-002 / 003 / 004 |
| Deno 下 Pi / PG / MCP / OpenWorkflow 实际兼容 | 已做 | `docs/spikes/`,MCP 用官方 SDK 实连(`mcp.test`) |
| Pi 白名单、无隐式扩展 | 已做 | `runtime.test`「未注册工具(bash)被拒」 |
| 执行器崩溃恢复 | 已做 | `tasks/test/crash-recovery`、e4 |
| 流程版本升级 | 部分 | 只在 spike 验证,产品代码没有测试 |
| 提前审批不丢失 | 已做 | `engine.test`「waitForFact 事实先于等待到达不丢失」、`approvals.test` |
| 多 Feed 并发不重复提交 | 部分 | 顺序 ingest 去重 + outbox 并发投递有测试;并发 ingest 没有 |
| 改名与映射修订后路径不变 | 已做 | `organize-move.test`、`resolve.test` |
| MP 多文件 / 整季包 / 目标冲突源码对照 | 部分 | `docs/porting/moviepilot-transfer.md`,只到源码层 |
| 浏览器连用户现有 camofox,验证同会话交接 | 未做(待用户提供) | 只对 mock 验证;linuxserver/chrome / Selkies 适用性未记录 |
| 脱敏真实样本 | 部分 | MP 差分样本(识别 / 规则 / 命名);没有四站真实 RSS 与综艺样本 |
| 自动执行关闭、影子决策 | 已做 | 自动化总开关;`resolve.test`「自动化关闭:证据足够也只提议」 |
### M1
| 项 | 状态 | 证据 / 缺口 |
| --- | --- | --- |
| 观众 + 馒头、多 RSS | 已做(mock) | `api.test`、`mteam-tasks.test`、`ingest.test` |
| qB 标签接管、Copy / Move | 已做 | `vertical.test`、`organize-move.test`、e8 |
| 一个电影目标 + 一部常规剧集 | 已做 | e1 / e2(电影)、e7 / e9(剧集) |
| 整理记录 API、可选 Emby 查询 | 已做 | 见 R23 / R24 |
| 备份、审计、恢复、停用自动化开关 | 部分 | 备份脚本与 `umt backup`;恢复只有人工演练;定时任务里的"备份"是占位 |
| 工作台列表 / 详情 / 库存标注 / 统一下载入口 | 已做(mock) | 站点页、全局搜索、`/search/releases/{siteId}/{rid}/plan` |
| Agent 自然语言目标 → 查库存 / 搜索 / 选片 / 提交 → 持续流程入库 → 真实汇报 | 已做(fake 模型) | e2「有持续授权:……汇报来自整理记录」 |
| 授权内异常调查与恢复 | 已做 | e6「task.inspect → download.recheck → 系统核实已恢复」 |
| 关闭聊天后台继续 | 已做 | e3 |
### M2
| 项 | 状态 |
| --- | --- |
| 综艺内容分类与分段覆盖 | 部分(只到标题解析) |
| 本地临时集账本 | 已做 |
| 独立双版本 | 部分(`require_distinct_asset` 未生效) |
| 新作品 / 追更 / 升级三种规则 | 已做 |
| 浏览器 Adapter、工作台双视图、同会话接管 | 部分(mock;截图轮询) |
| 映射巡检与辅助刮削 | 部分(资产对账、元数据刷新;无身份巡检、无 NFO) |
| 旧库分范围接管 | 未做(只有库根两种模式) |
| 授权规则优化、条件 / Agent 选片 | 部分(只有条件选片;策略预览 = 对最近 200 条已识别资源试算) |
| 缓存硬阈值与清理 | 已做 |
| 偏好标签 | 已做(学习未做) |
| 站点快照缓存 | 已做 |
| 跨季召回与待识别治理 | 部分 |
| 双入口待处理 | 已做(顶栏收件箱 + 首页 + 页面内联) |
| HHClub / CHD 适配 | 待真实环境验证(定义来自 MovieClaw v0.27.0 MIT,有解析单测) |
| 媒体级主动整理 | 已做(文件管理 v2、整理向导、命名模板) |
| 影子模式比较人工选择 | 未做 |
### M3
| 项 | 状态 |
| --- | --- |
| 更多 PT | 部分:23 个站点定义 + MP 专用 spider / 用户信息解析器已移植,均未真实核验 |
| Transmission / Plex | 未做 |
| 历史样本回放、规则迁移 | 未做 |
| Skill 管理 | 未做 |
| CLI | 部分:`umt backup` / `--role export-mappings` 等运维入口,没有业务 CLI |
| MCP 扩展 | 已做(提前到 v0.2.1) |
| 页面提取修复提案 | 未做 |
## 4. §16 AT01–AT80
分类:**测试** = 有自动化测试覆盖通过标准;**部分** = 有测试但只覆盖一段;**手工** = 只能手工验证;**未覆盖** = 没有测试也没有对应实现或手工流程。标 (mock) 的只在 mock 服务上跑过。
统计:测试 44(55%),部分 26(32.5%),手工 2(2.5%),未覆盖 8(10%)。有自动化测试的(测试 + 部分)合计 70 / 80 = 87.5%;完整覆盖率按 55% 计。
| AT | 状态 | 测试 / 说明 |
| --- | --- | --- |
| 01 | 测试 | `ingest.test`「三个 Feed 看到同一资源只建一条 source_release」 |
| 02 | 部分 | e10「按作品选 Slot」;没有两站不同版本分进各自 Slot 的用例 |
| 03 | 测试 | `ingest.test`「窗口零重叠 → feed.gap_suspected,并路由到有预算的补漏快照」 |
| 04 | 部分 | `release-parser.test` 把加更识别为 extra;分段覆盖未实现 |
| 05 | 部分 | `release-parser.test` 会员版样本;节目级规则未实现 |
| 06 | 测试 | `resolve.test`「剧集:建 series 作品与临时季/集单元」、e7 |
| 07 | 测试 | `organize-move.test`「路径绑定固定:译名变化后新集仍进旧目录」 |
| 08 | 测试 | `resolve.test`「人工纠错映射」 |
| 09 | 部分 | e9 多版本延后;没有"两个 Slot 同时缺失分别执行"的专项 |
| 10 | 测试 | `rules-api.test`「new_title:not_new_release」 |
| 11 | 测试 (mock) | `browser-api.test`「租约到期 → 等待处理 + 待处理事项」、`browser-e2e.test` 验证码转接管 |
| 12 | 测试 | e4「download.submit 途中 kill worker → 不重复提交」 |
| 13 | 测试 | `organize-move.test` 跨卷 kill 后 resumed |
| 14 | 测试 | `vertical.test`「资产对账:库根离线只标 unavailable」 |
| 15 | 测试 | `tasks/engine.test` waitForFact 先到;`approvals.test` |
| 16 | 测试 | `approvals.test` 改计划 → 被拒 → 重批 → 只消费一次;`rules-api` 旧授权吊销 |
| 17 | 部分 | `runtime.test` 预算超限;e6 预算超限;没有"模型断网时确定性链继续"的用例 |
| 18 | 未覆盖 | 只有系统提示词约束,没有恶意标题 e2e |
| 19 | 部分 | `vertical.test` 删数据安全检查;硬链接工作流未做 |
| 20 | 手工 | `docs/runbook/backup-restore.md` 演练记录 |
| 21 | 测试 | `resolve.test`「用户锁定字段不被覆盖」(海报锁随 NFO 未做) |
| 22 | 测试 | `emby.test`、`inventory/media-servers.test`「异常实例 unknown」 |
| 23 | 测试 | `vertical.test`「already_exists:……只补管理标签」 |
| 24 | 测试 | e8 去标签 / 任务消失 |
| 25 | 测试 | `vertical.test`「缓存清理」、e8「缓存清理」 |
| 26 | 部分 | `space_insufficient` 事项有代码;没有"全部仍需保留"的专项用例 |
| 27 | 测试 | `organize-move.test` 跨卷 Move resumed |
| 28 | 测试 | `vertical.test`「H&R 未满足时 Move 变冲突」、`organize-guard.test` |
| 29 | 未覆盖 | 代码有文件级结果检查,无测试 |
| 30 | 部分 | 条件选片有测试;Agent 偏好选片未实现 |
| 31 | 部分 | 人工纠错有测试;Agent 规则优化未实现 |
| 32 | 测试 | e1 / e7 发布策略 → 持续授权 → 自动执行 |
| 33 | 未覆盖 | 旧库接管未实现 |
| 34 | 部分 | e7 / e9 持续追更;追新季开关没有测试 |
| 35 | 部分 | `browser-e2e.test` 凭证注入登录 (mock);HTTP → 浏览器自动切换未实现 |
| 36 | 测试 | `rules-api.test` revision 乐观锁 |
| 37 | 测试 | `file-manager/write.test`、`organize-move.test` |
| 38 | 部分 | `domain/slot.test`、`rules-slot.test` 升级档位;没有服务端 4K WEB-DL → 蓝光压制用例 |
| 39 | 部分 | e10「重复评估只留一条候选」;Agent 选片未实现 |
| 40 | 测试 | `rules-api.test`、`rule-groups.test` 抑制记录 |
| 41 | 测试 | `vertical.test`「硬阈值……只恢复阈值暂停项」 |
| 42 | 未覆盖 | 同卷汇总已实现(`volumes.ts`),未纳管任务没有测试 |
| 43 | 未覆盖 | 没有调查整个 qB 实例(含未纳管任务)的能力 |
| 44 | 部分 | `seasonScope` 已实现;来源默认值没有测试 |
| 45 | 部分 | `resolve.test` 本地召回、合并;同名重启 / 简称变化没有样本 |
| 46 | 测试 | `resolve.test`「no_match 进池并开未识别事项」 |
| 47 | 测试 | `ingest.test`「站点关闭后 Feed 不再抓取」、`browser-api.test`「站点停用」 |
| 48 | 测试 | `vertical.test`「changes 游标增量(含既有记录状态更新)」、`w5a2.test` partial |
| 49 | 部分 | Emby unknown 有测试;来源版本未知的专项没有 |
| 50 | 部分 | `download-state.test`「无进展判定」;服务端 e2e 没有 |
| 51 | 部分 | e11 开关关闭时拒绝派生;思考档位能力表达只有 `upstreams.test` |
| 52 | 测试 | e11 预算共享、父中止级联取消 |
| 53 | 测试 | e12「先看方案时执行被拒」 |
| 54 | 部分 | e7 整季包只覆盖实际文件;MP 对照样本没有 |
| 55 | 部分 | `op-ledger`「租约丢失旧 attempt 提交被拒」;流程升级没有 |
| 56 | 部分 | `auth.test` 撤销后 401;恢复与路径改变没有自动化 |
| 57 | 部分 | 站点 mock 列表 / 详情;四站真实页面没有 |
| 58 | 部分 | `vertical.test`「首页、媒体库、库存叠加 API」;Emby 叠加没有 |
| 59 | 测试 | `sources-identity/api.test` 实时补查并发合并、关闭站点 |
| 60 | 部分 | e10 去重、浏览器下载转 `/acquisition-plans`;并发触发没有 |
| 61 | 测试 (mock) | `browser-api.test`「输入类动作要先接管;他人接管中 409」 |
| 62 | 测试 (mock) | `browser-api.test`「交还后需重新读取页面」 |
| 63 | 测试 (mock) | `browser-api.test`「服务重启……标签页标 lost」「站点停用」 |
| 64 | 测试 | `browser-api.test` 快照遮蔽密码与 passkey;`redact-consistency.test` |
| 65 | 测试 (mock) | `browser-api.test` 下载暂存、sha256 / infohash 核验 |
| 66 | 未覆盖 | 不适用:没有接独立 Chrome |
| 67 | 测试 | e2 |
| 68 | 测试 | e5 自动调查、e6 授权内恢复 |
| 69 | 测试 | e3、e4 |
| 70 | 测试 | e2「已提交≠已入库」 |
| 71 | 测试 | e5「重复事件只一个 run」、e6 尝试上限 |
| 72 | 测试 | `mcp.test`「execute Key……有授权后执行并记账本」 |
| 73 | 未覆盖 | 多下载器相同 hash 没有测试 |
| 74 | 未覆盖 | 待处理按 `dedupe_key` 去重,但没有挂载根因聚合 |
| 75 | 手工 | 待处理事项有 dismissed 状态,无测试 |
| 76 | 测试 | `search.test`「两站成功 + 一站超时 → partial」 |
| 77 | 测试 | `w5a2.test` 目录复制 partial;`vertical.test` 文件明细 |
| 78 | 部分 | `agent-mock.test` 生产禁 mock;卡片引用失效没有测试 |
| 79 | 测试 | `sse.test`、`sse-pg.test` resync |
| 80 | 部分 | `logger.test`、`redact-consistency.test`、`runtime.test` 脱敏;"未知用量不填零"没有测试 |
## 5. §17 待落实事项
### 5.1 §17.2 部署配置(界面都已可配,缺的是用户的真实值)
| 项 | 状态 |
| --- | --- |
| HHWEB 所指站点的域名 / 身份 | 待用户提供(目前按 HHClub `hhanclub` 定义处理) |
| 另外 1–2 个站点 | 待用户提供(23 个定义可选) |
| 实例地址与凭据(qB、Emby、站点) | 待用户提供 |
| qB 管理标签 | 可配(每个下载器实例 `managedTag`) |
| 容器路径与共享挂载 | 待用户提供(路径映射有 verify 端点) |
| 现有目录模板 | 可配(命名模板三级覆盖);需用户确认默认模板 |
| 电影 / 剧集 / 综艺的 Slot 作用范围 | 待用户提供 |
| Copy / Move 默认范围 | 可配 |
| H&R / 保留要求及单位 | 可配;观众站缺 H&R 选择器 |
| 缓存阈值 / 恢复水位 | 可配,默认 90% / 85% / 清理目标 80% |
| 新旧媒体保留策略 | 部分:替换时旧文件进回收站,没有独立的旧版本保留策略 |
| NFO / 海报权限 | 未做(写 NFO / 图片未实现) |
| 快照周期 | 可配 |
| Pi 上游、思考档位、上下文 / 压缩预算、子会话开关 | 可配;待用户提供真实上游 |
| camofox 仓库 / 版本 / 地址 / 认证 | 待用户提供 |
| Move 遇未满足 H&R | 已定:409 + 待处理,不自动改 Copy |
| 升级后旧文件何时清理 | 未定,目前进回收站按回收站过期清理 |
| 合并版是否替换既有分段 | 未定(综艺分段未做) |
### 5.2 §17.3 技术准入
| 项 | 状态 |
| --- | --- |
| 业务核心 Deno | 已定 2.9.7 锁版本(ADR-004) |
| PostgreSQL | 已定 PG 16 + Kysely,迁移到 0040;大库规模性能未测 |
| 执行引擎 | 已定 openworkflow 0.10.1(ADR-002);旧流程跨版本升级未做产品测试 |
| Agent | 已定 pi 0.87.1;子会话自研(`agent.spawn` / `agent.await`) |
| 前端 / API | 已定 Hono + React Router 7 SPA,REST / OpenAPI / MCP |
| 浏览器 | camofox 适配完成;fork / 版本 / 画面交接待真实实例 |
| 文件工具 | 静态 ffprobe 9.0.2;真实挂载基准 B1–B3 未跑 |
### 5.3 §17.4 下一阶段产物
| # | 产物 | 状态 |
| --- | --- | --- |
| 1 | 两项目实现迁移对照 | 已做(`docs/porting/`),运行对照未做 |
| 2 | 固定版本兼容原型 | 已做(`docs/spikes/`、ADR) |
| 3 | Agent 发起并跟踪的恢复纵切 | 已做(mock,e2 / e6) |
| 4 | 四站真实脱敏样本集 | 未做,待用户提供账号 |
| 5 | 正式接口与数据迁移草案 | 已做(`packages/contracts`,旧库接入部分未做) |
| 6 | 可观测性合同 | 部分(任务流、时间线、运行状态页;根因聚合与版本覆盖矩阵只做了订阅侧) |
| 7 | PT 工作台原型 | 已做(mock);真实实例核验清单见 `docs/runbook/browser.md` §6 |
## 6. 未做功能清单(按优先级)
估算按一个开发子代理的工作日粗估,不含等待用户提供环境的时间。
| # | 功能 | 实施建议 | 估算 |
| --- | --- | --- | --- |
| 1 | 综艺分段与正片覆盖(REQ §5、R02) | 覆盖计算从"集号"改为"内容单元 × 分段":上 + 下或完整版任一满足一期;节目级策略(附加内容收录、是否等完整版、完整版出现后是否替换分段);待识别池加分段歧义事项;先收集 3–5 个节目的真实标题样本 | 5–8 天 |
| 2 | 四站真实核验(观众 / 馒头 / HHClub / CHD) | 用户给账号后逐站跑列表、详情、下载、促销、H&R、登录过期;补观众 H&R 选择器;结果写 `docs/runbook/sites.md` | 2–3 天(拿到账号后) |
| 3 | camofox 真实实例核验 | 按 `browser.md` §6 六项逐条核验,写 `verified`;决定截图轮询是否够用,不够再评估 VNC / 流式 | 2 天(拿到实例后) |
| 4 | 双版本组合校验(R04) | `checkDistinctAssets` 接进 Slot 落定与计划预留;同一资产满足第二个 Slot 时转 attention | 1–2 天 |
| 5 | 旧库分范围接管(R18、AT33) | 首次扫描任务(续扫游标,复用 `reconcileLibrary` 批处理)→ 识别登记 → 预览影响(作品数、缺口、预计下载量)→ 按库根 / 作品开启;先修 `scanIncremental` 的 partial | 5–7 天 |
| 6 | Emby 库存参与收录决策(R24) | 已确认的外部库存可满足 Slot(需证据与策略开关);Server Reconciler 写 `server_mapping`;真实 Emby / Jellyfin 验证分页与认证 | 3–4 天 |
| 7 | Agent 偏好选片(R16、AT30 / 39) | 策略增加"Agent 判断"层:确定性过滤后把候选交给有界 Agent 任务,独立预算,理由存 `acquisition_plan.evaluation`;硬排除仍由代码执行 | 4–5 天 |
| 8 | 规则学习与样本回放(R20、AT31) | 人工纠错写标注样本;策略新旧版本对历史样本回放,展示新增命中 / 误排除;Agent 发布需额外授权并可回滚 | 5–7 天 |
| 9 | 委托换源的替换计划(R27 例外流程) | 新能力生成"替换计划":新候选 + 原任务处置(保留 / 暂停 / 移除 / 删数据分别授权),一次审批或持续授权覆盖 | 2–3 天 |
| 10 | 备份恢复演练自动化(AT20 / 56) | compose 夜间任务:备份 → 清库 → 恢复 → 只读对账 → 映射行数比对;定时任务"备份"从占位改为真实执行 | 2 天 |
| 11 | Pi 上游真实验证(R26) | 用户提供 1–2 个真实上游(API Key 与一种订阅登录)跑 e2 纵切;Codex `_randomBytes` spike | 1–2 天 |
| 12 | 测试补缺 | AT18 恶意标题 e2e、AT29 部分入库不清理、AT42 未纳管占用、AT73 多下载器同 hash、流程版本升级回归 | 3 天 |
| 13 | NFO / 图片投影(R10) | 遵守字段锁,临时文件 + 原子提交,写入受库根策略控制 | 2–3 天 |
| 14 | 身份巡检与挂载根因聚合(R09、AT74) | Identity Reconciler 周期核对外部对象;同一库根离线的事项按根因合并 | 3 天 |
| 15 | HTTP 失败自动切浏览器(R06、AT35) | 站点适配器在登录失效 / 挑战时按策略转浏览器会话,仍失败再进待处理 | 2–3 天 |
| 16 | 调查整个 qB 实例(AT43) | 只读能力列出实例全部任务(含未纳管),一次性操作不写管理标签 | 1–2 天 |
| 17 | 通知渠道 | REQ 未列为必需;若要做,先做 webhook 出站(待处理新增 / 解决),Telegram 之后 | 2 天 |
| 18 | Transmission / Plex、Skill 管理、业务 CLI | M3 范围,真实需求出现后再排 | — |
说明:任务书里曾列为缺口的"多 qB 缓存卷汇总"已实现(`services/volumes.ts` 按 `cache_volume_key` 汇总),缺的只是未纳管任务的测试(第 12 项)。
## 7. 与 REQ 的有意偏离
| 偏离 | 说明 | 记录位置 |
| --- | --- | --- |
| 运行时先 Node 后改 Deno | REQ 首选 Deno;W0 曾用 Node 24,W1 后迁到 Deno 2.9.7,现已符合 REQ | ADR-001(已取代)、ADR-004 |
| 不引入 Redis / Deno KV | 与 REQ §9.1 一致;限流与短期缓存放 PG(令牌桶、`UNLOGGED` 表),c2a 进行中 | `00` §9 |
| MP 站点定义文件加密不可用,改用 MovieClaw v0.27.0(MIT)定义 | MP `user.sites.v3.bin` 加密;MovieClaw 只取 MIT 版本,之后的附条件许可内容未使用 | `packages/adapters/src/sites/definitions/NOTICE-MovieClaw.md`、`docs/porting/license-and-provenance.md` |
| Agent 取消 plan_only / execute 模式 | REQ §10.6 的"只规划"改为会话内"先给方案"选项与 `agent.plan` 步骤清单;旧 `mode=plan_only` 兼容为 `proposeFirst` | `00` §9、`docs/runbook/agent.md` |
| 子代理自研 | REQ 说不假定 SDK 提供子代理;实现为 `agent.spawn` / `agent.await`,继承授权上限、共享预算 | `docs/runbook/agent.md`、CHANGELOG 0.2.0 |
| 命名模板与 MP 输出的差异 | 10 处:非法字符全变量转全角、空白规整、合集集号范围、扩展名小写、长度截断、安全子集不支持 for / 属性访问、已有绑定目录优先、末段必须有扩展名 | `docs/design/naming-template.md` §5、§10 |
| 识别与 MP 的故意差异 | 125 处 intentional(未知发布组兜底、期号记为 issue 等) | `docs/porting/mp-rust-logic-parity.md` §2.3 |
| 转移行为必须偏离 MP 的点 | 不覆盖、路径绑定优先、跨卷可恢复等 | `docs/porting/moviepilot-transfer.md` §3 |
| OpenWorkflow 面板自研 | 官方面板 Proprietary,只参考信息架构,直查同一 schema;后并入统一任务页 | `docs/design/openworkflow-dashboard-reference.md`、`docs/design/console-ia.md` |
| 原站视图用截图轮询 | REQ 要求同会话可视接管,传输方案待验证;先用截图 + 坐标输入,未冒充实时画面 | `docs/runbook/browser.md` |
| 永久删除开关是环境变量 | 规格原为设置项,改为 `FILES_ALLOW_PERMANENT_DELETE`,需重启生效 | `07` §3.2 |