强制 SYB 采购先真机遍历 PDD 规格再确定性/AI 匹配 #215

Open
opened 2026-09-04 18:41:20 +08:00 by ila · 2 comments
Owner

基本信息

  • 类型:需求
  • 所属 Epic:无
  • 所属 MVP / 版本:采购 MVP
  • 阶段:待验收

依赖与并行

  • 前置工单:#214
  • 是否允许与前置工单并行:否
  • 原因:两者都会修改 Android 采购规格面板探测/选择链路;本工单以 #214 已实现的可验证点击与容器滚动为基线,避免状态和动作语义冲突。

子项目影响

  • 交付单元:server、android、shared-docs
  • 是否跨子项目:是
  • 是否修改共享接口或契约:是;唯一事实来源:Wiki Android-Agent-API-Contract
  • 验证:Server 采购状态机/匹配单元测试、Android 采购执行单元测试、共享契约测试、Debug APK 构建;正式采购真机验证另行授权。

原始需求

  • 来源:用户对话
  • 提出时间:2026-09-04
  • 关键摘要:用户要求“现在强制每次采购”都先有界遍历 PDD 规格面板、收集颜色和尺码候选并回传服务端;服务端用 SYB 待采购规格先做标准化唯一匹配,不能唯一匹配时才调用 AI;AI 只能返回 PDD 原始候选;匹配成功后再次下发任务,由 Agent 精确选择。
  • Gitea 交互:当前会话未提供项目 Gitea MCP,按仓库规则回退 Gitea API;凭据仅从安全环境配置读取,未写入工单、代码或日志。

要解决什么

  • 当前代码事实:现有 SYB 采购优先复用已确认/已归档的 PDD 规格映射,只有初始规格未决或精确目标在页面不可见且服务端允许时才进入真机 spec_probe 慢路径;因此并非每次采购都以当次 PDD 页面候选重新决策。
  • 目标契约:每个新建的 SYB 订单采购任务都必须先进入只读规格探测阶段;在服务端接受并完成当次探测结果的确定性/AI 决策前,Agent 不得执行地址、创建订单等后续采购动作。
  • 假设:本单“每次采购”指 SYB 订单采购。备货 stock/direct_select 没有 SYB 待采购规格,不在本单扩展范围;如需同样强制探测,应单独确认其目标规格来源和失败语义。

做什么 / 不做什么

做

  1. 新创建的 SYB 采购任务无论是否已有长期规格映射,都先下发 spec_probe 阶段;长期映射只能作为审计/已有事实,不能跳过当次页面探测。
  2. Agent 使用既有 PDD 商品详情采集器在规格面板内有界遍历,收集当次 color、size 原始候选并回传;动作、耗时和滚动次数继续有上限。
  3. 服务端校验探测结果与 taskId、deviceId、attempt、任务规则快照和当前商品身份关联;目标要求存在但对应候选不完整时明确失败,不把不完整候选交给 AI 猜测。
  4. 服务端以任务冻结的 SYB 目标颜色/尺码与当次 PDD 原始候选先执行标准化唯一匹配;只有无法唯一确定时才调用配置的 AI Provider。
  5. AI 输出必须逐字属于当次 PDD 原始候选集合;集合外值、角色缺失、歧义、无结果、Provider 失败或输入漂移均不得进入采购执行。
  6. 决策成功后固化本任务的 mappedColor/mappedSize、候选指纹和决策来源,再进行第二次下发;Agent 只精确点击服务端固化值,不能本地猜测或选择相近值。
  7. 第二阶段若精确目标不存在、歧义或选中验证失败,任务明确失败;同一任务不得循环重新探测并反复调用 AI。
  8. 更新共享契约、业务规则和相应自动测试。

不做

  • 不改变 SYB 原始规格解析规则,不把“解析 SYB 规格”和“匹配 PDD 候选”合并成同一事实。
  • 不自动写回或覆盖虾皮商品的长期规格映射。
  • 不增加 OCR/VLM,不保存原始控件树或整屏截图。
  • 不放宽为相近、子串、前缀或编辑距离匹配。
  • 不修改地址策略、价格保护、数量、订单结果读取或支付边界。
  • 永久不执行付款。
  • 本工单实施和自动测试阶段不创建真实订单;真机正式采购需再次取得人工授权。

