From 8092431208ee1880a77c44280f37e6a9a57f4ee3 Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Tue, 4 Aug 2026 22:41:59 +0800 Subject: [PATCH] docs(tasks): order evidence before attempt events --- docs/06-tasks.md | 11 ++++++----- docs/current-state.md | 38 ++++++++++++++++++++------------------ docs/tasks/T-205.md | 39 ++++++++++++++++++++++++++------------- docs/tasks/T-210.md | 20 ++++++++++++-------- 4 files changed, 64 insertions(+), 44 deletions(-) diff --git a/docs/06-tasks.md b/docs/06-tasks.md index 33df85c..d468353 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -19,7 +19,7 @@ Phase 是里程碑分组,不是整段串行栅栏。推荐波次: | --- | --- | --- | --- | | 1 | T-001 → T-004 → T-201 → T-202 | T-002 → T-101 → T-102 | T-003、原型与契约 | | 2 | T-209 → T-203 → T-204 | T-103 → T-104 → T-105 → T-107 | T-111 单趟重构;逐任务主审 | -| 3 | T-205 →(T-206 → T-207)/ T-210 → T-208 | T-301 → T-302 → T-303,再并行 T-304 / T-306 / T-307 | 双端契约完整门禁 | +| 3 | T-210 → T-205 → T-206 → T-207 → T-208 | T-301 → T-302 → T-303,再并行 T-304 / T-306 / T-307 | 双端契约完整门禁 | | 4 | - | T-305 | 围栏前端到端 dry-run 主审 | | 5 | T-402 / T-403 | T-401 | 真机人工授权、提交与调和验收 | | 6 | - | T-405 | T-404 完整验收 | @@ -28,7 +28,8 @@ Phase 是里程碑分组,不是整段串行栅栏。推荐波次: - T-202 只创建/展示 `DRAFT`,可与 T-103 并行;T-203 只实现管理员授权与任务状态,不依赖页面 选择器,也可在 T-103 完成前推进。 -- T-205 起涉及实际 attempt/证据字段,必须等待 T-103 确认规格和价格最小事实。 +- T-210 必须等待 T-107 真机确认三闸门证据类型;T-205 再基于三类真实 asset 冻结事件与摘要, + 不允许用 mock 或缺证据事件绕过生产 schema。 - T-103、T-105、T-106、T-107 的 capability 相互隔离;未经取证的后续动作不可提前暴露。 - T-401 前任何任务都不得真实点击“提交订单”;支付能力永远不实现。 - 主 agent 独立审阅每个子 agent 的 diff 并重跑验证,不以其自报完成作为证据。 @@ -77,11 +78,11 @@ T-106 / T-107 是发布前只读验证,不是业务任务的第一趟。首次 | T-209 | 把核心 schema / 状态机迁移为单趟模型 | T-004, T-111 | 新 migration 安全替换旧 `spec_trials` / 授权锁价结构;新增 `purchase_attempts`;删除旧 MVP 状态;无业务数据事实写入迁移前置,遇未知旧数据 fail closed;领域/迁移测试同步 | | T-203 | 表格查询与批量开始采购(F-004、F-008、F-018) | T-202, T-209 | 只选 DRAFT;按钮明确“不付款”;事务内创建锁定任务字段的一次性授权并全批 `DRAFT → PENDING`;重放/冲突测试 | | T-204 | 路由化任务详情与内部截图资产(F-007、F-011) | T-203 | 抽屉/完整页共享 URL;状态详情;受保护 `INTERNAL_RAW` screenshot 上传/读取、SHA-256 与 no-store;不接收 XML | -| T-205 | purchase attempt、事件与执行摘要 API | T-103, T-204, T-301, T-302 | 记录实际规格、两次单价、数量、确认页金额、固定 reason;不再创建 `spec_trials` 审批记录 | -| T-210 | 扩展闸门二与闸门三证据类型 | T-107, T-205 | 精确扩展 Gate2/Gate3 kind;保留 Gate1、归属/FK/trigger/幂等;有新事实时拒绝降级 | +| T-210 | 扩展闸门二与闸门三证据类型 | T-107, T-204, T-302 | 先精确扩展 Gate2/Gate3 kind;保留 Gate1、归属/FK/trigger/幂等;有新事实时拒绝降级 | +| T-205 | purchase attempt、事件与执行摘要 API | T-210 | 三条成功事件分别绑定正确 Gate1/2/3 asset,冻结摘要与围栏前 reason;不再创建 `spec_trials` 审批记录 | | T-206 | 单趟状态视图与安全主动作 | T-205 | PENDING/CLAIMED/ORDERING/NEEDS_MANUAL/WAITING_PAYMENT/RECONCILIATION_REQUIRED 显示和允许动作一致;无中途确认 | | T-207 | 授权有效期与围栏前重置(F-010) | T-206 | 围栏前过期/关闭旧授权后回 DRAFT;围栏后拒绝释放、取消、重新授权 | -| T-208 | 提交围栏与结果调和 API(F-017) | T-207, T-107, T-210 | 原子复核授权/attempt/三闸门/唯一控件;首次许可一次;重放不许可点击;结果不明永久围栏且只调和 | +| T-208 | 提交围栏与结果调和 API(F-017) | T-207, T-210 | 原子复核授权/attempt/三闸门/唯一控件;首次许可一次;重放不许可点击;结果不明永久围栏且只调和 | ### Phase 3 · 双端打通(单趟围栏前) diff --git a/docs/current-state.md b/docs/current-state.md index 68385c3..34a6ddb 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -19,15 +19,16 @@ - 技术栈:已定。采购服务(`admin/`)使用 Go 1.23+ / gin / SQLite;采购工具(`client/`) 使用 Python 3.11+ / uiautomator2 / PySide6。 详见 [`03-tech-stack.md`](03-tech-stack.md) -- 生产代码:`admin/` 已有最小 Go 服务、健康检查、核心领域模型、SQLite 迁移与任务状态机; +- 生产代码:`admin/` 已有登录/会话、手工 DRAFT 建单、批量开始采购与一次性授权、任务详情、内部 + 原始截图、设备身份,以及已授权任务的原子领取/幂等重放/租约续期; `client/` 已有 Python 包、PySide6 最小入口、运行目录与日志脱敏策略,以及显式 serial 的 ADB 连接边界、本地基线取证 CLI、受限商品链接打开取证 CLI、人工声明规格面板状态的只读取证 CLI, - 以及绑定 PKG110 / Android 16 / 拼多多 8.17.0 的规格证据确定性脱敏 CLI;尚无规格选择、价格读取或下单流程 -- 测试:采购服务已覆盖健康检查、核心模型、迁移与状态机等离线包级测试;采购工具 80 项离线单元测试 - (全部 mock,不连接真机) -- 数据:SQLite v2 单趟核心表与领域状态机已落成,旧 `spec_trials`、`authorized_unit_price` 和 - 两趟状态已由受保护迁移移除;无业务实例数据。T-203 可以基于新模型实现批量“开始采购”与 - 一次性授权事务。 + 绑定 PKG110 / Android 16 / 拼多多 8.17.0 的证据工具,以及受控规格入口、精确规格选择、SKU 当前价 + 读取、原始截图和一次安全退出能力;该能力尚待最终人工真机验收,数量/确认页/提交仍未开放。 +- 测试:采购服务已覆盖登录、建单、授权、详情/证据、设备身份、迁移、原子 claim/renew 与竞态; + 采购工具 112 项离线单元测试(全部 mock,不连接真机)。 +- 数据:受保护迁移已落到 `00005_task_claims.sql`。旧两趟模型已移除;开始采购会锁定任务快照并签发 + 一次性授权,领取会创建唯一 attempt/claim、HMAC claim token 与有界租约。仓库不含业务实例数据。 - 标准启动路径:Windows PowerShell 运行 `./init.ps1`,Unix shell 运行 `./init.sh`。Windows 入口 优先使用合规的既有 venv;仅在其缺失时才从 Python Launcher 已安装版本中选择最高的 Python 3.11+, 并且不覆盖低版本环境;成功后打印真实启动命令。 @@ -39,20 +40,22 @@ 分别取证后才接入生产单趟流程。T-103 的 v5 派生 XML 已由人确认无实际地址/ 手机号,并保留目标预选规格、顶部当前价“快卖完 ¥12.88”和原价“¥29.88”;底部“提交订单 ¥12.88” 继续属于硬拒绝区。派生截图虽然把顶部价格遮住一半,但项目已停止遮罩器开发,视觉完整性不再阻塞 - 规格选择与读价;T-204 将直接上传内部原始截图供管理员查看。T-010 已允许不依赖真机字段的 T-201 - 和只创建 `DRAFT` 的 T-202 并行。T-209 已完成 schema / 状态机单趟迁移;T-203 服务端 - “开始采购”授权事务可立即推进。T-205 起实际 attempt / 真机字段继续等待 T-103。 + 规格选择与读价;T-204 已允许认证设备上传内部原始截图供管理员查看。入口父链证据已由人确认并 + 收紧为精确唯一“快要抢光”子节点及证据绑定可点击祖先,“免拼购买”仍为硬拒绝。离线实现和 112 项 + 测试已通过;T-103 只差人把手机置于 PDD 安全起点后完成精确规格恢复、读取 `12.88` 和一次安全退出。 + 完整事件链必须等待 T-107 与 T-210:先让 Gate2/Gate3 证据进入真实 schema,再实现 T-205 事件, + 不用 mock 或无证据成功事件抢跑。 ## 当前目录要点 | 路径 | 状态 | 说明 | | --- | --- | --- | | `docs/` | 已有 | 项目规范化文档,本次已完整生成 | -| `docs/tasks/` | 已有(含 T-001~T-111、T-201~T-203、T-209) | T-111 单趟契约、T-202 手工 DRAFT 建单及 T-209 单趟 schema 已完成;T-103、T-203 并行推进 | +| `docs/tasks/` | 已有(含 T-001~T-111、T-201~T-210、T-301~T-307) | T-302 已完成;T-103 等最终真机验收,后续三闸门与双端组合任务已按依赖落成 | | `docs/design/` | 已有(6 个原型) | web 登录 / 建单 / 工作台 / 详情,desk 采购执行 / 配置;均已人工确认 | | `scripts/` | 已有 | 上下文门禁、Vikunja 单向导出与 MCP 启动包装 | -| `admin/` | 已初始化 | Go 1.23+ / gin / SQLite,含核心模型、迁移与状态机;无真机采购执行 | -| `client/` | 已初始化 | Python 3.11+ 包、依赖源、PySide6 最小入口、显式 serial 的基线/商品打开/规格面板只读取证、确定性证据脱敏、离线测试与 wheel 元数据检查;无规格选择、价格读取或下单流程 | +| `admin/` | 已初始化 | Go 1.23+ / gin / SQLite,含建单/授权/详情/证据/设备身份与原子 claim/renew;不执行真机动作 | +| `client/` | 已初始化 | Python 3.11+、PySide6/uiautomator2、真机取证及受控规格选择/读价/安全退出;数量、确认页和提交未开放 | | `init.ps1` / `init.sh` | 已完成 | 统一安装与离线验证入口;PowerShell 优先复用合规 venv,缺失时自动选择最高的 Python 3.11+,Unix 缺工具链明确失败 | ## 任务状态 @@ -68,11 +71,10 @@ - 已完成 T-010(安全并行门禁)、T-201(管理员登录与会话)与 T-202(手工 DRAFT 建单和 基础列表)。T-202 已通过主 agent 独立审查、竞态测试与完整门禁并合入主线,仍只创建/展示 `DRAFT`,未实现授权、设备领取或采购执行。 -- 已完成 T-110(受控规格入口边界)与 T-111(开始采购授权的单趟契约)。T-103 已恢复为 - `DOING`,以 `SkuSelectionFlow` 继续最小 fixture、精确规格和读价,不实现数量、确认页或提交; - 内部原始截图上传交给 T-204。admin 方向已完成 T-209,正在转入 T-203“开始采购”授权事务。 -- 已完成 T-209:SQLite v2 已迁移为单趟授权、采购尝试和提交围栏模型,并删除旧试选领域模型; - 迁移和状态机护栏已通过完整门禁。下一项采购服务任务为 T-203 批量“开始采购”与一次性授权。 +- 已完成 T-110、T-111、T-203、T-204、T-301 与 T-302。服务端已能授权、认证设备、原子领取、 + 稳定重放和续租;claim token 不是提交许可,尚无事件、提交围栏或结果 API。 +- T-103 离线 `SkuSelectionFlow` 已实现并通过独立审计,仍为 `DOING` 等人工真机验收;T-104~T-107 + 按数量/确认页风险逐段开放。服务端后续顺序已收紧为 T-210 → T-205 → T-206 → T-207 → T-208。 - 已确认原型继续只作信息架构依据;原型假数据不调用真实接口、不驱动真机。真机结论改变 可读字段时必须先回修原型与交互清单。 diff --git a/docs/tasks/T-205.md b/docs/tasks/T-205.md index 09ac988..48357ee 100644 --- a/docs/tasks/T-205.md +++ b/docs/tasks/T-205.md @@ -2,17 +2,17 @@ id: T-205 title: purchase attempt、事件与执行摘要 API phase: 2 -deps: [T-103, T-204, T-301, T-302] +deps: [T-210] status: TODO created: 2026-08-04 vikunja_task_id: 35 -context_ref: 8ec740d +context_ref: cd47d0c work_branch: task/t-205-attempt-events needs_device: false needs_human_review: false write_paths: - docs/tasks/T-205.md - - admin/migrations/00006_attempt_events.sql + - admin/migrations/00007_attempt_events.sql - admin/internal/migrations/migrations_test.go - admin/internal/attempts/** - admin/internal/taskclaim/** @@ -23,7 +23,7 @@ write_paths: - docs/04-architecture.md --- - + ## 问题 / 背景 T-302 负责创建并租赁唯一 purchase attempt,T-103 提供已取证的规格选择与闸门一能力。后续单趟执行需要把每个安全步骤以最小结构化事件追加到采购服务,并在围栏前失败时形成不可覆盖的执行摘要。T-205 只记录既有 claim/attempt 的事实和安全失败;不创建 attempt、不释放授权、不建立提交围栏、不点击或付款。 @@ -32,20 +32,21 @@ T-302 负责创建并租赁唯一 purchase attempt,T-103 提供已取证的规 - 功能:F-006、F-007。 - 用户故事:US-003、US-004、US-005。 -- 依赖:T-103、T-204、T-301、T-302。 -- 后续消费者:T-206 状态视图、T-303 HttpResultSink、T-305 围栏前 dry-run、T-208 提交围栏。 +- 依赖:T-210;T-107/T-204/T-302/T-301 由 T-210 传递满足。 +- 后续消费者:T-206 状态视图、T-307 客户端 attempt sink、T-305 围栏前 dry-run、T-208 提交围栏。 - API:`POST /api/v1/tasks/{id}/events`、`POST /api/v1/purchase-attempts/{aid}/fail`。 ## 方案 -1. 新增 `00006_attempt_events.sql`,保存 append-only attempt events、批次幂等请求和必要执行摘要;事件以 attempt 内单调序号、事件 id/批次 id、固定 step/outcome/reason、服务端接收时间及允许的最小字段组成。数据库约束禁止更新/覆盖旧序号、跨 task/attempt 或围栏后继续写。 +1. 新增 `00007_attempt_events.sql`,保存 append-only attempt events、批次幂等请求和必要执行摘要;事件以 attempt 内单调序号、事件 id/批次 id、固定 step/outcome/reason、服务端接收时间及允许的最小字段组成。数据库约束禁止更新/覆盖旧序号、跨 task/attempt 或围栏后继续写。 2. 复用 T-302 的统一 claim validator:每个请求都绑定当前设备 Bearer、session、task、attempt、generation、claim token 和未过期租约;认证在 body 前,业务事务在线性化位置再次验证设备 ACTIVE、claim/authorization/attempt 归属与状态。旧 generation/token、跨设备/会话、租约或授权过期均不能写事件。 3. 事件 API 只接受有界批次和严格 JSON。每个事件的 step/outcome/reason 来自版本化白名单,不接收自由页面文本、XML、地址、手机号、路径、token、选择器、坐标或动作脚本。金额为规范正十进制字符串,数量为正整数;未知字段、额外 JSON、序号缺口/倒退/重复异载荷全部拒绝。 4. 同一 batch id 同载荷在响应丢失/服务重启后重放原结果;同键异载荷冲突。一个事务内校验整批连续性、步骤状态机和 summary 兼容性后全批追加,任一事件非法则零写入。 -5. 第一个明确的执行开始事件只允许把 attempt `CLAIMED→ORDERING`、task `CLAIMED→ORDERING`;不得隐式续租。后续事件只在 ORDERING 中追加。规格、两次规格面板价格、数量读回、确认页金额仅由对应固定成功 step 写入 summary,不能由客户端直接覆盖已有摘要。 -6. 围栏前 fail API 只接受固定 reason code 和已记录的最后安全步骤,幂等地把当前 attempt 置 FAILED、task 置 NEEDS_MANUAL,并写终止事件/finished_at。authorization 和 claim 保持占用,等待 T-207 人工检查后显式关闭;失败请求不自动回 DRAFT、不释放、不转领。 -7. 已失败、已围栏、存在 order_submission、claim/授权/租约不再有效时拒绝新事件或新的失败结果。围栏相关状态只能由 T-208 创建,T-205 不读取或返回 `click_permitted`。 -8. 原始截图继续走 T-204/T-306;事件只引用服务端已有的受控 evidence asset id(如需要),不得上传文件或枚举本地证据目录。完整 XML 永不上传。 +5. 三条成功步骤固定为:`GATE_1_PASSED` 只携带 color、size、unit_price 和 `SKU_PANEL_GATE_1` asset id;`GATE_2_PASSED` 只携带 color、size、quantity、unit_price 和 `SKU_PANEL_GATE_2` asset id;`GATE_3_PASSED` 只携带 color、size、quantity、confirm_amount、submit_control_text、submit_control_match_count、submit_control_enabled 和 `ORDER_CONFIRM_GATE_3` asset id。每个 asset 必须属于同一 task/attempt/device/generation 且 kind 精确匹配;缺失、错 kind、跨归属或证据未明确成功时整批零写入。 +6. 第一个明确的执行开始事件只允许把 attempt `CLAIMED→ORDERING`、task `CLAIMED→ORDERING`;不得隐式续租。后续事件只在 ORDERING 中追加。规格、两次规格面板价格、数量读回、确认页金额仅由对应固定成功 step 写入 summary,不能由客户端直接覆盖已有摘要。 +7. 围栏前 fail API 只接受固定 reason:`DEVICE_UNAVAILABLE`、`APP_VERSION_MISMATCH`、`PRODUCT_OPEN_FAILED`、`SKU_PANEL_UNAVAILABLE`、`SKU_SELECTION_MISMATCH`、`GATE_1_PRICE_INVALID`、`QUANTITY_MISMATCH`、`GATE_2_PRICE_INVALID`、`ORDER_CONFIRM_UNAVAILABLE`、`GATE_3_MISMATCH`、`SUBMIT_CONTROL_NOT_UNIQUE`、`CLAIM_NOT_CURRENT`、`AUTHORIZATION_EXPIRED`、`EVIDENCE_UPLOAD_UNRESOLVED`、`PAGE_RESULT_UNKNOWN`、`STEP_TIMEOUT`、`DRY_RUN_COMPLETED_BEFORE_FENCE`,以及已记录的最后安全步骤。幂等地把当前 attempt 置 FAILED、task 置 NEEDS_MANUAL,并写终止事件/finished_at。authorization 和 claim 保持占用,等待 T-207 人工检查后显式关闭;失败请求不自动回 DRAFT、不释放、不转领。`EXTERNAL_PAYMENT_HANDOFF`、`SECURITY_CHALLENGE` 与 `UNKNOWN` 是围栏后 result observation,不得作为围栏前失败码。 +8. 已失败、已围栏、存在 order_submission、claim/授权/租约不再有效时拒绝新事件或新的失败结果。围栏相关状态只能由 T-208 创建,T-205 不读取或返回 `click_permitted`。 +9. 原始截图继续走 T-204/T-306;事件只引用服务端已有的受控 evidence asset id(如需要),不得上传文件或枚举本地证据目录。完整 XML 永不上传。 ## 验收要点 @@ -62,6 +63,10 @@ T-302 负责创建并租赁唯一 purchase attempt,T-103 提供已取证的规 ### 2026-08-04T13:44:42Z · ila 2026-08-04 与 T-302 恢复契约定值:第一个执行开始事件在同一事务把 attempt/task 从 CLAIMED 转为 ORDERING,并把 task.version 恰好递增一次;后续事件不再递增。T-302 同会话恢复只接受 ORDERING 且当前版本等于领取快照版本+1,其他版本漂移转人工。 + +### 2026-08-04T14:39:03Z · ila + +2026-08-04 契约收紧:T-205 改为依赖 T-210、迁移 00007;冻结 GATE_1/2/3_PASSED 的完整字段与对应 evidence kind,并冻结围栏前失败码和 DRY_RUN_COMPLETED_BEFORE_FENCE。围栏后 observation 不得伪装成围栏前失败。 ## 边界 @@ -73,13 +78,21 @@ T-302 负责创建并租赁唯一 purchase attempt,T-103 提供已取证的规 缺口、异载荷、跨 attempt、跨设备或并发冲突不得覆盖、跳过或重排既有事实。 - 只接收版本化白名单中的 step/outcome/reason 及该步骤必需的规范金额、正整数数量和受控引用。 不接收自由页面文本、完整 XML、地址、手机号、本机路径、token、动作脚本、选择器或坐标。 +- 三条成功步骤只能是 `GATE_1_PASSED`、`GATE_2_PASSED`、`GATE_3_PASSED`,且分别引用同一 + task/attempt/device/generation 下精确 kind 为 `SKU_PANEL_GATE_1`、`SKU_PANEL_GATE_2`、 + `ORDER_CONFIRM_GATE_3` 的已成功 asset。缺证据、错 kind、跨归属或上传结果不明时零事件写入。 - 实际规格、闸门一/二单价、数量读回和确认页金额只能由对应固定成功步骤首次写入执行摘要;后续 - 冲突值必须拒绝,不能最后写入者覆盖。金额始终是十进制字符串,不用浮点数。 + 冲突值必须拒绝,不能最后写入者覆盖。闸门三还必须首次固定提交控件精确文案、匹配数和启用态; + 金额始终是十进制字符串,不用浮点数。 - 第一个执行开始事件必须在同一事务中把 attempt/task 从 `CLAIMED` 转为 `ORDERING`,并把 task `version` **恰好递增一次**;后续事件不得继续递增。T-302 的同会话恢复只可把 ORDERING 解释为 领取快照版本加一,其他版本漂移必须转人工,不能用“状态是 ORDERING”跳过版本一致性。 - 围栏前失败只把 attempt 置 `FAILED`、task 置 `NEEDS_MANUAL` 并留下终止事实;authorization 与 claim 保持占用,等待 T-207 人工检查。不得自动回 `DRAFT`、释放、重新授权、转领或重试页面动作。 +- 围栏前 reason 必须来自任务方案冻结的精确白名单,包含 `DRY_RUN_COMPLETED_BEFORE_FENCE`; + `EXTERNAL_PAYMENT_HANDOFF`、`SECURITY_CHALLENGE` 与 `UNKNOWN` 只属于围栏后 result observation, + 不得伪装成可恢复的围栏前失败。 - 不实现或引用 submission fence、`click_permitted`、订单结果、提交订单点击。不得编写支付、免密 支付、先用后付或任何扣款控件代码;第一趟试选/围栏前路径不得可达下单函数。 -- 不扩展 T-204 的截图 kind,不上传 XML/manifest/目录,不接触真机页面判据或 client 代码。 +- 不在 T-210 三种证据 kind 之外继续扩展截图,不上传 XML/manifest/目录,不接触真机页面判据或 + client 代码。 diff --git a/docs/tasks/T-210.md b/docs/tasks/T-210.md index 1d3d15d..9352df6 100644 --- a/docs/tasks/T-210.md +++ b/docs/tasks/T-210.md @@ -2,17 +2,17 @@ id: T-210 title: 扩展闸门二与闸门三证据类型 phase: 2 -deps: [T-107, T-205] +deps: [T-107, T-204, T-302] status: TODO created: 2026-08-04 vikunja_task_id: 43 -context_ref: 772e379 +context_ref: cd47d0c work_branch: task/t-210-gate-evidence-kinds needs_device: false needs_human_review: false write_paths: - docs/tasks/T-210.md - - admin/migrations/00007_gate_evidence_kinds.sql + - admin/migrations/00006_gate_evidence_kinds.sql - admin/internal/migrations/migrations_test.go - admin/internal/evidence/** - admin/internal/storage/evidence/** @@ -22,7 +22,7 @@ write_paths: - docs/06-tasks.md --- - + ## 问题 / 背景 T-204 当前数据库和 API 只允许 SKU_PANEL_GATE_1;T-107 将以真机证据批准闸门二规格面板和闸门三确认页截图。T-210 在不改变上传身份、大小、隐私或幂等边界的前提下,安全扩展两个固定证据类型,为 T-305 提供完整三闸门审计。 @@ -30,15 +30,15 @@ T-204 当前数据库和 API 只允许 SKU_PANEL_GATE_1;T-107 将以真机证 ## 关联需求与交互 - 功能:F-007、F-013、F-017 的证据部分。 -- 依赖:T-107、T-205;T-204/T-302 由 T-205 传递。 -- 后续消费者:T-305、T-208。 +- 依赖:T-107、T-204、T-302。 +- 后续消费者:T-205、T-305、T-208。 - 只修改采购服务证据 schema/validation,不修改 client 或页面判据。 ## 方案 -1. 新增 00007 迁移,把 evidence kind 白名单精确扩展为 SKU_PANEL_GATE_1、SKU_PANEL_GATE_2、ORDER_CONFIRM_GATE_3;保留所有旧 gate1 资产和审计身份,不把 kind 变成任意字符串。 +1. 新增 00006 迁移,把 evidence kind 白名单精确扩展为 SKU_PANEL_GATE_1、SKU_PANEL_GATE_2、ORDER_CONFIRM_GATE_3;保留所有旧 gate1 资产和审计身份,不把 kind 变成任意字符串。 2. SQLite 表重建/约束迁移必须在事务内保持 foreign_keys=ON,迁移后运行 foreign_key_check;保留 T-302 claim ownership trigger、唯一键、索引、已有外键和所有列约束。不得通过关闭 FK 或丢弃历史行绕过。 -3. 降级只在没有 gate2/gate3 资产及其事件引用时允许;存在新事实必须原子拒绝,不能静默把新 kind 改名为 gate1 或删除记录。 +3. 降级只在没有 gate2/gate3 资产时允许;存在新事实必须原子拒绝,不能静默把新 kind 改名为 gate1 或删除记录。 4. 领域白名单、multipart handler、store 与返回 DTO 只增加这两个常量;设备认证仍先于 Content-Type/body,首次写入仍要求当前设备未关闭 claim,closed claim 只允许旧 key replay。 5. 三个 kind 均只接受单个显式 INTERNAL_RAW PNG,沿用 10 MiB、像素、SHA-256、原子文件发布、固定字段和不上传 XML/path 的边界。 6. kind 与页面事实固定映射:Gate1/Gate2 只能规格面板,Gate3 只能订单确认页。服务端不解析图片或推断页面;真实性由 T-107/T-305 事件顺序和人工验收保证。 @@ -57,6 +57,10 @@ T-204 当前数据库和 API 只允许 SKU_PANEL_GATE_1;T-107 将以真机证 ### 2026-08-04T14:06:35Z · ila 2026-08-04 从 T-305 拆出服务端证据类型扩展:只在 T-107 取证批准后增加固定 Gate2/Gate3 kind,保留 Gate1 与 T-302 ownership/replay 边界;不让 T-306 或 dry-run 临时改 schema。 + +### 2026-08-04T14:39:05Z · ila + +2026-08-04 依赖审计反转 T-210/T-205:三种 evidence kind 必须先进入真实 SQLite schema,T-205 才能对 Gate1/2/3 成功事件做真实正向与错 kind/跨归属测试。T-210 改为 00006,依赖 T-107/T-204/T-302。 ## 边界