Files
soft_quay/docs/tasks/T-301.md
T

4.7 KiB

id, title, phase, deps, status, created, issue, context_ref, claim_branch, work_branch, write_paths
id title phase deps status created issue context_ref claim_branch work_branch write_paths
T-301 可恢复下载队列 3
T-202
DOING 2026-07-16 null a52acbf926 null agent/codex/T-301
docs/tasks/T-301.md
core/downloader/
core/application/
core/storage/
schemas/download-task.schema.json
testdata/download/
testdata/README.md
docs/api.md
docs/04-architecture.md
docs/current-state.md

问题 / 背景

Phase 2 已能识别软件状态并展示列表/详情,但点击下载后还没有并发调度、暂停/取消/重试、HTTP Range 续传或重启恢复。若下载状态只保存在 goroutine 内存中,盒子退出后任务丢失;若 Range 响应、临时文件和元数据不一致,可能把拼接错误的字节交给 T-302 校验/安装链路。

T-301 是 T-302/T-303 的前置安全边界。它只负责把远端 ZIP 稳定下载为隔离的 .part/完成文件并发布进度事件,不声称包已可信可执行。

方案

  1. 在 core/downloader 定义任务模型、队列命令与状态机;默认最多 2 个 active transfer,其余保持 queued。
  2. 支持 enqueue、pause、resume、cancel、retry;每个命令按稳定 request_id / app_id 定位,重复命令返回确定结果而非产生第二份任务。
  3. HTTP transport 使用注入接口和标准库实现:
    • 已有 .part 时发送 Range: bytes=<offset>-。
    • 206 必须校验 Content-Range 起点;不匹配则拒绝。
    • 服务端返回 200 时安全截断并从 0 重下,不得追加到旧字节。
    • 网络中断保留已落盘 .part;取消按策略删除任务临时文件;完成前 flush/sync/close。
  4. 在 core/storage 持久化下载任务元数据,采用同目录临时文件 + backup 原子替换;Schema 落到 schemas/download-task.schema.json。
  5. 启动恢复时:
    • queued / paused / failed 保持可恢复语义。
    • 进程退出时遗留的 downloading 降级为 queued,不假装仍在下载。
    • 元数据与 .part 实际长度不一致时以磁盘为准或返回稳定损坏错误,不得静默跳过字节。
  6. application 事件沿用 DownloadStarted / DownloadProgress / DownloadPaused / DownloadCompleted / DownloadFailed;负载使用具体类型,UI 只消费事件,不轮询文件。
  7. 进度包含 done/total/speed;total 未知时明确表示 unknown,不伪造百分比。事件节流与 clock 注入保证测试确定性。

验收要点

  • 并发默认值为 2;表驱动/阻塞 transport 测试证明任意时刻 active transfer 不超过 2,完成/暂停后下一个 queued 自动开始。
  • pause 保留 .part 和元数据;resume 使用正确 Range;cancel 不再发布进度且按协议清理;failed 可 retry。
  • httptest 覆盖:正常 200、正确 206、错误 Content-Range、服务器忽略 Range 返回 200、连接中断后续传、非成功状态。
  • 任务元数据严格读写;未知字段、非法状态/ID/URL/路径/计数被拒绝;主文件缺失时可读取中断遗留 backup。
  • 新队列实例能从磁盘恢复;遗留 downloading → queued,paused 保持 paused,已完成任务不重复下载。
  • .part 长度、done 与下一次 Range offset 一致;不把未完成文件暴露为完成文件。
  • application 具体事件负载与 request_id/app_id 匹配;进度 done 单调不回退,暂停/取消后不出现迟到 progress。
  • cd core && go vet ./... && go test -count=1 ./...、完整双目标闸门与治理校验通过。

边界(不改什么)

  • 不做 ZIP SHA-256 / package 签名、app.json 比对、解压、staging 切换或健康检查(T-302)。
  • 不做磁盘空间预检查、程序占用、hash_mismatch/zip_corrupt 等完整失败矩阵(T-303)。
  • 不实现 Gio DownloadPanel;本任务只交付 core 队列、持久化与事件,后续 UI 通过事件接入。
  • 不实现多源下载、P2P、带宽限速、代理设置或动态并发 UI。
  • 不引入第三方下载器、数据库或 Go 1.21+ API。

协作约束

  • 唯一写入 Agent 独占本任务全部 write_paths,负责实现但不创建额外任务提交。
  • 测试设计 Agent 只读输出并发、Range、崩溃恢复和事件时序测试矩阵。
  • 安全/架构 Agent 只读审查路径隔离、响应拼接、持久化原子性、迟到事件和 T-302 信任边界。
  • coordinator 汇总意见、要求必要修正、执行最终验证、更新本执行记录并创建唯一 T-301 Git 提交。
  • T-302/T-303 在本任务 DONE 前不得领取;若后续决定并行编码,先另行落成并提交带后缀子任务及共享接口冻结任务。

执行记录

  • 2026-07-16:正式落成多 Agent 协作方式;采用一个写入 Agent + 测试设计/安全架构两个只读 Agent,保持 T-301 → T-302 → T-303 依赖串行。