已确认方案

状态流程:

新建 SYB 采购任务 → spec_probe 待领取 → Agent 只读遍历并回传候选 → 服务端校验 → 标准化唯一匹配 → 必要时 AI 封闭候选匹配 → 固化任务级执行规格 → 第二次领取/下发 → Agent 精确选择 → 继续既有核价、地址及创建订单门禁

关键安全约束:

  • 第一阶段任务载荷只能执行只读规格探测,不包含或不得执行地址、创建订单动作。
  • 一次任务只接受一次有效探测决策;结果以幂等请求和候选指纹防止重复/漂移。
  • 第二阶段只消费固化的精确规格;失败不自动回到第一阶段。
  • 现有设备租约和本地互斥锁保持不变,一台设备同一时刻仍只执行一个任务。

预计修改范围:

  • server/app/goauto/purchase/:创建、领取/载荷、探测结果处理、状态机与测试。
  • server/app/goauto/aimatching/:复用确定性优先、AI 封闭候选校验,按需补测试,不放宽 Provider 输出。
  • android/app/src/main/java/cn/ilapage/goauto/agent/:强制探测阶段执行及第二阶段精确选择契约。
  • Wiki Android-Agent-API-Contract、Business-Rules-and-Glossary 及其本地只读镜像。
  • 初步判断可复用现有任务字段与阶段,不预设数据库迁移;若实施核对发现必须迁移,先更新本工单方案并再次取得迁移授权。

需求变化记录

日期 变化内容 原因 用户确认
2026-09-04 从“仅未决/页面目标不可见时探测”改为“每个 SYB 采购任务先真机探测” 用户明确要求使用当次 PDD 页面候选重新决策 是

设计与原型门禁

  • 修改类型:非 UI;采购状态、API 与流程设计变化
  • 所需设计证据:本工单中的状态流程、契约和安全约束
  • 状态:已确认文字需求;实施仍受高风险人工授权门禁约束
  • 确认人、时间和范围:用户,2026-09-04;覆盖 SYB 采购的探测、匹配与第二次下发
  • 无需 UI 原型:不新增或改变 Admin/Agent 页面结构与交互。

文档影响

  • 不影响长期文档
  • 更新业务规则与术语 Wiki
  • 更新 API 契约 Wiki

需要记录强制双阶段采购、当次候选来源、确定性优先、AI 封闭候选、一次探测及失败收敛规则。按 Wiki-first 在线更新、回读 revision,再执行一次 sync 和一次 sync --check。

交付文档影响

  • 无额外交付文档;长期契约由上述 Wiki 页面维护。

任务记录与可选快照

  • 单次任务事实来源:本 Gitea 工单正文与评论
  • 默认不创建任务快照

验收标准

  • 新建 SYB 采购任务即使已有确认映射,也只先下发只读 spec_probe,不得直接进入正式采购阶段。
  • Agent 有界遍历并回传当次颜色、尺码原始候选;候选与 taskId、deviceId、attempt 和 ruleSnapshot 可核对。
  • 服务端仅以任务冻结的 SYB 目标与当次候选先做标准化唯一匹配,无法唯一确定时才调用 AI。
  • AI 返回值严格属于当次原始候选;集合外、缺失、歧义、无结果、Provider 失败或输入漂移均 fail-closed。
  • 决策成功后任务第二次下发精确 mappedColor/mappedSize,Agent 不猜测、不选相近候选。
  • 同一任务不循环重复探测;第二阶段精确选择失败保留真实失败阶段。
  • 第一阶段绝不修改地址、创建订单或触发支付;永久禁止支付。
  • Server/Android/契约测试与 APK 构建通过。
  • Wiki 在线页面更新并回读 revision,本地镜像完成一次 sync 和一次 sync --check。
  • 代码已提交、推送并回写提交哈希;工单停在待验收,不在用户验收前关闭。

验证方式

  • Server:运行采购创建、领取、结果回传、确定性/AI 匹配与重复探测相关单元测试。
  • Android:运行采购执行、规格探测与精确选择 JVM 单元测试。
  • 构建:Debug APK 构建及仓库受影响组件验证。
  • 安全检查:测试第一阶段载荷不能触发地址、创建订单、订单详情或支付动作。
  • 真机:先使用不含地址和创建订单动作的 rehearsal 验证双阶段;任何 live 正式采购、地址修改或创建待付款订单均需另行授权。

