7.2 KiB
7.2 KiB
id, title, phase, deps, status, created, vikunja_task_id, context_ref, work_branch, needs_device, needs_human_review, write_paths
| id | title | phase | deps | status | created | vikunja_task_id | context_ref | work_branch | needs_device | needs_human_review | write_paths | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| T-308 | 客户端提交围栏与结果 sink | 3 |
|
TODO | 2026-08-04 | 49 | 8600c33 |
task/t-308-submission-sink | false | true |
|
问题 / 背景
T-303 只提供 claim/renew/evidence 的严格 HTTP、本地 DPAPI/SQLite 与恢复底座,T-307 只实现围栏前 events/fail,二者都明确禁止伪造 fence/result。T-208 将冻结服务端 CREATE_ONCE、LOOKUP_ONLY、一次性 result 与同一 submission 调和语义。T-308 补齐客户端提交围栏与结果 sink,并把许可、点击意图和结果恢复事实写入 T-303 的同一 localstate;本任务不连接真机、不接 UI、不执行或暴露任何点击。
关联需求与交互
- 功能:F-007、F-011、F-017。
- 用户故事:US-004、US-005、US-008。
- 交互:IX-011;只实现后台契约和恢复状态,不实现界面。
- 依赖:T-208、T-303、T-307。
- 后续消费者:T-400 离线单次提交安全编排。
- API:CREATE_ONCE / LOOKUP_ONLY submission fence 与一次性 submission result;严格消费 T-208 最终 wire。
方案
- 定义窄 SubmissionSink:create_submission_fence、lookup_submission_fence、prepare_click_intent、report_submission_result。proof/result 值对象只含 T-208 固定 UUID、claim 归属、规范十进制金额、正整数、三闸门 AssetRef、精确 submit 文本/计数和固定 observation;不接收自由页面文本、XML、路径、selector、坐标或动作脚本。
- HTTP 必须复用 T-303 的精确 loopback、禁代理/重定向、有界请求/响应和严格 JSON 解析。每次方法最多一次传输,不在 transport 或 sink 内隐藏重试。
- 只扩展 T-303 的同一 SQLite/localstate,不建立第二个数据库。首次网络前原子保存 fence_key、operation、完整规范 proof、active claim 绑定和预期状态;DPAPI、SQLite 或归属校验失败时零 HTTP。
- CREATE_ONCE 结果不明时只允许以原 fence_key、原 proof 调用 LOOKUP_ONLY。不得换 key、再次 CREATE_ONCE 或根据本地页面猜测围栏是否存在;LOOKUP_ONLY 找到或未找到都不得产生可点击许可。
- 只有当前进程当前 CREATE_ONCE 调用收到首次、明确、完整且严格核对的 click_permitted=true 响应,并已把 submission 与许可事实 durable 落盘后,才由模块私有工厂返回 opaque SubmissionPermit。响应截断、协议漂移、落盘失败、重放、LOOKUP_ONLY 或 click_permitted=false 均不返回 permit。
- SubmissionPermit 不提供公共构造器,不可 pickle/JSON/复制,不写入 SQLite、日志或异常。SQLite 只保存围栏和恢复审计事实;重启后无论数据库记录什么都不能重建可点击 permit,只能进入同一 submission 的调和路径。
- prepare_click_intent 必须消费当前进程唯一 permit,在返回一次性 ArmedSubmission 前原子写入“即将发出唯一点击”。同 permit 二次调用、并发调用、active claim 漂移或已有点击意图均拒绝;重启只看到 reconcile-only 事实,不能重新 arm。
- result_key、固定 observation 与 submission/attempt/冻结归属在首次 result HTTP 前原子保存。结果不明和重启只能重放原 key、原载荷;明确成功后保存服务端终态。同一 submission 不得创建第二个 observation 或把 UNKNOWN 改写成 SUBMITTED。
- 401、403、409、非法 2xx、本地状态错误按 T-303 分类停止;网络、超时、5xx 只表示原幂等 HTTP 可调和,绝不表示 fence、permit、点击或页面动作可重试。
- 构造和 import 闭包不包含 pdd、device、uiautomator2、UI、execution、app、通用 click、SubmitOrderPort、submit_order_once 或任何 payment 能力。
验收要点
- 覆盖首次 CREATE_ONCE、同键重放、LOOKUP_ONLY 找到/未找到、响应截断/漂移、落盘失败、401/403/409/503;只有首次明确且 durable 成功返回 opaque permit。
- 覆盖并发围栏、并发 prepare_click_intent、同 permit 二次消费、进程重启和 SQLite 恢复;任一非首次路径均无法获得或重建 permit/ArmedSubmission。
- 证明 fence/result 首次网络前已持久化完整键、载荷与 frozen claim 绑定;不明结果只重放原 HTTP 事实,不产生新 key 或第二 observation。
- 证明 SQLite/WAL、日志、异常和 DTO 不含明文 token、页面正文、XML、本机路径、selector、坐标或可点击对象。
- 静态 import/AST 检查证明 pdd/device/UI/app/execution、真机 click、submit_order_once 和任何付款能力不可达。
- client 全量 unittest、compileall、wheel metadata、完整 init、上下文、Vikunja export 与 diff-check 通过。
- needs_human_review:人工审阅 opaque permit 的构造边界、首次许可与重启不可重建证明;确认前不得标 DONE。
执行记录
(暂无)
边界
- 本任务只实现 T-208 已冻结的
CREATE_ONCE、LOOKUP_ONLY与一次性 result 客户端契约, 并复用 T-303 同一 transport/localstate。不得另建 HTTP 客户端、SQLite、DPAPI 封装或第二份 权威恢复状态;本地与服务端事实冲突时只能停止并调和。 - 只有当前进程当前
CREATE_ONCE调用收到首次、明确、完整且已 durable 落盘的click_permitted=true响应,才可由模块私有工厂产生 opaqueSubmissionPermit。同键重放、LOOKUP_ONLY、响应不明、解析/落盘失败、并发输家和服务重启均不得产生许可。 SubmissionPermit与一次性ArmedSubmission不得公开构造、序列化、复制、写入 SQLite 或从 恢复快照重建。SQLite 只能保存围栏、点击意图与调和事实;进程退出后即使尚不能确认是否点击, 也只能进入RECONCILE_ONLY,不能重新 arm。- fence/result 的 key、完整规范载荷和 frozen claim 绑定必须先原子持久化再发送。HTTP 结果不明
只能重放原 key、原载荷;不得换 key、再次
CREATE_ONCE、覆盖 observation 或把 HTTP 可恢复 错误解释为页面动作可重试。 - 本任务不得导入或修改
client/src/cmbuyer_client/pdd/**、device/**、ui/**、execution/**或app.py,不得连接真机、持有 selector/坐标/节点/点击对象,也不得实现SubmitOrderPort、submit_order_once()或任何通用/具体点击。 - 本任务不编写支付、免密支付、先用后付或任何扣款能力。外部支付、安全校验与未知结果只能作为 T-208 固定 observation 保存并转调和,不能继续交互、释放围栏、重新授权、重新领取或再次提交。
needs_human_review: true:自动验证完成后仍保持DOING,等待人审 opaque permit 构造边界、 首次许可唯一性和重启不可重建证明;未经明确确认不得标DONE。