2026-08-03 12:13:39 +08:00
|
|
|
|
# API 合约
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
> 本文是采购服务与采购工具之间的唯一线协议权威。页面判据和本地类名不是线协议。
|
|
|
|
|
|
> 接口形状参考前序项目的经验,但所有状态与安全语义在 cmbuyer 重新定义、测试和取证。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 通用约定
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 生产前缀:`/api/v1`;管理页面路由见 [routes.md](routes.md)。
|
|
|
|
|
|
- JSON 使用 UTF-8;时间为 UTC RFC 3339;ID 为 UUID 字符串。
|
|
|
|
|
|
- 金额均为规范十进制字符串,如 `"12.88"`;禁止 JSON number 和浮点计算。
|
|
|
|
|
|
- 所有写接口接受 `request_id` / 业务幂等键;同键同载荷重放同一结果,同键异载荷返回 `409`。
|
|
|
|
|
|
- 任务写入携带 `expected_task_version`;版本冲突返回 `409 version_conflict`。
|
|
|
|
|
|
- 服务端错误不得回显设备 token、完整节点树、地址、手机号或支付信息。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 身份
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 身份 | 凭据 | 能力 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 管理员 | `HttpOnly; Secure; SameSite=Lax` 会话 cookie + CSRF | 建单、开始采购、查看内部证据、人工调和 |
|
|
|
|
|
|
| 设备 | `Authorization: Bearer <device-token>` + 设备 id | 心跳、领取、事件、截图、围栏与结果 |
|
|
|
|
|
|
| ERP(V2) | 独立凭据 | 只读来源同步,不访问采购结果 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
设备凭据不能建单或开始采购;管理会话不能调用设备接口。未认证统一返回 `401`,无权返回 `403`。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### 错误响应
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"error": {
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"code": "version_conflict",
|
|
|
|
|
|
"message": "任务已变化,请刷新后重选",
|
|
|
|
|
|
"retryable": false,
|
|
|
|
|
|
"request_id": "018f..."
|
2026-08-03 12:13:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
`retryable=true` 只表示接口调用可以按同一幂等键重放,不表示可以重试任何真机点击。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
## 一、管理端接口
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 方法 | 路径 | 作用 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| `GET/POST` | `/login` | 登录页 / 建立管理员会话 |
|
|
|
|
|
|
| `POST` | `/logout` | 退出并使会话失效 |
|
|
|
|
|
|
| `GET` | `/tasks` | SSR 任务表格;关键词、状态、时间筛选 |
|
|
|
|
|
|
| `POST` | `/tasks` | 手工创建 `DRAFT` |
|
|
|
|
|
|
| `POST` | `/tasks/start-purchases` | 批量开始采购:创建一次性授权并原子转 `PENDING` |
|
|
|
|
|
|
| `GET` | `/tasks/{id}` | 任务完整页;同一 URL 也可由列表详情抽屉加载 |
|
|
|
|
|
|
| `POST` | `/tasks/{id}/reset-to-draft` | 围栏前人工处理后关闭旧授权,回到 `DRAFT` |
|
|
|
|
|
|
| `POST` | `/tasks/{id}/cancel` | 围栏前取消任务 |
|
|
|
|
|
|
| `POST` | `/order-submissions/{sid}/reconcile` | 围栏后人工调和同一提交 |
|
|
|
|
|
|
| `POST` | `/tasks/{id}/mark-paid` | 人工确认已付款并完成核对 |
|
|
|
|
|
|
| `GET` | `/evidence/{asset_id}` | 登录后读取内部截图;`Cache-Control: no-store` |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### `POST /tasks`
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
核心字段:
|
2026-08-03 15:00:49 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"create_key": "018f...",
|
|
|
|
|
|
"title": "纯棉短袖",
|
|
|
|
|
|
"product_url": "https://mobile.yangkeduo.com/goods.html?goods_id=937122477375",
|
|
|
|
|
|
"sku_color": "黑色CHA(纯棉)",
|
|
|
|
|
|
"sku_size": "M(建议100-115)",
|
|
|
|
|
|
"quantity": 2,
|
|
|
|
|
|
"max_total_price": "30.00"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- 服务端解析并保存 canonical URL 与 `goods_id`;URL 非拼多多商品页、`goods_id` 缺失或含歧义则拒绝。
|
|
|
|
|
|
- `max_total_price` 是本任务允许创建待付款订单的总额上限,不是参考单价。
|
|
|
|
|
|
- 成功只产生 `DRAFT`;不得创建授权、开放设备领取或触发真机。
|
|
|
|
|
|
|
|
|
|
|
|
### `POST /tasks/start-purchases`
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"start_key": "018f...",
|
2026-08-03 15:00:49 +08:00
|
|
|
|
"tasks": [
|
2026-08-04 16:25:34 +08:00
|
|
|
|
{"task_id": "018f-task-1", "expected_task_version": 1},
|
|
|
|
|
|
{"task_id": "018f-task-2", "expected_task_version": 1}
|
2026-08-03 15:00:49 +08:00
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
管理员按钮必须显示为“开始采购(只创建待付款订单)”。**点击本身就是授权**:允许采购工具按任务
|
|
|
|
|
|
锁定字段创建一笔待付款订单;不再等待试选后人工确认,也不授权付款。
|
2026-08-03 15:00:49 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
服务端在一个事务中:
|
|
|
|
|
|
|
|
|
|
|
|
1. 校验列表非空、无重复任务,所有任务均为 `DRAFT` 且版本一致;
|
|
|
|
|
|
2. 校验每条任务的 `goods_id`、规格、正整数数量和最高总价完整;
|
|
|
|
|
|
3. 为每条任务创建一次性 `order_authorization`,锁定任务版本、上述字段、管理员、时间和有效期;
|
|
|
|
|
|
4. 把所有任务转为 `PENDING` 并递增版本。
|
|
|
|
|
|
|
|
|
|
|
|
任一条失败则整批不变。相同 `start_key` + 相同任务集合重放同一批结果;集合或版本不同返回 409。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"start_key": "018f...",
|
|
|
|
|
|
"authorized_count": 2,
|
|
|
|
|
|
"tasks": [
|
|
|
|
|
|
{"task_id": "018f-task-1", "task_version": 2, "authorization_id": "018f-auth-1"},
|
|
|
|
|
|
{"task_id": "018f-task-2", "task_version": 2, "authorization_id": "018f-auth-2"}
|
|
|
|
|
|
],
|
|
|
|
|
|
"payment_automated": false
|
2026-08-03 12:13:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 围栏前重置与围栏后调和
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- `reset-to-draft` 必须同时校验任务版本、授权 id 与“尚无 `order_submission`”。关闭旧授权后回到
|
|
|
|
|
|
`DRAFT`;重新开始必须产生新版本与新授权。
|
|
|
|
|
|
- 一旦存在 `order_submission`,重置、取消、授权过期和重新开始都返回 `409 submission_fenced`。
|
|
|
|
|
|
- `reconcile` 只能处理指定 `sid`:人工记录“已创建待付款订单”或“确认未创建/无法完成”。它不能
|
|
|
|
|
|
触发设备点击、释放围栏或签发新授权。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
## 二、设备侧接口
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 方法 | 路径 | 作用 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
| --- | --- | --- |
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| `POST` | `/api/v1/devices/heartbeat` | 上报设备、ADB、App 版本和能力状态 |
|
|
|
|
|
|
| `POST` | `/api/v1/tasks/claim-next` | 原子领取一个 `PENDING` 授权任务或重放本设备未结束领取 |
|
|
|
|
|
|
| `POST` | `/api/v1/tasks/{id}/lease/renew` | 续租;只允许当前 claim |
|
|
|
|
|
|
| `POST` | `/api/v1/tasks/{id}/events` | 批量追加结构化步骤事件 |
|
|
|
|
|
|
| `POST` | `/api/v1/tasks/{id}/evidence` | 显式上传一个内部原始截图 |
|
|
|
|
|
|
| `POST` | `/api/v1/purchase-attempts/{aid}/fail` | 围栏前停止并回传失败摘要 |
|
|
|
|
|
|
| `POST` | `/api/v1/purchase-attempts/{aid}/submission-fence` | 提交当前三闸门摘要并原子申请唯一围栏 |
|
|
|
|
|
|
| `POST` | `/api/v1/order-submissions/{sid}/result` | 点击后一次性上报观察结果;只调和不重试 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### `POST /api/v1/devices/heartbeat`
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"device_id": "desk-01",
|
|
|
|
|
|
"client_version": "0.1.0",
|
|
|
|
|
|
"adb_serial": "192.168.0.173:5555",
|
|
|
|
|
|
"android_release": "16",
|
|
|
|
|
|
"pdd_version": "8.17.0",
|
|
|
|
|
|
"state": "READY"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
服务端可返回 `app_version_allowed=false`;采购工具必须停止领取,不能只显示警告后继续。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### `POST /api/v1/tasks/claim-next`
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
请求携带 `device_id`、`session_id`、`claim_request_id`。领取与授权绑定且具租约:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"task": {
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"id": "018f-task",
|
|
|
|
|
|
"version": 3,
|
|
|
|
|
|
"title": "纯棉短袖",
|
|
|
|
|
|
"product_url": "https://mobile.yangkeduo.com/goods.html?goods_id=937122477375",
|
|
|
|
|
|
"goods_id": "937122477375",
|
|
|
|
|
|
"sku_color": "黑色CHA(纯棉)",
|
|
|
|
|
|
"sku_size": "M(建议100-115)",
|
2026-08-03 12:13:39 +08:00
|
|
|
|
"quantity": 2,
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"max_total_price": "30.00"
|
2026-08-03 12:13:39 +08:00
|
|
|
|
},
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"authorization": {
|
|
|
|
|
|
"id": "018f-auth",
|
|
|
|
|
|
"task_version": 2,
|
|
|
|
|
|
"expires_at": "2026-08-04T10:00:00Z"
|
|
|
|
|
|
},
|
|
|
|
|
|
"attempt": {
|
|
|
|
|
|
"id": "018f-attempt",
|
|
|
|
|
|
"claim_token": "opaque-single-claim-token",
|
|
|
|
|
|
"claim_generation": 1,
|
|
|
|
|
|
"lease_expires_at": "2026-08-04T09:05:00Z"
|
|
|
|
|
|
}
|
2026-08-03 12:13:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 只返回有 `ACTIVE` 授权的 `PENDING`;服务端在一个事务中转为 `CLAIMED` 并创建 attempt。
|
|
|
|
|
|
- 同一 `claim_request_id` 同载荷重放同一结果;并发设备只有一个成功。
|
|
|
|
|
|
- 一个设备有未结束领取时优先重放该领取,不能悄悄领第二条。
|
|
|
|
|
|
- 响应不得包含自由动作脚本、CSS/XPath、通用坐标或支付能力。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 事件与证据
|
2026-08-04 10:59:40 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
事件只包含固定 `step` / `outcome` / `reason_code` 和非敏感摘要。禁止把完整 XML、地址、手机号、
|
|
|
|
|
|
页面全文或 token 塞进日志字段。
|
2026-08-04 15:47:47 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
截图接口使用 `multipart/form-data`,只接受单个显式文件及以下元数据:
|
2026-08-04 10:59:40 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"attempt_id": "018f-attempt",
|
|
|
|
|
|
"kind": "SKU_PANEL_GATE_1",
|
2026-08-04 15:47:47 +08:00
|
|
|
|
"privacy_tier": "INTERNAL_RAW",
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"sha256": "64-lowercase-hex",
|
|
|
|
|
|
"captured_at": "2026-08-04T09:01:00Z"
|
2026-08-04 10:59:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 允许规格面板和确认页截图保留页面已显示的地址/手机号;不要求遮罩或裁剪。
|
|
|
|
|
|
- 不接受 XML、目录、manifest、本机绝对路径、外部支付页截图或支付凭据。
|
|
|
|
|
|
- MIME、尺寸、字节数和 SHA-256 必须校验;资产只经管理员鉴权端点读取。
|
2026-08-04 10:59:40 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### `POST /api/v1/purchase-attempts/{aid}/submission-fence`
|
|
|
|
|
|
|
|
|
|
|
|
客户端只有在当前页面四条件中的后三项已经满足后才能调用:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"fence_key": "018f-fence-request",
|
|
|
|
|
|
"task_id": "018f-task",
|
|
|
|
|
|
"expected_task_version": 3,
|
|
|
|
|
|
"authorization_id": "018f-auth",
|
|
|
|
|
|
"claim_token": "opaque-single-claim-token",
|
|
|
|
|
|
"selected_color": "黑色CHA(纯棉)",
|
|
|
|
|
|
"selected_size": "M(建议100-115)",
|
|
|
|
|
|
"gate1_unit_price": "12.88",
|
|
|
|
|
|
"gate2_unit_price": "12.88",
|
2026-08-03 12:13:39 +08:00
|
|
|
|
"quantity_read": 2,
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"confirm_page_amount": "25.76",
|
|
|
|
|
|
"submit_control_match_count": 1
|
2026-08-03 12:13:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
服务端在一个事务中校验:任务/版本/claim/attempt 一致;授权有效未消费且字段等于任务快照;
|
|
|
|
|
|
规格与授权相等;数量相等;两个单价相等;计算金额及确认页金额均不超过 `total_price_cap`;提交控件
|
|
|
|
|
|
计数为一;此前不存在该授权或 attempt 的 submission。随后创建唯一 `order_submission`,授权转
|
|
|
|
|
|
`FENCED`,任务保持不可重领。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
首次明确成功响应:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"submission_id": "018f-submission",
|
|
|
|
|
|
"status": "FENCED",
|
|
|
|
|
|
"click_permitted": true,
|
|
|
|
|
|
"submit_text": "提交订单"
|
2026-08-03 12:13:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 任一校验失败返回错误,绝不返回 `click_permitted=true`。
|
|
|
|
|
|
- 同一 `fence_key` 的重放返回同一 `submission_id`,但 `click_permitted=false` 且
|
|
|
|
|
|
`reconciliation_required=true`;客户端不能凭重放响应点击。
|
|
|
|
|
|
- 客户端收到首次许可后,必须先把“围栏已取得/即将发出唯一点击”持久化,再执行点击。进程崩溃或
|
|
|
|
|
|
本地状态不明时宁可转调和,也不再次点击。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### `POST /api/v1/order-submissions/{sid}/result`
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
2026-08-04 16:25:34 +08:00
|
|
|
|
"result_key": "018f-result",
|
|
|
|
|
|
"attempt_id": "018f-attempt",
|
|
|
|
|
|
"observation": "SUBMITTED",
|
|
|
|
|
|
"evidence_asset_id": "018f-asset"
|
2026-08-03 12:13:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
`observation` 只允许:
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- `SUBMITTED`:明确订单已创建,转 `WAITING_PAYMENT`;
|
|
|
|
|
|
- `EXTERNAL_PAYMENT_HANDOFF`:已跳外部支付,停止并转 `RECONCILIATION_REQUIRED`;
|
|
|
|
|
|
- `SECURITY_CHALLENGE`:出现安全校验,停止并转调和;
|
|
|
|
|
|
- `UNKNOWN`:超时、断连或页面不明,转调和。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
提交后没有“retry”观察值。任何结果都不能释放围栏或开放第二次点击。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 文本和金额校验
|
|
|
|
|
|
|
|
|
|
|
|
- 规格字段:Unicode 规范化后精确相等;不得包含、前缀、编辑距离或 AI 猜测。
|
|
|
|
|
|
- `goods_id`:仅 ASCII 十进制数字,canonical URL 中唯一。
|
|
|
|
|
|
- 金额:`0.01` 到系统配置上限,至多两位小数;规范化后再比较和持久化。
|
|
|
|
|
|
- 数量:正整数,服务端与设备均设置合理上限;不能从字符串静默截断。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-03 16:27:05 +08:00
|
|
|
|
## 三、采购工具本地模块合约
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
|
|
|
|
|
### `TaskSource` / `ResultSink`
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
2026-08-04 16:25:34 +08:00
|
|
|
|
class TaskSource(Protocol):
|
|
|
|
|
|
def claim_next(self, session: Session) -> ClaimedPurchase | None: ...
|
|
|
|
|
|
def renew_lease(self, claim: Claim) -> Lease: ...
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
class ResultSink(Protocol):
|
|
|
|
|
|
def append_events(self, claim: Claim, events: list[TaskEvent]) -> None: ...
|
|
|
|
|
|
def upload_screenshot(self, claim: Claim, asset: ScreenshotAsset) -> AssetRef: ...
|
|
|
|
|
|
def fail_attempt(self, claim: Claim, failure: AttemptFailure) -> None: ...
|
|
|
|
|
|
def create_submission_fence(self, claim: Claim, proof: SubmissionProof) -> SubmissionPermit: ...
|
|
|
|
|
|
def report_submission_result(self, permit: SubmissionPermit, result: SubmissionResult) -> None: ...
|
2026-08-03 12:13:39 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
执行器不能依赖具体 HTTP 或 Excel 实现。`SubmissionPermit` 只能由 `ResultSink` 的服务端成功响应构造,
|
|
|
|
|
|
业务代码不能手工 new 一个许可。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
### 真机能力分层
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
| 能力 | 输入 | 输出 | 安全边界 |
|
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
|
| `open_product()` | canonical URL + 证据版本 | 已确认商品页 | URL、前台包、App 版本全部匹配 |
|
|
|
|
|
|
| `open_sku_panel()` | 版本绑定受控入口 | 已确认规格面板 | 精确唯一;无通用 click |
|
|
|
|
|
|
| `select_sku_options()` | 维度 → 精确值 | 选中态摘要 | 维度内唯一匹配并读回 |
|
|
|
|
|
|
| `read_sku_unit_price()` | 已确认规格面板 | 十进制单价 | 排除原价、按钮价和歧义候选 |
|
|
|
|
|
|
| `set_quantity_and_readback()` | 授权数量 | 实际数量 | 精确读回,否则停 |
|
|
|
|
|
|
| `go_to_order_confirm()` | 已通过闸门二 | 确认页摘要 | 后续真机任务取证后才实现 |
|
|
|
|
|
|
| `submit_order_once()` | 不可伪造的首次 `SubmissionPermit` | 观察结果 | 许可、闸门、唯一控件全校验;点前持久化;绝不重试 |
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
T-103 只实现隔离的 `SkuSelectionFlow`:前四项加安全退出。它的模块和静态依赖不得引用数量、确认页、
|
|
|
|
|
|
围栏、提交或支付能力。后续任务按取证顺序组合成生产 `SinglePassPurchaseFlow`。
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
## 四、实现前仍需定值
|
2026-08-03 12:13:39 +08:00
|
|
|
|
|
2026-08-04 16:25:34 +08:00
|
|
|
|
- 授权有效期、领取租约时长、心跳/轮询间隔和连续失败停止阈值;
|
|
|
|
|
|
- 截图大小上限和内部保留期限;
|
|
|
|
|
|
- 可配置单任务数量与最高总价系统上限;
|
|
|
|
|
|
- 首次真实提交真机任务的人工授权和待付款订单处置步骤。
|