风险和回退

  • 风险:每单至少增加一次真机规格遍历和一次服务端往返,采购耗时、PDD 页面操作次数和失败概率会上升;AI 调用量也可能增加。
  • 风险:页面候选可能因滚动上限或控件树可见性而不完整,必须明确失败,不能回退到历史映射绕过当次探测。
  • 风险:这是创建订单前置状态机和共享契约变化,生产实现、迁移(如发现需要)、真机 live 验证和发布均分别受人工确认门禁约束。
  • 回退:恢复“已有精确映射直接执行、仅未决时探测”的旧调度策略;不改写既有任务历史和决策审计记录。
## 基本信息 - 类型:需求 - 所属 Epic:无 - 所属 MVP / 版本:采购 MVP - 阶段:待验收 ## 依赖与并行 - 前置工单:#214 - 是否允许与前置工单并行:否 - 原因:两者都会修改 Android 采购规格面板探测/选择链路;本工单以 #214 已实现的可验证点击与容器滚动为基线,避免状态和动作语义冲突。 ## 子项目影响 - 交付单元:server、android、shared-docs - 是否跨子项目:是 - 是否修改共享接口或契约:是;唯一事实来源:Wiki `Android-Agent-API-Contract` - 验证:Server 采购状态机/匹配单元测试、Android 采购执行单元测试、共享契约测试、Debug APK 构建;正式采购真机验证另行授权。 ## 原始需求 - 来源:用户对话 - 提出时间:2026-09-04 - 关键摘要:用户要求“现在强制每次采购”都先有界遍历 PDD 规格面板、收集颜色和尺码候选并回传服务端;服务端用 SYB 待采购规格先做标准化唯一匹配,不能唯一匹配时才调用 AI;AI 只能返回 PDD 原始候选;匹配成功后再次下发任务,由 Agent 精确选择。 - Gitea 交互:当前会话未提供项目 Gitea MCP,按仓库规则回退 Gitea API;凭据仅从安全环境配置读取,未写入工单、代码或日志。 ## 要解决什么 - 当前代码事实:现有 SYB 采购优先复用已确认/已归档的 PDD 规格映射,只有初始规格未决或精确目标在页面不可见且服务端允许时才进入真机 `spec_probe` 慢路径;因此并非每次采购都以当次 PDD 页面候选重新决策。 - 目标契约:每个新建的 SYB 订单采购任务都必须先进入只读规格探测阶段;在服务端接受并完成当次探测结果的确定性/AI 决策前,Agent 不得执行地址、创建订单等后续采购动作。 - 假设:本单“每次采购”指 SYB 订单采购。备货 `stock/direct_select` 没有 SYB 待采购规格,不在本单扩展范围;如需同样强制探测,应单独确认其目标规格来源和失败语义。 ## 做什么 / 不做什么 ### 做 1. 新创建的 SYB 采购任务无论是否已有长期规格映射,都先下发 `spec_probe` 阶段;长期映射只能作为审计/已有事实,不能跳过当次页面探测。 2. Agent 使用既有 PDD 商品详情采集器在规格面板内有界遍历,收集当次 `color`、`size` 原始候选并回传;动作、耗时和滚动次数继续有上限。 3. 服务端校验探测结果与 taskId、deviceId、attempt、任务规则快照和当前商品身份关联;目标要求存在但对应候选不完整时明确失败,不把不完整候选交给 AI 猜测。 4. 服务端以任务冻结的 SYB 目标颜色/尺码与当次 PDD 原始候选先执行标准化唯一匹配;只有无法唯一确定时才调用配置的 AI Provider。 5. AI 输出必须逐字属于当次 PDD 原始候选集合;集合外值、角色缺失、歧义、无结果、Provider 失败或输入漂移均不得进入采购执行。 6. 决策成功后固化本任务的 mappedColor/mappedSize、候选指纹和决策来源,再进行第二次下发;Agent 只精确点击服务端固化值,不能本地猜测或选择相近值。 7. 第二阶段若精确目标不存在、歧义或选中验证失败,任务明确失败;同一任务不得循环重新探测并反复调用 AI。 8. 更新共享契约、业务规则和相应自动测试。 ### 不做 - 不改变 SYB 原始规格解析规则,不把“解析 SYB 规格”和“匹配 PDD 候选”合并成同一事实。 - 不自动写回或覆盖虾皮商品的长期规格映射。 - 不增加 OCR/VLM,不保存原始控件树或整屏截图。 - 不放宽为相近、子串、前缀或编辑距离匹配。 - 不修改地址策略、价格保护、数量、订单结果读取或支付边界。 - 永久不执行付款。 - 本工单实施和自动测试阶段不创建真实订单;真机正式采购需再次取得人工授权。 ## 已确认方案 状态流程: `新建 SYB 采购任务 → spec_probe 待领取 → Agent 只读遍历并回传候选 → 服务端校验 → 标准化唯一匹配 → 必要时 AI 封闭候选匹配 → 固化任务级执行规格 → 第二次领取/下发 → Agent 精确选择 → 继续既有核价、地址及创建订单门禁` 关键安全约束: - 第一阶段任务载荷只能执行只读规格探测,不包含或不得执行地址、创建订单动作。 - 一次任务只接受一次有效探测决策;结果以幂等请求和候选指纹防止重复/漂移。 - 第二阶段只消费固化的精确规格;失败不自动回到第一阶段。 - 现有设备租约和本地互斥锁保持不变,一台设备同一时刻仍只执行一个任务。 预计修改范围: - `server/app/goauto/purchase/`:创建、领取/载荷、探测结果处理、状态机与测试。 - `server/app/goauto/aimatching/`:复用确定性优先、AI 封闭候选校验,按需补测试,不放宽 Provider 输出。 - `android/app/src/main/java/cn/ilapage/goauto/agent/`:强制探测阶段执行及第二阶段精确选择契约。 - Wiki `Android-Agent-API-Contract`、`Business-Rules-and-Glossary` 及其本地只读镜像。 - 初步判断可复用现有任务字段与阶段,不预设数据库迁移;若实施核对发现必须迁移,先更新本工单方案并再次取得迁移授权。 ## 需求变化记录 | 日期 | 变化内容 | 原因 | 用户确认 | |---|---|---|---| | 2026-09-04 | 从“仅未决/页面目标不可见时探测”改为“每个 SYB 采购任务先真机探测” | 用户明确要求使用当次 PDD 页面候选重新决策 | 是 | ## 设计与原型门禁 - 修改类型:非 UI;采购状态、API 与流程设计变化 - 所需设计证据:本工单中的状态流程、契约和安全约束 - 状态:已确认文字需求;实施仍受高风险人工授权门禁约束 - 确认人、时间和范围:用户,2026-09-04;覆盖 SYB 采购的探测、匹配与第二次下发 - 无需 UI 原型:不新增或改变 Admin/Agent 页面结构与交互。 ## 文档影响 - [ ] 不影响长期文档 - [x] 更新业务规则与术语 Wiki - [x] 更新 API 契约 Wiki 需要记录强制双阶段采购、当次候选来源、确定性优先、AI 封闭候选、一次探测及失败收敛规则。按 Wiki-first 在线更新、回读 revision,再执行一次 `sync` 和一次 `sync --check`。 ## 交付文档影响 - [x] 无额外交付文档;长期契约由上述 Wiki 页面维护。 ## 任务记录与可选快照 - 单次任务事实来源:本 Gitea 工单正文与评论 - [x] 默认不创建任务快照 ## 验收标准 - [ ] 新建 SYB 采购任务即使已有确认映射,也只先下发只读 `spec_probe`,不得直接进入正式采购阶段。 - [ ] Agent 有界遍历并回传当次颜色、尺码原始候选;候选与 taskId、deviceId、attempt 和 ruleSnapshot 可核对。 - [ ] 服务端仅以任务冻结的 SYB 目标与当次候选先做标准化唯一匹配,无法唯一确定时才调用 AI。 - [ ] AI 返回值严格属于当次原始候选;集合外、缺失、歧义、无结果、Provider 失败或输入漂移均 fail-closed。 - [ ] 决策成功后任务第二次下发精确 mappedColor/mappedSize,Agent 不猜测、不选相近候选。 - [ ] 同一任务不循环重复探测;第二阶段精确选择失败保留真实失败阶段。 - [ ] 第一阶段绝不修改地址、创建订单或触发支付;永久禁止支付。 - [ ] Server/Android/契约测试与 APK 构建通过。 - [ ] Wiki 在线页面更新并回读 revision,本地镜像完成一次 sync 和一次 sync --check。 - [ ] 代码已提交、推送并回写提交哈希;工单停在待验收,不在用户验收前关闭。 ## 验证方式 - Server:运行采购创建、领取、结果回传、确定性/AI 匹配与重复探测相关单元测试。 - Android:运行采购执行、规格探测与精确选择 JVM 单元测试。 - 构建:Debug APK 构建及仓库受影响组件验证。 - 安全检查:测试第一阶段载荷不能触发地址、创建订单、订单详情或支付动作。 - 真机:先使用不含地址和创建订单动作的 rehearsal 验证双阶段;任何 live 正式采购、地址修改或创建待付款订单均需另行授权。 ## 风险和回退 - 风险:每单至少增加一次真机规格遍历和一次服务端往返,采购耗时、PDD 页面操作次数和失败概率会上升;AI 调用量也可能增加。 - 风险:页面候选可能因滚动上限或控件树可见性而不完整,必须明确失败,不能回退到历史映射绕过当次探测。 - 风险:这是创建订单前置状态机和共享契约变化,生产实现、迁移(如发现需要)、真机 live 验证和发布均分别受人工确认门禁约束。 - 回退:恢复“已有精确映射直接执行、仅未决时探测”的旧调度策略;不改写既有任务历史和决策审计记录。
Author
Owner

