# 核销表 · 第2环 竞品标杆分析（标杆8特征）

> 90分级验收（孙总方法论·硬门禁）。已吸收独立交叉验证修正（⚠️）。本环是本轮**补全的缺失引擎环**。

## 模块目标
①用户截图/手填竞品爆款 → 提取标杆8特征(features_json) ②标杆可在任务里被选中(benchmark_ids) ③选中的标杆特征**真注入文案生成 prompt**(不能只存不用) ④分析结果落库可复用。

## 🔴 迁移版本号统一（防三环撞车 008）
- 008 = brand_keyword（第5环）
- **009 = features_json + analyze_status（本环）**
- 010 = fission_tasks 表（第11环）
- **011 = benchmark_ids(task) + source_fission_id（本环S12 + 第11环合并）**

## Ralph 修改步骤

| # | 改什么 | 落点 |
|---|--------|------|
| S1 | 迁移 009：benchmark 表加 `features_json TEXT NULL` + `analyze_status VARCHAR(20) DEFAULT 'pending'` | alembic versions/009_*.py |
| S2 | ⚠️行号修正:benchmark ORM 在 created_at(line 73)后插 features_json/analyze_status(非68-79) | models/benchmark.py:73 |
| S3 | benchmark_analyzer.py 新建(≤120行):入参截图URL/手填文本，调 chat_complete 出8特征 dict，走 MODEL_TEXT(claude-opus-4-8) | services/benchmark_analyzer.py(新) |
| S4 | 8特征 prompt 模板新建：输出严格 JSON(8个 key)，含 few-shot；温度0.3 | prompts/benchmark_features.py(新) |
| S5 | POST /benchmarks/{id}/analyze：触发分析，写 features_json，analyze_status=done/failed | benchmarks.py |
| S6 | analyze 异步:丢 Celery generation 队列(同步会超 60s 网关);analyze_status=running→done | tasks/benchmark_task.py(新) |
| S7 | BenchmarkSelector.tsx(底座 S5 已建)展示8特征 chips + analyze_status 角标 | BenchmarkSelector.tsx |
| S8 | dto.benchmark.ts 加 features_json?:Record<string,string> + analyze_status | dto.benchmark.ts |
| S9 | 提取失败兜底:JSON parse 失败 retry 1次仍失败→analyze_status=failed,前端显"重新分析" | benchmark_analyzer.py |
| S10 | 8特征注入文案 prompt:text_variants.py 组 prompt 处拼入选中标杆 features | text_variants.py(组prompt处) |
| **S11** | ⚠️构造校验:analyze 输出必须8个 key 齐(缺 key→failed),防模型偷工 | benchmark_analyzer.py |
| **S12a** | ⚠️拆分:迁移011 task 表加 `benchmark_ids TEXT NULL`(JSON list)；task.py ORM 加字段；task_service.py:60-73 构造任务时补传 benchmark_ids | 011_*.py + task.py + task_service.py:60-73 |
| **S12b** | ⚠️拆分:pipeline 读取 task.benchmark_ids → 查 features_json → 注入(S10 的数据来源接通) | pipeline_io.py + text_variants.py |

## 验收清单（做完一个勾一个）

- [ ] **A1**〔auto〕迁移009:`alembic upgrade head` 成功，`DESC benchmark` 含 features_json/analyze_status。
- [ ] **A2**〔auto〕analyze 接口:POST /benchmarks/{id}/analyze → 202/200，analyze_status 转 running。
- [ ] **A3**〔auto〕8特征产出:分析完 features_json 是 dict 且**恰好8个 key**(非空、非 null、key 名与北哥定义一致)。
- [ ] **A4**〔auto〕走最强档:抓 chat_complete 请求体 model==claude-opus-4-8(非 sonnet)。
- [ ] **A5**〔auto〕异步不超时:analyze 触发后接口 <2s 返回(非阻塞等模型)。
- [ ] **A6**〔auto〕失败兜底:喂坏输入(乱码截图)→analyze_status=failed(非500/非永久 running)。
- [ ] **A7**〔human〕前端8特征:选标杆 → 卡片显8个特征 chip + 状态角标(分析中/已完成/失败)。
- [ ] **A8**〔human〕重新分析:failed 标杆有"重新分析"按钮，点后重跑。
- [ ] **A9**〔auto〕注入文案:选中标杆生文案，抓文案 prompt 请求体**含该标杆 features 文本**(grep 特征关键词命中)。
- [ ] **A10**〔auto〕不选不注入:不选标杆生文案，prompt **不含** benchmark features 段(反向断言，防硬编码常驻)。
- [ ] **A11**〔human〕复用:同标杆第二个任务直接读 features_json(不重新调模型，analyze_status 已 done)。
- [ ] **A12**〔auto〕⚠️审计补·最高风险:benchmark_ids **真持久化**——建任务带 benchmark_ids=[1,2]→ `SELECT benchmark_ids FROM task WHERE id=?` 取回==[1,2]。(防链路断:S10/S9 仍可能因 benchmark_ids 没存而 A9/A11 假过)。

## 待北哥定义（🔴阻断 S4/A3，标杆8维度必须先定义）
- **标杆8特征的名称+定义**(如:钩子类型/痛点切入/卖点呈现/信任背书/场景/情绪/CTA/排版风格？)——北哥未给前 S4 prompt 用占位8维，A3 key 名校验放宽到"恰好8个 key"不校验具体名。
- 截图提取:截图是先 OCR 还是直接喂多模态(gpt 多模态 vs claude vision)？本期默认手填文本优先，截图 OCR 留接口。
