From 8c50e1579e05852966d33c9bfa477c520f92fa58 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Tue, 4 Aug 2026 21:50:15 +0800 Subject: [PATCH] docs(tasks): define T-307 attempt sink --- docs/tasks/T-307.md | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docs/tasks/T-307.md diff --git a/docs/tasks/T-307.md b/docs/tasks/T-307.md new file mode 100644 index 0000000..ba38f78 --- /dev/null +++ b/docs/tasks/T-307.md @@ -0,0 +1,78 @@ +--- +id: T-307 +title: 客户端 attempt 事件与失败 sink +phase: 3 +deps: [T-205, T-303] +status: TODO +created: 2026-08-04 +vikunja_task_id: 39 +context_ref: 35d7ce1 +work_branch: task/t-307-attempt-sink +needs_device: false +needs_human_review: false +write_paths: + - docs/tasks/T-307.md + - client/src/cmbuyer_client/attempts/** + - client/src/cmbuyer_client/core/** + - client/src/cmbuyer_client/remote/** + - client/src/cmbuyer_client/localstate/** + - client/tests/attempts/** + - client/tests/core/** + - client/tests/remote/** + - client/tests/localstate/** +--- + + +## 问题 / 背景 + +T-205 将冻结 attempt events/fail 的严格服务端 wire,T-303 提供安全 HTTP 传输原则、DPAPI/SQLite 与恢复快照,但刻意不伪造完整 ResultSink。T-307 补齐客户端围栏前 HttpAttemptSink 和事件/失败幂等状态,使 T-305 只组合已完成能力;不连接真机、UI、证据、围栏或结果接口。 + +## 关联需求与交互 + +- 功能:F-006、F-007。 +- 用户故事:US-003、US-004、US-005。 +- 依赖:T-205、T-303。 +- 后续消费者:T-305。 +- API:只消费 T-205 的 events 与 fail;不实现 fence/result。 + +## 方案 + +1. 定义窄 AttemptSink 协议:append_events 与 fail_attempt。模型只含 T-205 固定 step/outcome/reason、规范十进制金额、正整数和受控 AssetRef;不接收自由页面文本、XML、路径、token、selector、坐标或动作脚本。 +2. HttpAttemptSink 复用 T-303 直连 transport 规则:精确 loopback、禁代理/重定向、有界请求/响应、严格 Content-Type/UTF-8/重复 key/未知字段;每次方法最多一个 HTTP 请求,不隐藏重试。 +3. 扩展 T-303 localstate,而不创建第二个数据库:event batch 与 fail 在首次 HTTP 前原子保存幂等 key、active claim 绑定、完整载荷与预期序号/状态;结果不明和重启只能重放原键原载荷。 +4. event 成功必须严格核对服务端批次结果并持久化已确认序号/摘要;同批重复只返回原结果。异载荷、序号漂移、服务端摘要漂移或 active claim 不一致转协议冲突,不覆盖本地事实。 +5. fail 仅消费 T-205 固定 reason 与 last_safe_step;成功后原子保存终态响应。结果不明保留同 key,不能创建第二个 fail 或把任务本地假设为已释放。 +6. 401、403、409、协议错误、本地 DPAPI/SQLite 错误按 T-303 分类停止;网络/超时/5xx 只标记同键可恢复。retryable 永不表示页面动作、证据替换、围栏或提交可重试。 +7. 停止轮询/关闭窗口不取消在途请求、不清 pending、不 release/abandon claim。重启可调和 HTTP,但绝不自动恢复真机点击。 +8. 构造与 import 闭包中没有 fence client、ResultSink、SubmissionPermit、click_permitted、submitter、PDD 或 payment 能力。 + +## 验收要点 + +- 覆盖 event/fail 成功、严格 schema、同键同载荷重放、异载荷冲突、响应截断/漂移、401/403/409/503。 +- 证明首次网络前已持久化;崩溃与重启后键/载荷/claim 绑定完全一致,active claim 漂移时零 HTTP。 +- 并发 append 序列化且不跳号;fail 与未决 event 的顺序失败闭合;成功结果不可覆盖。 +- SQLite/WAL、日志、异常不含 claim/device token、页面全文、XML、本机路径或 selector。 +- 静态检查没有 evidence 文件读取、uiautomator2/PDD、release/abandon、fence/result、提交订单或付款能力。 +- client 全量 unittest、compileall、wheel metadata、完整 init、Vikunja 导出、上下文校验与 diff-check 通过。 + +## 执行记录 + +### 2026-08-04T13:49:39Z · ila + +2026-08-04 从 T-305 预研拆出:只实现 events/fail 的客户端窄 sink 与本地幂等恢复,避免在 dry-run 集成任务中临时扩展 T-303;不实现完整 ResultSink、fence/result 或真机/UI。 + + +## 边界 + +- 只实现 T-205 已冻结的 `append_events` 与 `fail_attempt` 窄客户端契约;不得提供完整 ResultSink, + 不得访问 submission fence、result、`click_permitted`、SubmissionPermit 或提交许可。 +- 事件只含版本化固定 step/outcome/reason、规范十进制金额、正整数和受控 AssetRef。不得接收或发送 + 自由页面文本、完整 XML、地址、手机号、本机路径、token、selector、坐标或动作脚本。 +- HTTP 必须复用 T-303 精确 loopback、禁代理/重定向、严格解析与每方法一次传输边界。本任务不得 + 建第二个 transport 或隐藏重试循环;`retryable` 只允许同幂等键 HTTP 恢复,不能推导页面动作可重试。 +- Event batch 与 fail 的幂等键、active-claim 绑定和完整载荷必须先进入 T-303 同一 localstate 事务再 + 发送。结果不明、重启和停止只能重放原键原载荷;不得另建 SQLite、换 key、跳序号或覆盖已确认摘要。 +- 停止轮询、Esc、关闭窗口和进程退出不取消在途请求、不清 pending、不 release/abandon claim, + 也不触发 ADB/PDD 动作。重启只可调和同一 attempt 的 HTTP 事实,不自动恢复任何真机点击。 +- 不读取或上传 evidence 文件,不导入 uiautomator2/PDD,不实现规格、数量、确认页、围栏或结果动作; + 不编写或引用点击“提交订单”的代码,不编写支付、免密支付、先用后付或任何扣款能力。