2026-09-04 已收到用户“授权执行工单 #215”。开始实施。

基线:683aa9c,分支 feat/214-verified-purchase-actions(#215 依赖 #214 的 Android 可验证规格动作)。当前工作区存在与本单无关的用户改动,将保留且不纳入本单提交。

安全边界:本轮只做代码、自动测试、Debug 构建和只读契约验证;不运行真机 live 采购,不修改地址,不创建真实订单,不执行付款。若发现需要数据库迁移,将停止并另行申请迁移授权。

2026-09-04 已收到用户“授权执行工单 #215”。开始实施。 基线:`683aa9c`,分支 `feat/214-verified-purchase-actions`(#215 依赖 #214 的 Android 可验证规格动作)。当前工作区存在与本单无关的用户改动,将保留且不纳入本单提交。 安全边界:本轮只做代码、自动测试、Debug 构建和只读契约验证;不运行真机 live 采购,不修改地址,不创建真实订单,不执行付款。若发现需要数据库迁移,将停止并另行申请迁移授权。
Author
Owner

实施完成,待验收

已按 2026-09-04 用户授权完成 #215,未执行真机 live 采购、地址修改、真实订单创建或付款。

实现

  • 新建 SYB 采购任务不再复用长期规格映射或 PDD 档案候选直接进入采购,任务级执行规格固定以 unresolved / 空映射开始。
  • 不再为新任务创建档案异步 purchase_spec_match_work_item,首次领取后 start 固定进入 spec_probe。
  • 批量预检、批量创建、失败重试和替换后继续采购不再要求先保存长期规格映射;仍保留商品关联、PDD active、价格、规则、设备、订单与不可逆安全门禁。
  • 首趟回传当次 PDD 颜色/尺码候选后,服务端先做标准化唯一匹配,必要时才调用 AI;在采购生命周期层再次校验来源及返回值逐字属于当次对应候选,集合外结果 fail-closed。
  • 决策成功后固化任务级精确规格并进行第二次派发;同一任务重复探测继续以 PURCHASE_SPEC_REPROBE_REJECTED 收敛。
  • 服务端新增硬门禁:spec_probe attempt 不能调用 order-submit-started。
  • Android 生产链路无需新增字段或动作;既有 phase=spec_probe 已只执行只读规格探测。本单补充回归测试,证明即使载荷含历史映射也不会执行地址、订单或支付动作。
  • 无数据库迁移。

验证

通过:

  • go test -count=1 ./app/goauto/purchase ./app/goauto/aimatching ./app/goauto/purchasecontract ./app/goauto/purchaserule
  • Server go build
  • android\gradlew.bat testDebugUnitTest assembleDebug
  • Android 定向 PurchaseRehearsalExecutorTest
  • python dev_scripts/harness.py check --strict
  • git diff --check
  • Wiki 一次 sync 与一次 sync --check(检查时临时隔离并随后逐字恢复用户已有的 docs/12-syb-erp-interface.md 未提交改动)

全量 go test ./... 中采购及其他 Server 包通过,只有无关 apprelease 的 TestParseBuiltAgentAPKWhenAvailable 失败:工作区 Debug APK 为 0.9.39 (52),该测试仍使用旧固定版本预期;未混入本单修复。

Wiki

  • Business-Rules-and-Glossary revision 069248c1466d54273900a4c87d1285436f7d50f9
  • Android-Agent-API-Contract revision a022259ba39db7588eaa3b6579c799e2eb6a6f9e

Git

  • 分支:feat/215-mandatory-live-spec-probe
  • 提交:c09ddc8 feat(purchase): 强制真机探测规格后匹配 (#215)
  • 已推送:origin/feat/215-mandatory-live-spec-probe

未验证

  • 未做真机 rehearsal 和 live 采购;live 会触及地址与创建待付款订单,必须再次取得人工授权。
  • 未发布到本地或线上常驻服务。

工单保持 open / 待验收,等待用户验收。

## 实施完成,待验收 已按 2026-09-04 用户授权完成 #215,未执行真机 live 采购、地址修改、真实订单创建或付款。 ### 实现 - 新建 SYB 采购任务不再复用长期规格映射或 PDD 档案候选直接进入采购,任务级执行规格固定以 `unresolved` / 空映射开始。 - 不再为新任务创建档案异步 `purchase_spec_match_work_item`,首次领取后 `start` 固定进入 `spec_probe`。 - 批量预检、批量创建、失败重试和替换后继续采购不再要求先保存长期规格映射;仍保留商品关联、PDD active、价格、规则、设备、订单与不可逆安全门禁。 - 首趟回传当次 PDD 颜色/尺码候选后,服务端先做标准化唯一匹配,必要时才调用 AI;在采购生命周期层再次校验来源及返回值逐字属于当次对应候选,集合外结果 fail-closed。 - 决策成功后固化任务级精确规格并进行第二次派发;同一任务重复探测继续以 `PURCHASE_SPEC_REPROBE_REJECTED` 收敛。 - 服务端新增硬门禁:`spec_probe` attempt 不能调用 `order-submit-started`。 - Android 生产链路无需新增字段或动作;既有 `phase=spec_probe` 已只执行只读规格探测。本单补充回归测试,证明即使载荷含历史映射也不会执行地址、订单或支付动作。 - 无数据库迁移。 ### 验证 通过: - `go test -count=1 ./app/goauto/purchase ./app/goauto/aimatching ./app/goauto/purchasecontract ./app/goauto/purchaserule` - Server `go build` - `android\gradlew.bat testDebugUnitTest assembleDebug` - Android 定向 `PurchaseRehearsalExecutorTest` - `python dev_scripts/harness.py check --strict` - `git diff --check` - Wiki 一次 `sync` 与一次 `sync --check`(检查时临时隔离并随后逐字恢复用户已有的 `docs/12-syb-erp-interface.md` 未提交改动) 全量 `go test ./...` 中采购及其他 Server 包通过,只有无关 `apprelease` 的 `TestParseBuiltAgentAPKWhenAvailable` 失败:工作区 Debug APK 为 `0.9.39 (52)`,该测试仍使用旧固定版本预期;未混入本单修复。 ### Wiki - `Business-Rules-and-Glossary` revision `069248c1466d54273900a4c87d1285436f7d50f9` - `Android-Agent-API-Contract` revision `a022259ba39db7588eaa3b6579c799e2eb6a6f9e` ### Git - 分支:`feat/215-mandatory-live-spec-probe` - 提交:`c09ddc8 feat(purchase): 强制真机探测规格后匹配 (#215)` - 已推送:`origin/feat/215-mandatory-live-spec-probe` ### 未验证 - 未做真机 rehearsal 和 live 采购;live 会触及地址与创建待付款订单,必须再次取得人工授权。 - 未发布到本地或线上常驻服务。 工单保持 open / 待验收,等待用户验收。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#215