# POST /api/v1/price/step — 外卖比价 Phase 2 步进（透传 + done 帧 harvest 落库）

> 所属:Compare 组（前缀 `/api/v1`,外卖比价） | 鉴权:**软鉴权 OptionalUser**（带 JWT 则绑 `user_id`,不带也放行） | [← 返回 API 索引](../README.md)

## 入参
任意 JSON body,**不做 schema 校验**,原样透传给上游。后端从中读 `device_id`、`trace_id`、`step`、`device_info` 用于日志与落库。
客户端逐帧上报 `screen_state` + 上一步 `action_result`;`step=0` 还带 `query` + `calibration`（来自 Phase 1）。

## 出参
pricebot-backend 的响应**原样返回**（JSON object）,并在顶层补 `trace_id`（见下「trace_id 签发」）。含 `action`（tap / set_text / launch / wait / done…）、`continue`、`status`、每帧顶层 `trace_url`;最终 `done` 帧带 `comparison_results`（源 + 各目标平台到手价,按价升序）。

## 错误码
- `400` body 不是合法 JSON
- `502` pricebot 上游不可达（网络错误）或返回 5xx

## 说明
把请求体原样转发到 `PRICEBOT_BASE_URL` 的 `/api/price/step`（去掉 `/v1`,共享 httpx 单例）。**多轮循环**:客户端按返回的 `action` 操作手机、再上报下一帧,直到 `continue=false`。真正的目标驱动比价逻辑（多目标平台串行复现订单、读到手价、聚合排序）在 **pricebot-backend**。

**不再是纯透传壳(2026-07 起,`compare.py`)**:
- **trace_id 签发**:客户端首帧可不带 `trace_id`——app-server 用 uuid 签发、注入转发 body、回填进响应顶层 `trace_id`,客户端后续帧都带它(老客户端自带则原样用)。
- **harvest 落库**([comparison_record](../../database/comparison_record.md)):首帧(mint 时)建 `running` 行 → **done 帧** `harvest_done` 写 `success`/`failed` + 派生 `best_*`/`saved_amount_cents`。写库 best-effort(threadpool 独立 session),失败不连累透传。
- **软鉴权**:新客户端带 Bearer → 记录绑 `user_id`;老客户端/匿名 → `user_id` 暂空,由其后续 `POST /compare/record` 上报补(灰度期两条写路径按 `trace_id` reconcile,success 不降级)。
- 邀请发奖**不在这里**:#113 起口径为好友「比价并下单」,发放在 `POST /order/report`。

**相关配置**:
- `PRICEBOT_BASE_URL`（默认 `http://localhost:8000`;生产部署应与 pricebot-backend 同内网——比价一单 30~80 步、逐帧多一跳,走公网延迟会累积）
- `PRICEBOT_COMPARE_TIMEOUT_SEC`（默认 60s,price/step 每帧都是 LLM）
