diff --git a/T-206.-.md b/T-206.-.md new file mode 100644 index 0000000..9a92b5a --- /dev/null +++ b/T-206.-.md @@ -0,0 +1,157 @@ + +> 同步来源:[`docs/tasks/T-206.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-206.md) · commit `afc651f75a3a` + +--- +id: T-206 +title: App 接入领取、有限离线执行和进度 +phase: 2 +deps: + - T-202 + - T-205 +status: DONE +created: 2026-07-27 +context_ref: 45d1436 +work_branch: main +write_paths: + - README.md + - android-buyer/** + - backend-api/** + - docs/00-ai-start-here.md + - docs/02-requirements.md + - docs/03-tech-stack.md + - docs/04-architecture.md + - docs/05-coding-rules.md + - docs/07-user-stories.md + - docs/08-interaction-checklist.md + - docs/api.md + - docs/current-state.md + - docs/routes.md + - docs/tasks/T-206.md + - progress.md +--- + +## 问题 / 背景 + +T-205 已实现 BUYER + 设备联合鉴权、readiness heartbeat、原子 claim、任务参考图、 +start、90 秒运行租约、release 和取消确认,但 Android 仍只消费本地 fixture。 +管理员创建的 `PENDING` 任务无法在手机领取。 + +90 秒运行租约要求手机持续连接管理后端,与“手机独立完成采购,只从管理后端领取并 +回传结果”的目标冲突。T-206 需要接入后端任务,同时把运行租约扩展为有限离线执行 +授权;后台失联不能导致任务被另一台设备重复执行,也不能让手机无限离线运行。 + +Roubao 原有独立模式和端上 VLM 设置必须保留。后台任务不得下发或覆盖 VLM provider、 +Base URL、model、prompt 或 API Key。 + +## 关联需求与交互 + +- 功能:F-003、F-007、F-009。 +- 用户故事:US-003、US-006、US-007、US-009。 +- 交互:IX-004、IX-005、IX-006、IX-008、IX-010。 +- 架构/API:`HttpTaskSource`、设备联合身份、claim/运行租约、有限离线执行、前台服务 + 和本地 outbox。 + +## 已定合约 + +1. 管理后端只负责身份、任务分配、状态、取消和结果审计;App 独立负责 VLM、拼多多 + 自动化、人工确认、本地状态和待上传结果。 +2. BUYER 登录同时提交预授权 device ID/secret;access token、device secret、 + claim token 和幂等 key 使用 Android Keystore 支撑的加密存储,不进入 SavedState、 + 普通 SharedPreferences、崩溃报告或日志。 +3. App 每次领取前发送设备 heartbeat。未就绪、已有活跃任务或服务端离线时不能领取; + 用户点击后才生成并持久化 claim token 与幂等 key。 +4. `CLAIMED` 默认租约仍为 10 分钟。start 后默认运行授权从 T-205 的 90 秒调整为 + 30 分钟,可在 5 至 120 分钟范围配置;成功 heartbeat 使用服务端时间滑动续期。 +5. App 计划每 30 秒 best-effort heartbeat,以同步步骤和取消请求。heartbeat 失败时 + 可在服务端下发的 `execution_expires_at` 前继续,不能因为短时断网停止或生成新 + execution;到期仍未恢复连接时必须在安全检查点停止自动化。 +6. `RUNNING/WAITING_CONFIRMATION` 无论授权是否过期都不自动回队列。重新分配必须先 + 由人员结束旧 execution,避免两台手机同时操作同一任务。 +7. 管理取消在 App 离线期间不能保证即时生效。恢复连接后 App 必须先 heartbeat, + 收到取消标志便在下一个安全检查点停止并 `cancel-ack`,不得先继续页面动作。 +8. App 在授权内完成但暂时无法上传时,把结果、事件和证据引用写入加密 outbox。 + T-207 允许原设备在授权过期后补交终态结果,并标记 + `received_after_execution_expiry=true`;过期后不得继续自动化。 +9. App 重启先恢复加密本地 execution,再与服务端核对。无法证明任务归属、授权时间 + 或本地步骤安全时停止并等待人工处理,不领取第二条任务。 +10. Roubao 独立模式与后台任务共享现有本地 workflow/VLM 能力,但任务源和同步边界 + 独立。后台任务不能携带 provider 配置,也不能触发 App 修改本地模型设置。 +11. T-206 验证登录、领取、预览、start、前台步骤、有限离线、恢复、release 和取消; + 真实候选/截图/事件/终态回传由 T-207 完成。 + +## 方案 + +1. 增加严格的后端地址、认证 client、Keystore-backed secret store、持久 task state + 和稳定错误映射。Release 后端地址只接受 HTTPS;开发证书路径与生产隔离。 +2. 实现 `HttpTaskSource`,把 claim 和 task-scoped 参考图规范化为现有领域输入; + workflow/AI/automation 不判断任务来自 fixture 还是 HTTP。 +3. 接入登录、任务主页、预览、运行和恢复状态;重复点击、空队列、登录失效、授权 + 到期和服务端冲突均使用已确认页面反馈。 +4. 扩展后端运行租约配置及 start/heartbeat 响应,显式返回 + `execution_expires_at`;保持 RUNNING 不自动回收的 T-205 安全规则。 +5. 前台服务持有 execution,best-effort heartbeat 并使用服务端时间偏移判断离线 + 截止点。网络恢复后先同步取消/归属,再恢复允许的步骤。 +6. 增加加密本地状态/outbox 基础接口;T-206 只验证恢复和安全停止,不实现 T-207 + 的完整结果 payload。 + +## 验收要点 + +- [x] 预授权 BUYER 在真机登录成功;错误账号、错误设备、禁用和过期均被拒绝,秘密 + 不出现在日志和普通存储。 +- [x] 真机 heartbeat 后点击“获取任务”只领取管理 Web 创建的一条 `PENDING` 任务, + 显示标题、SKU、数量、描述和参考图;无任务显示空状态。 +- [x] 重复点击和模拟响应丢失不会重复领取;App 重启能恢复同一 `CLAIMED`/RUNNING。 +- [x] start 返回默认约 30 分钟 `execution_expires_at`;断开管理后端超过 90 秒后, + 受控 fake workflow 仍能在授权内继续,任务不会分配给第二台设备。 +- [x] 离线授权到期后 App 安全停止;恢复网络先同步服务端状态,不擅自续作。 +- [x] 管理取消在在线时及时处理;离线时恢复连接后的首个同步点处理并确认。 +- [x] Roubao 原独立模式、端上 provider 选择和本地 fixture 探针回归通过;后台任务 + 不下发、覆盖或读取来自任务内容的 provider 配置。 +- [x] Android/后端测试、根 `init.ps1` 和 OnePlus PKG110 Android 16 真机 smoke + 通过,验证过程中不提交订单。 + +## 边界 + +- 不实现候选、截图、事件、complete/fail 和人工理由回传;属于 T-207。 +- 不把模型调用代理到管理后端,不实现后台 provider 配置、推送、自动领取或多任务。 +- 不承诺离线期间即时取消;不允许离线授权无限延长、自动下单或支付。 +- 不提交真实账号、设备 secret、VLM Key、订单或证据。 + +## 执行记录 + +### 2026-07-27:任务开始 + +- 基于提交 `9e698c1` 开始,工作区干净;T-202/T-205 依赖均已完成。 +- codebase-memory MCP 本轮未暴露 graph 工具,按仓库规则回退到 `rg` 和定点读取。 +- 开工基线 `.\init.ps1` 通过:Android Debug/Release 测试与 Debug APK 构建成功, + Go 全包测试、vet、gofmt 检查和 API/migration/authctl 构建成功。 +- 先固定并实现后端默认 30 分钟运行授权和 `execution_expires_at`,再让 Android + 登录、领取、恢复和前台服务依赖该契约。 + +### 2026-07-27:实现与验证完成 + +- 后端默认运行授权改为 30 分钟、允许 5-120 分钟;start/task heartbeat 的 + `execution` 显式返回 `execution_expires_at`。授权过期后原设备 heartbeat 只同步 + 状态、不延长旧授权;匹配原 execution/claim 的取消确认仍可完成,RUNNING 不回队列。 +- Android 新增独立“任务”入口、严格 backend 地址策略、无明文 fallback 的 + `ProcurementSecureStore`、`ProcurementApiClient`、`HttpTaskSource`、参考图 + MIME/JPEG/20 MiB/SHA-256 校验和加密 task/execution 恢复。密码不存储;设备 + secret、access/claim token 和各操作幂等 key 只进加密存储。 +- 前台服务每 30 秒 best-effort heartbeat;使用保守的服务端时钟偏移和持久 + `SAFE_STOPPED` 判断离线截止。登录 token 过期时只允许同后台、同 BUYER、同设备 + 重新认证;过期恢复同步不会自动继续外部动作。 +- 领取前先持久化 256 bit claim token/独立幂等 key,响应不确定时复用;参考图和 + task 快照落盘后才可预览。start 增加二次确认和至少 2 秒稳定预览门禁,避免页面 + 重组或自动化注入导致误启动;T-206 受控步骤不打开拼多多、不调用 VLM、不提交订单。 +- MockWebServer 覆盖 Android 登录、幂等领单、参考图 hash/同源限制和 start 到期契约; + 端点策略与服务端时钟/预览门禁有纯 Kotlin 单测。最终根 `.\init.ps1` 通过: + Android 32 份报告、184 次测试零失败,Go 含子测试 193 次通过,vet、gofmt 和 + API/migration/authctl Windows 构建成功。 +- PKG110 Android 16 真机使用临时 18080 后端、一次性 DPAPI 保护凭证和脱敏任务 + 完成:BUYER 登录、readiness、领取、字段/参考图预览、start、前台通知、95 秒 + 后端断线、恢复滑动续期、管理取消/`cancel-ack`、release 和进程重启恢复。断线 + 后仍为同一 `CONTROLLED_WORKFLOW`,倒计时从约 29:38 到 27:54;重连恢复到约 + 29:41。验证未打开拼多多、未调用 VLM、未提交订单。 +- 最终 Debug APK 已覆盖安装;一次性 API/数据库/DPAPI 凭证和 App 临时后台登录 + 状态已清理,Roubao 其他设置保留,采购无障碍恢复启用。T-207 接入真实端上 + VLM/候选并实现事件、证据、结果和完整加密 outbox。