# launch_confirm_sample — 启动确认窗 agent 兜底样本

> 模型 `app/models/launch_confirm_sample.py`(`LaunchConfirmSample`) · 仓库 `app/repositories/launch_confirm_sample.py`(`insert_sample`) · 接口 `POST /internal/launch-confirm-sample`(pricebot→app-server,`app/api/internal/launch_confirm.py`,`X-Internal-Secret` 校验) · [← 索引](./README.md) · [总览](./OVERVIEW.md)

pricebot 的 `launch_confirm_agent` 每次「静态 PROFILES 没认出、靠 LLM 兜底放行」一个跨 App 启动确认窗(繁体 / 英文 / 小语种 / ROM 改版的「想要打开 XX」弹窗)时,把完整样本 server→server 落这里。研发定期**人工**把 `exec_success=true` 的样本沉淀进 pricebot 的 `launch_confirm.PROFILES`(静态快路径),让以后同款窗不必再调 LLM(回到快路径)。

> **不是给客户端的接口**:与登录无关、不鉴权,靠共享密钥头 `X-Internal-Secret`(== `settings.INTERNAL_API_SECRET`)校验,未配置则 503。

## 用在哪 / 增删改查
- **C(插入)**:`insert_sample`(`POST /internal/launch-confirm-sample`)。**都上报、不去重**(by design):同一种窗多台机器上报多条,研发按 `host_package`/`system_locale` 聚合后人工筛。大字段截断到列长上限(繁体长标题等),空串入库为 None。
- **R / U / D**:**无**(研发查库靠 SQL 直接看 + 人工沉淀,不经本服务接口)。

## 字段
| 列 | 类型 | 约束 / 默认 | 说明(取值 / join) |
|---|---|---|---|
| `id` | Integer | PK, autoincrement | |
| `created_at` | DateTime(tz) | server_default now(), index | 上报时间 |
| `trace_id` | String(64) | index, nullable | pricebot 侧 trace_id:回指原始 trace,可去 `price.shaguabijia.com` 查完整上下文 |
| `device_id` | String(64) | index, nullable | 上报设备 |
| `host_package` | String(128) | index, nullable | 弹窗宿主包(= 触发判据,也是研发沉淀进 `PROFILES.host_packages` 的键)。**按它聚合人工筛** |
| `target_app` | String(128) | nullable | 被打开的目标 App 包名(标题里「想要打开 X」的 X 是变量,据此把它从 sign 里挖空) |
| `system_locale` | String(32) | index, nullable | 系统语言地区(`zh-TW`/`en-US`…)—— 多语言问题的核心维度。⚠️ 前端 `AgentStepRequest` 暂未上报设备信息 → **现恒 None**,待前端加 `device_info` 字段后回填 |
| `exec_success` | Boolean | NOT NULL, default false | 这次兜底是否成功放行(弹窗消失=true;放弃 / LLM 没认出=false)。**研发只沉淀 true 的** |
| `dialog_title` | String(256) | nullable | 弹窗标题全文(研发据此提 `launch_sign`),如「『傻瓜比价』想要開啟『京東』」 |
| `payload` | JSON(PG: JSONB) | nullable | 完整样本大 JSON:`{is_launch_confirm, llm_model, llm_reason, plan, dialog_tree, device_info:{screen,locale,brand,model,android_version,rom_version}}`。加字段不必迁移 schema |

## 关系 / Join Key
- 无外键。`trace_id` 软指 pricebot trace(回指排查),`device_id` 软指设备;均不与本服务其它表 join。

## 索引与约束
- PK `id`;index `created_at`、`trace_id`、`device_id`、`host_package`、`system_locale`。
- **无唯一约束**(by design 不去重,见上)。

## 注意
- **PG 上 `payload` 用 JSONB**(可建 GIN 索引),SQLite(本地/测试)退化为通用 `JSON`(同 `price_observation`、`comparison_record`)。
- **为什么大字段塞 `payload` 而非拆列**:弹窗树快照 + LLM plan + 设备信息都是「研发偶尔人工看」的兜底数据,拆列会让每次扩样本字段都要迁移 schema;只把聚合/筛选要用的维度(`host_package`/`system_locale`/`exec_success`)提成结构化列建索引。
