Files

96 lines
9.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-306
title: 规格面板原始截图与可靠证据上传
phase: 3
deps: [T-104, T-303]
status: TODO
created: 2026-08-04
vikunja_task_id: 38
context_ref: 3a0a41d
work_branch: task/t-306-evidence-upload
needs_device: false
needs_human_review: false
write_paths:
- docs/tasks/T-306.md
- client/src/cmbuyer_client/evidence/**
- client/tests/evidence/**
---
<!-- BEGIN VIKUNJA EXPORT id=38 synced=2026-08-04T15:31:58Z sha256=9d3d86a2c34aab67a4ada76f3735ee8c79eddb89b1112b697f43b108a629af57 -->
## 问题 / 背景
T-104 将在规格选择、闸门一读价、原始截图和严格安全退出全部成功后返回显式 PNG 路径与实际 UTC 截图时刻;T-303 提供受设备认证的 EvidenceSink 与可崩溃恢复的唯一上传槽。T-306 只把调用方显式给出的这张 Gate1 规格面板原始截图可靠上传为内部审计证据,不连接 UI/轮询、不扩展页面能力或服务端证据类型。
服务端当前只以设备主体与 upload_key 保证幂等,并没有数据库级 `(attempt_id, kind)` 唯一约束。因此“一个 attempt 只发布一张 Gate1”必须由 T-303 本地唯一槽失败闭合保证;T-306 不能在本地状态丢失或损坏后生成新 key、扫描目录或寻找替代资产。
## 关联需求与交互
- 功能:F-007、F-013。
- 用户故事:US-004、US-005。
- 依赖:T-104、T-303;T-103 由 T-104 传递,T-204/T-302 由 T-303 传递。
- 后续消费者:T-305 围栏前 dry-run。
- 本任务可与 T-304、T-205 并行,不修改 app/polling/ui、remote/localstate、PDD 或 admin。
## 方案
1. 唯一公开接口固定为 `publish_gate1(active_claim, *, screenshot_path: Path, captured_at: datetime) -> AssetRef`。调用方不能传入 kind、privacy tier、task id 或 attempt id;接口不接受目录、manifest 或任意文件选择结果。
2. Publisher 内部固定 `kind=SKU_PANEL_GATE_1`、`privacy_tier=INTERNAL_RAW`。task/attempt/device/session/generation 归属只取 T-303 的完整 active_claim,不拆散、不重建,也不允许调用方参数覆盖。
3. `screenshot_path` 与 UTC-aware `captured_at` 只来自 T-104 成功结果。T-104 只有在规格选择、闸门一读价、原始截图和严格安全退出全部成功后才返回;post-exit 商品详情截图不得冒充 Gate1。
4. Publisher 只做窄参数适配并对 T-303 EvidenceSink 调用一次,不直接实现或调用 HTTP、SQLite、UUID、DPAPI、localstate,也不导入 PDD、ADB、uiautomator2。每次 publish 调用最多一次 sink;异常或结果不明不得内部循环重试。
5. `lstat`、常规文件与 PNG 判定、文件 identity/大小/SHA-256、固定安全 multipart 文件名、首次 HTTP 前持久化以及 `(attempt_id, evidence_kind)` 唯一 prepare-or-resume 槽全部由 T-303 负责。T-306 不另建缓存、数据库、key 或恢复状态。
6. 本地上传槽缺失、损坏或无法与完整 active_claim 核对时必须零 HTTP 失败闭合。不得生成新 upload key、枚举目录、读取 manifest、查询相似资产、改用另一张截图或重新截图;结果不明只能经 T-303 以原 key、原字节和原元数据恢复。
7. T-303 对 201 首次成功和 200 稳定重放严格解析 AssetRef;Publisher 再核对 AssetRef 的 task/attempt 与 active_claim 一致,kind/tier 与内部固定值一致。fake sink 返回错误 task、attempt、kind 或 tier 时必须拒绝,不能把不一致引用交给后续事件。
8. 成功 AssetRef 继续保存在原槽;重复调用只返回同一结果,不能清 pending/success 后生成新 key。claim 后续关闭时,只允许原 key 对既有成功资产的稳定重放,不允许创建新槽。
9. 原始 PNG 字节保持不变,可以包含页面已显示的地址和手机号;不遮罩、不裁剪、不重编码、不 OCR,也不把页面内容解析为字段、日志或异常。完整 XML、manifest、本机路径、原文件名、外部支付页和支付凭据永不上传。
10. multipart 只使用 T-204 已冻结的字段,不增加 claim token/session/path,不扩展 SKU_PANEL_GATE_2、确认页或其他 kind;不新增页面判据、PDD 动作、事件、围栏、结果或提交能力。
## 验收要点
- 静态签名精确为 `publish_gate1(active_claim, *, screenshot_path: Path, captured_at: datetime) -> AssetRef`;kind/tier/task/attempt 不能成为调用方参数,内部只固定 Gate1/InternalRaw。
- T-104 成功产物只调用一次 sink;安全退出失败、无 active claim、claim 归属不一致、UTC 时间非法、文件缺失或变化均零 HTTP,且 Publisher 不做内部重试。
- 首次传输前 T-303 唯一槽已持久化;结果不明和重启后 key/bytes/metadata 原样重放,重复成功返回同一 AssetRef,关闭 claim 后只能重放既有成功资产。
- 本地槽缺失、损坏或不可验证时零 HTTP,证明不会生成新 key、扫描目录、读取 manifest、寻找替代文件或重新截图。
- fake sink 分别返回错误 task、attempt、kind、tier 的 AssetRef 时 Publisher 全部拒绝;正确 AssetRef 原样返回。
- 用包含地址/手机号的合成有效 PNG 证明传给 sink 的原始字节完全不变;日志和异常不含页面正文、token、本机路径或原文件名。
- 拒绝目录、XML、manifest、JPEG、post-exit 截图和未批准 kind;静态检查没有目录枚举、图像变换/OCR、HTTP/SQLite/UUID、uiautomator2、PDD/ADB、数量、确认页、围栏、提交订单或付款能力。
- client 全量 unittest、compileall、wheel metadata、完整 init、Vikunja 导出、上下文校验与 diff-check 通过。
## 执行记录
### 2026-08-04T13:47:38Z · ila
2026-08-04 预研定值:T-306 收窄为 T-104 gate1 单张原始 PNG 到 T-303 唯一持久上传槽的可靠适配,因此可与 T-304/T-205 并行;不扩展服务端 kind、不另建 SQLite、不连接真机或 UI。
<!-- END VIKUNJA EXPORT -->
## 边界
- 唯一发布接口固定为
`publish_gate1(active_claim, *, screenshot_path: Path, captured_at: datetime) -> AssetRef`。调用方不得
传入 kind、privacy tier、task id 或 attempt id;`kind=SKU_PANEL_GATE_1` 与
`privacy_tier=INTERNAL_RAW` 只能由 Publisher 内部固定,task/attempt/device/session/generation 归属
只能取自 T-303 的完整 `active_claim`,不得拆散、重建或由其他参数覆盖。
- `screenshot_path` 与 UTC-aware `captured_at` 只能来自 T-104 在规格选择、闸门一读价、规格面板原始
截图和严格安全退出全部成功后返回的显式结果。不得枚举目录、读取 manifest、使用文件选择器,也不得
把 post-exit 商品详情截图或其他文件冒充规格面板证据。
- 只发布一个 `kind=SKU_PANEL_GATE_1`、`privacy_tier=INTERNAL_RAW` 的原始 PNG;task/attempt 只来自
当前 active claim。不得增加 gate2/确认页 kind,不得修改 admin schema/API,也不得自行向 multipart
增加 claim token、session、路径、原文件名或其他字段。
- Publisher 每次调用只适配一次 T-303 `EvidenceSink`,不得直接实现或调用 HTTP、SQLite、UUID、DPAPI
或本地状态细节,也不得导入 PDD/ADB。`lstat`、常规 PNG 判定、文件 identity/大小/SHA-256、首次发送
前原子持久化和 `(attempt_id, evidence_kind)` 唯一恢复槽全部由 T-303 负责。
- 服务端当前只保证设备主体与 `upload_key` 幂等,不保证数据库级 `(attempt_id, kind)` 唯一。因此本地
上传槽缺失、损坏或无法验证时必须在零 HTTP 下失败闭合;绝不能生成新 key、扫描目录、读取 manifest、
查询相似资产或重新截图来“恢复”。结果不明只能经 T-303 以原 key、原字节、原元数据恢复。
- T-303 返回的 AssetRef 必须再次匹配当前 active claim 的 task/attempt 以及固定 kind/tier;fake sink
返回错 task、attempt、kind 或 tier 时 Publisher 必须拒绝,不能把不一致引用交给后续事件。成功
AssetRef 继续保存在原槽,重复调用只能返回同一结果,不能清槽后生成第二个 key。
- 每次调用最多一次 HTTP,不在内部循环重试。文件缺失或 identity/大小/hash 变化时必须零 HTTP 并
转人工;不得重新截图、替换文件或在目录中寻找“相似”截图。
- 停止轮询、Esc、关闭窗口和进程退出不取消在途上传、不清 pending、不删除原图、不 release/abandon
claim,也不触发任何 ADB/PDD 动作。重启只可恢复同一 HTTP 请求,不自动恢复设备页面操作。
- 原始 PNG 字节必须保持不变,可以包含页面已显示的地址和手机号;不得遮罩、裁剪、重编码、OCR,
也不得把地址或手机号解析为业务字段、日志或异常文本。完整 XML、manifest、本机路径、页面全文、
外部支付页和支付凭据不上传。
- 不导入或实现 uiautomator2、PDD 页面判据、通用 click、规格/数量/确认页动作、事件、失败上报、
提交围栏或结果接口;不编写或引用点击“提交订单”的代码,不编写支付或任何扣款能力。