Files
cmroubao/docs/tasks/T-104.md
T

110 lines
5.9 KiB
Markdown
Raw Normal View History

---
id: T-104
title: 接入候选评估并停在人工确认点
phase: 1
deps:
- T-102
- T-103
status: DONE
created: 2026-07-25
context_ref: 32d5310
work_branch: main
write_paths:
- android-buyer/app/src/main/java/com/roubao/autopilot/MainActivity.kt
- android-buyer/app/src/main/java/com/roubao/autopilot/accessibility/**
- android-buyer/app/src/main/java/com/roubao/autopilot/pinduoduo/**
- android-buyer/app/src/main/java/com/roubao/autopilot/ui/screens/SearchProbeScreen.kt
- android-buyer/app/src/main/java/com/roubao/autopilot/vlm/**
- android-buyer/app/src/test/java/com/roubao/autopilot/pinduoduo/**
- android-buyer/app/src/test/java/com/roubao/autopilot/vlm/**
- docs/**
- progress.md
---
## 问题 / 背景
T-102 已能有界采集最多 5 份匿名候选截图证据,T-103 已能从私有任务得到严格的结构化
需求,但两者尚未使用同一搜索词连接,候选也没有匹配项、缺失项和拒绝原因。T-104
只完成候选建议和人员确认闭环,不提交订单、不进入支付。
## 方案
1. 需求提取成功后,候选探针使用该提取结果的搜索词;固定脱敏词仍保留给 T-101/T-102
独立回归。
2. 只有搜索词与当前需求一致且 workflow 成功的候选证据可以评估。
3. 受控 evidence source 按内存中的候选元数据读取匿名 PNG,复核数量、文件名、路径、
字节数、PNG 尺寸和 SHA-256;VLM adapter 不自行遍历 cache。
4. 每次用户操作按 ordinal 串行评估,单个候选最多调用一次、全批最多 5 次;任一网络
失败或无效输出都会停止后续付费调用。
5. 本地代码从有效评估中稳定产生建议项;预算缺失、低分、不确定或模型输出无效时保持
人工处理。无论模型输出如何,都不能产生页面动作或订单授权。
6. UI 展示匹配项、缺失项、拒绝原因和建议项,并停在人工确认点;人员只能标记候选
可用或拒绝本次候选,结果始终记录 `order_submitted=false`。
## 验收要点
- [x] 候选搜索使用当前结构化需求的搜索词,旧搜索结果不能冒充当前任务证据。
- [x] 最多 5 份候选 PNG 经受控边界验证后才进入评估 gateway。
- [x] 模型请求不含订单号、店铺名、本机路径、数量或支付信息。
- [x] 严格 schema 输出每个候选的判断、分数、匹配项、缺失项和拒绝原因。
- [x] 缺候选、ordinal 不一致、额外字段、动作语义和证据篡改均安全失败或转人工。
- [x] UI 明确停在人工确认,不包含提交订单或支付动作。
- [x] Fake gateway、证据读取、动态搜索和人工确认状态均有自动化测试。
- [x] `lintDebug test assembleDebug` 通过,默认 APK 不含私有 fixture。
- [x] 无真实模型凭证时只用本机 mock 验证集成,不宣称真实匹配质量。
## 执行记录
### 2026-07-25:任务开始
- 基于 T-103 提交 `32d5310` 开始。
- 当前外部 blocker 仍是真实 VLM 供应商、凭证、费用、数据留存和模型效果;先完成
provider-neutral 契约、Fake 测试和本机 mock 集成。
### 2026-07-25:实现
- 动态搜索使用当前 `RequirementExtraction.searchQuery`,同时绑定完整需求快照、
搜索词、成功 workflow 和本次候选 metadata;任一不一致都拒绝评估。
- `CandidateEvidenceSource` 只按内存 allowlist 读取 `candidate-01.png` 等固定匿名
文件,复核规范路径、8 MiB 单图/32 MiB 总量、PNG/IHDR、尺寸和 SHA-256。
- `CandidateEvaluator` 按 ordinal 串行调用,单候选一次、全批最多 5 次;无效输出、
provider 失败或取消立即停止后续调用,无效批次不保留先前自动建议。
- 严格解析候选 ordinal、判断、分数、匹配项、缺失项、拒绝原因和置信度;拒绝额外
字段、数字字符串、坐标/动作/提交/支付语义,以及无预算时的价格匹配声明。
- 推荐候选由本地按分数、置信度和 ordinal 稳定产生;人工接受必须对应实际存在的
`REVIEW` 建议项,批次和 UI 均固定 `order_submitted=false`。
- UI 展示每个候选的评估理由、警告和人工操作,只提供“标记建议候选可用”和
“拒绝本次候选”,没有提交订单或支付控件。
### 2026-07-25:自动化验证
- 执行
`.\gradlew.bat :app:lintDebug test assembleDebug --no-daemon`,构建与 lint 通过。
- App Debug/Release、task contract 和导入器共 26 份报告、166 次测试,0 failure、
0 error、0 skipped。
- 覆盖动态搜索、其他关键词结果页、受控证据路径/大小/PNG/尺寸/哈希、每候选调用
次数与停止规则、严格 schema、隐私字段、确定性推荐、人工确认和订单未提交状态。
- 不带 `probeFixturesDir` 重建默认 Debug APK,`assets/probe-fixtures/` 条目为 0。
### 2026-07-25:真机 smoke
- 在 OnePlus PKG110、Android 16/API 36、拼多多 8.17.0 上,用私有 fixture 完成
动态搜索和 5/5 候选证据采集。
- 一次性本机 OpenAI 兼容 mock 精确收到 5 次 POST,ordinal 为 1 至 5,每次只有
一张 JPEG data URL;订单、店铺、本机路径和数量字段命中均为 false。
- 严格响应进入“等待人工确认”,5 个候选均可见;点击“标记建议候选可用”后显示
候选已由人员标记可用且订单未提交,页面没有提交或支付按钮。
- 候选流程后的 logcat 中私有 sentinel、Base64、原始 mock 响应及 schema/prompt
命中均为 0;设备 provider 已恢复,ADB reverse 已移除。
### 未验证项
- 未使用真实远程 VLM 凭证,不宣称真实商品匹配质量、成本或供应商可用性。
- 当前证据是整页截图,尚无确定性商品标题和价格采集;第一层预算为空,因此任何
价格或预算匹配都转人工。
### 后续
- T-201 建立 Go-Gin、SQLite 和迁移骨架。
- T-202 生成并确认 P0 Web/App 低保真原型。