docs(plan): mark acceptance R2/R4/S5/S6/S8 fixed (W4-E3)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
ceff9cf51f
commit
673cb3920a
1 file changed
+5
-5
@@ -33,9 +33,9 @@
|
||||
| # | 问题 | 位置 | 修法 |
|
||||
|---|---|---|---|
|
||||
| R1 | `03` 的 P0 未落地。`start()` 的 `tick` 仍在直接调 `planImport`/`executeRecord`(`sweepPendingImports`),没有租约保护;`/download-cache/cleanup` 和 `/library/reconcile` 在 HTTP 请求里同步执行 | `apps/server/src/modules/acquisition-organize/index.ts:118-151`,`routes/downloads.ts`、`routes/library.ts` | 按 03 清单 P0 改为 enqueue,并返回 `{taskId, runId}`。W4-D 合入且 ci 通过后,再重跑本报告第 3 节的 e2e |
|
||||
| R2 | 所有包和 app 的版本都是 `0.0.0`,`/health` 返回的也是 `version:"0.0.0"`;仓库里没有任何 tag | `apps/server/deno.json:3` 等 10 处 | 统一改成 `0.1.0`(server 的 `denoJson.version` 会写进备份清单和 health),再打 `v0.1.0` tag |
|
||||
| R2 | 所有包和 app 的版本都是 `0.0.0`,`/health` 返回的也是 `version:"0.0.0"`;仓库里没有任何 tag | `apps/server/deno.json:3` 等 10 处 | 统一改成 `0.1.0`(server 的 `denoJson.version` 会写进备份清单和 health),再打 `v0.1.0` tag **已修(ceff9cf):所有成员与根 `deno.json` 版本改为 `0.1.0`,新增 `CHANGELOG.md`;tag 由协调者打** |
|
||||
| R3 | REQ §15.2 要求 M1 验证"授权内异常调查与恢复",AT68 也要求"查证后自动执行获准修正并继续"。现在后台调查固定是 `plan_only`:E5 只把结论写回待处理事项并交还人工,没有自动恢复这条路径 | `apps/server/src/modules/agent/service.ts:323-340`,`test/e2e/e5-auto-investigate.test.ts` | 二选一。(a) 在有 `automation_grant` 时允许调查 run 以 `execute` 模式调用 `task.retry` 或 `identity.resolve`,并加一条 e2e:下载失败 → 调查 → 授权内重试 → 入库。(b) 在 `00` §3.2 写明"授权内恢复延到 M2",并在 README 的范围说明里注明。不能不写就发布 **已修(86af723):按 (a) 实现。`agent.autoInvestigateMode=recover` 且有覆盖恢复动作的持续授权(绑定策略须为 published)时,调查 run 以 execute 模式运行,白名单为只读能力加 `task.retry` / `download.recheck`(新增能力)/ `identity.resolve`,换源、删除、清理不在白名单内。恢复结果按 download_task / task / source_release 的业务状态核实,核实通过后事项 resolved,run 汇报"已恢复(系统核实)"。没有授权时降级为只读调查,并在事项上留下建议。同一根因的尝试次数有上限。新增 e2e `e6-auto-recover`,覆盖 missingFiles → recheck → 核实、无授权降级、换源被拒、去重、尝试上限和预算超限** |
|
||||
| R4 | `POST /organization-records` 的 `sourcePaths` 没有任何根目录约束。持 `organize.execute` 的 API Key 可以 walk 任意目录(dryRun 时会泄漏文件清单),也可以把任意文件 Move 进媒体库并删掉源文件。这条路径不检查 automation_grant,也不检查 H&R | `apps/server/src/modules/acquisition-organize/services/organize.ts:229-241`,`routes/organization.ts:84-130` | `sourcePaths` 必须落在已登记的下载器路径映射(本机视图)或显式的导入根下,并且不能在任何 library_root 内;`action=move` 且调用方是 api_key 时要求有持续授权。补 403/422 反例测试 |
|
||||
| R4 | `POST /organization-records` 的 `sourcePaths` 没有任何根目录约束。持 `organize.execute` 的 API Key 可以 walk 任意目录(dryRun 时会泄漏文件清单),也可以把任意文件 Move 进媒体库并删掉源文件。这条路径不检查 automation_grant,也不检查 H&R | `apps/server/src/modules/acquisition-organize/services/organize.ts:229-241`,`routes/organization.ts:84-130` | `sourcePaths` 必须落在已登记的下载器路径映射(本机视图)或显式的导入根下,并且不能在任何 library_root 内;`action=move` 且调用方是 api_key 时要求有持续授权。补 403/422 反例测试 **已修(ceff9cf):`sourcePaths` realpath 后必须在已登记的 library_root 或下载器路径映射本机前缀下,拒绝 `..` 与符号链接逃逸(遍历用 lstat 不跟随),dryRun 同样受限 → 400;Move 需管理员会话或 API Key + 覆盖作品的 automation_grant / 与请求一致的一次性 approval(用后 consumed)→ 否则 403;纳管来源 H&R 未满足 → 409 + 待处理,不改 Copy。测试 `__tests__/organize-guard.test.ts`** |
|
||||
|
||||
### 1.2 应修(v0.1.x 内,11 项)
|
||||
|
||||
@@ -45,10 +45,10 @@
|
||||
| S2 | 服务端 logger 的脱敏覆盖面比 agent 和 adapters 的实现窄。实测 `redactString("/rss?rsskey=abc&torrent_pass=dead&authkey=zz&downhash=q1&c_secure_pass=cc")` 只遮住了 passkey。现在一共有 4 份脱敏实现(W1 的 S8 还没解决,反而多了一份) | `apps/server/src/logger.ts:6-8`,`packages/agent/src/redact.ts`,`packages/adapters/src/{rss,browser}/redact.ts` | 在 contracts(或新建的共享包)里保留唯一一份实现,取 agent 版的参数全集;logger 改为复用它;在 `logger.test.ts` 加上述 5 类参数的用例 **已修(f48e1aa):键表与规则收到 `@umt/contracts` 的 `redact.ts`,logger 与 `redactForModel` 共用;adapters 的 rss/browser 两份仍独立,留到 M2 收口** |
|
||||
| S3 | TMDB 网络错误时,`TmdbError` 的 message 直接拼上 Deno fetch 的错误信息。Deno 的这条信息里带完整 URL,也就带着 `api_key`;`cause` 里同样有(W1 的 S7 没有解决) | `packages/adapters/src/tmdb/client.ts:171-175` | message 先经过 redact,`cause` 不透传;或者强制使用 Bearer(accessToken) **已修(f48e1aa):message 经 `redactUrl`,`cause` 只留脱敏后的 name/message** |
|
||||
| S4 | 服务端授权器的单次审批分支(payloadHash/revision 变化后失效、过期、用后标为 consumed、approvalId 与计划不符)**没有任何测试**。AT15/AT16 在产品层也没有被验证 | `apps/server/src/modules/agent/authorize.ts:115-137` | 新增 `test/agent/authorize.test.ts`,对真实 PG 覆盖 6 条正反例;再加一条 e2e:审批后改计划 → 被拒 → 重新审批 → 成功且只消费一次 **已修(f48e1aa):`test/agent/approvals.test.ts` 覆盖 8 条拒绝分支与改计划→重批→只消费一次→不可重放;e2e 版留给 E2 系列** |
|
||||
| S5 | M1 要求的"一部常规剧集"没有端到端链路。E1 和 E2 只覆盖电影;剧集只在识别单测(resolve)和整理单测(organize-move)里分别出现过 | `apps/server/test/e2e/` | 新增 E7:RSS 剧集 S01E01 → 识别出 series 和单元 → Slot → qB → Copy 入库;第二集改译名后仍进旧目录 |
|
||||
| S6 | AT24(管理标签被移除、qB 任务消失)在服务端没有测试。代码在 `downloads.ts:359-383` 里,只有 domain 层的 `download-state` 单测覆盖 | `__tests__/vertical.test.ts` | 补两个断言:去掉标签后 `managed=false`、历史保留、之后不再暂停也不再清理;任务消失后 `removed`,并且库文件还在 |
|
||||
| S5 | M1 要求的"一部常规剧集"没有端到端链路。E1 和 E2 只覆盖电影;剧集只在识别单测(resolve)和整理单测(organize-move)里分别出现过 | `apps/server/test/e2e/` | 新增 E7:RSS 剧集 S01E01 → 识别出 series 和单元 → Slot → qB → Copy 入库;第二集改译名后仍进旧目录 **已修(ceff9cf):新增 E7 `e7-tv-series`:S01E01/E02 进同一绑定季目录、逐集覆盖、整季包按实际文件覆盖、总集数未知时 Slot 不满足且持续订阅继续;顺带修正剧集 Slot 在临时单元下被误判满足** |
|
||||
| S6 | AT24(管理标签被移除、qB 任务消失)在服务端没有测试。代码在 `downloads.ts:359-383` 里,只有 domain 层的 `download-state` 单测覆盖 | `__tests__/vertical.test.ts` | 补两个断言:去掉标签后 `managed=false`、历史保留、之后不再暂停也不再清理;任务消失后 `removed`,并且库文件还在 **已修(ceff9cf):新增 E8 `e8-tag-removal`:去标签后 managed=false、完成不入库、清理不触碰,任务消失 → removed 且资产/位置不变、不重下;以 mock qB 调用日志断言** |
|
||||
| S7 | 前端 Agent 页在生产构建里也能用 `?mock=1` 打开 mock 模式(sessionStorage 会记住),可能把演示数据当成真实运行展示,与 AT78 冲突 | `apps/web/app/api/agent.ts:37-48` | 只在 `import.meta.env.DEV` 或设置了 `VITE_AGENT_MOCK` 时启用 **已修(f48e1aa):只在 DEV 构建或后端 `pi.provider = "fake"` 时生效,生产构建忽略并清掉记住的开关(`app/api/agent-mock.test.ts`)** |
|
||||
| S8 | 引擎面板只有 cancel,没有 retry/rerun;§3.1-10 要求 "cancel/retry 操作"(02 backlog 也列了这一项) | `apps/web/app/routes/console/engine*.tsx`,`modules/auth-settings/engine-routes.ts` | 加 `POST /engine/runs/{id}/rerun`,用我们自己的 enqueue、带新幂等键实现,并写审计 |
|
||||
| S8 | 引擎面板只有 cancel,没有 retry/rerun;§3.1-10 要求 "cancel/retry 操作"(02 backlog 也列了这一项) | `apps/web/app/routes/console/engine*.tsx`,`modules/auth-settings/engine-routes.ts` | 加 `POST /engine/runs/{id}/rerun`,用我们自己的 enqueue、带新幂等键实现,并写审计 **已修(ceff9cf):`POST /engine/runs/{id}/retry`(admin,幂等键 `retry:<id>:<序号>`,审计),run 详情页"重跑"按钮;测试 `test/auth-settings/engine-retry.test.ts`** |
|
||||
| S9 | 账户 TOTP 在控制台没有入口(只有登录页的第二步),02 backlog 里是应修项 | `apps/web/app/routes/console/layout.tsx` | 账户弹层接上 `GET/POST /auth/totp` |
|
||||
| S10 | API 注册表把 `/auth/setup|login|session|logout` 标成 `read`,但实际上前三个免鉴权;`/auth/password`、`/auth/totp` 标成 `admin`,实际要求 admin 会话。按注册表生成的 scope 文档会误导外部集成方 | `packages/contracts/src/api.ts` | EndpointDef 增加 `auth: "public" | "session" | scope`,并加测试断言它与 `PUBLIC_AUTH_PATHS` 一致 **已修(f48e1aa):`EndpointDef.auth` 为 `public`/`session`,`api-registry.test` 断言与 `PUBLIC_AUTH_PATHS` 一致、session 端点拒绝 Bearer** |
|
||||
| S11 | 文档与实际不一致:任务书 §2、§4 还写着 `pnpm ci`;deploy.md 的验证记录写"21 个迁移",现在是 22 个(0017 号空缺);ci 耗时写"约 75 秒",实测约 135 秒;testkit README 没提 emby/browser mock;adapters 和 web 的 README 各只有 3 行 | `docs/plan/00-first-version-plan.md`,`docs/runbook/deploy.md:128`,`packages/testkit/README.md`,`packages/adapters/README.md` | 统一更新;adapters README 列出 8 个子模块的入口,并链接各子目录的 README **已修(f48e1aa):任务书 pnpm→deno task、ci 耗时、deploy.md 迁移数、testkit/adapters/web README;adapters 实际 7 个子模块** |
|
||||
|
||||
Reference in new issue
Block a user