修复 Android 采购规则 priceGuard 契约不兼容 #176

Open
opened 2026-08-31 17:21:17 +08:00 by ila · 2 comments
Owner

原始需求摘要

  • 来源:用户于 2026-08-31 报告最新 Agent 执行 CG44 失败,错误为“采购规则 包含未知字段: priceGuard”,并确认按分析建议建工单。
  • 目的:修复服务端合法采购规则快照被 Android Agent 误判为未知字段的问题,避免修复前无意义重试。
  • Gitea 交互回退:当前会话未提供项目 Gitea MCP,按仓库规则使用 Gitea API 创建工单;凭据仅从 gitea.env 读取,未写入工单或日志。

当前事实与根因

  • 代码基线:4343ab5,核验日期:2026-08-31。
  • CG44 为 live 采购任务,规则快照顶层包含合法 priceGuard={minRatio:0.2,maxRatio:2},同时包含 #174 的 probeSpecs.dimensionAliases。
  • 服务端 purchasecontract.RuleSnapshot 自 #146(56443c9)起支持并严格校验 priceGuard;Admin 当前规则也会保存该字段。
  • Android PurchaseRuleParser 的顶层字段白名单仍只有 schemaVersion、ruleType、requiredCapabilities、actions,因此在执行器和任何 PDD 动作之前返回 PURCHASE_RULE_INVALID。
  • CG44 attempt 65 从开始到失败约 37ms,未打开 PDD、未选择规格、未创建订单、未支付。修复前重试会稳定复现。

目标

  1. Android 能解析服务端已批准的可选 priceGuard。
  2. Android 对 priceGuard 保持与服务端一致的严格字段和范围校验,不能通过简单忽略未知内容放宽规则安全边界。
  3. 增加覆盖当前完整采购规则快照的跨端契约回归证据,防止服务端合法字段再次遗漏于 Agent。

非目标

  • 不改变服务端价格边界计算、任务状态机、重试权限或 Admin 页面。
  • 不修改 CG44 数据,不自动重试 CG44。
  • 不执行真机采购、创建订单或支付。
  • 不新增任意脚本或放宽未知字段拒绝策略。

前置依赖与并行性

  • 依赖 #146 的 priceGuard 服务端契约和 #174 的 dimensionAliases Agent 契约,二者代码均已在当前 main。
  • 可独立实施;CG44 必须等修复 APK 安装完成后再由用户单独授权重试。

实施方案

  1. 在 Android 采购规则契约中增加 PurchasePriceGuard(或等效严格解析结构)。
  2. 顶层仅新增允许字段 priceGuard;显式提供时必须是对象,只允许 minRatio、maxRatio。
  3. 与服务端保持一致:minRatio 为 0.1~1.0,maxRatio 为 1.0~3.0,最多 4 位小数,且 minRatio <= maxRatio;拒绝缺字段、非数值、NaN/Infinity、额外字段及越界值。
  4. Agent 不使用规则比例重新计算任务价格区间;执行仍以服务端任务字段 minUnitPriceCent / maxUnitPriceCent 为唯一价格边界。
  5. Android 自动测试加入同时包含 priceGuard、probeSpecs.dimensionAliases 和正式动作的当前完整规则快照;补充各类非法 priceGuard 拒绝测试。
  6. 增加可被服务端与 Android 双方验证的共享采购规则样例,或等效的双端一致性回归门禁;不得复制一份无人校验的静态示例冒充共享契约。

验收标准

  • 合法 priceGuard={minRatio:0.2,maxRatio:2} 的 CG44 同形规则快照可被 Android 解析。
  • 缺省 priceGuard 的旧任务快照继续兼容。
  • 未知顶层字段仍被拒绝。
  • 非对象、缺字段、额外字段、非数值、超过 4 位小数、越界及 minRatio > maxRatio 均被拒绝。
  • 当前完整正式采购规则的服务端与 Android 契约测试均通过。
  • Android 全量单元测试与 Debug APK 构建通过。
  • 不执行 CG44 重试或真机采购;如用户后续要求安装,安装前重新确认设备无活动采集/采购任务。

验证计划

  • go test ./app/goauto/purchasecontract ./app/goauto/purchase
  • android\gradlew.bat testDebugUnitTest
  • android\gradlew.bat assembleDebug
  • git diff --check
  • 只读核对 CG44 保持失败且未产生新 attempt。

风险与安全边界

  • 采购属于高风险域;本工单只修正规则解析和自动测试,不授权任务重试、真机采购、创建订单或支付。
  • 必须保持 Android fail-closed:只接受明确字段并逐项校验,不能整体忽略 priceGuard 或其他未知字段。
  • 安装 APK 属于独立设备变更,仅在用户后续明确要求且设备无活动任务时执行。

设计证据

  • 恢复既有契约行为的非 UI 缺陷,不涉及页面结构、交互或文案变化,无需新增原型。

子项目影响

  • Android:规则解析与自动测试。
  • Server:仅共享契约回归测试/样例(如方案采用),不改变运行行为。
  • Web、数据库、权限、并发、状态机:无变化。

文档影响

  • 无长期文档影响:现有 Wiki 已明确 priceGuard 合法范围和用途,本工单恢复 Android 与既有契约一致,不产生新 API、业务规则或运维事实,因此跳过 Wiki 更新与同步。
## 原始需求摘要 - 来源:用户于 2026-08-31 报告最新 Agent 执行 CG44 失败,错误为“采购规则 包含未知字段: priceGuard”,并确认按分析建议建工单。 - 目的:修复服务端合法采购规则快照被 Android Agent 误判为未知字段的问题,避免修复前无意义重试。 - Gitea 交互回退:当前会话未提供项目 Gitea MCP,按仓库规则使用 Gitea API 创建工单;凭据仅从 `gitea.env` 读取,未写入工单或日志。 ## 当前事实与根因 - 代码基线:`4343ab5`,核验日期:2026-08-31。 - CG44 为 `live` 采购任务,规则快照顶层包含合法 `priceGuard={minRatio:0.2,maxRatio:2}`,同时包含 #174 的 `probeSpecs.dimensionAliases`。 - 服务端 `purchasecontract.RuleSnapshot` 自 #146(`56443c9`)起支持并严格校验 `priceGuard`;Admin 当前规则也会保存该字段。 - Android `PurchaseRuleParser` 的顶层字段白名单仍只有 `schemaVersion`、`ruleType`、`requiredCapabilities`、`actions`,因此在执行器和任何 PDD 动作之前返回 `PURCHASE_RULE_INVALID`。 - CG44 attempt 65 从开始到失败约 37ms,未打开 PDD、未选择规格、未创建订单、未支付。修复前重试会稳定复现。 ## 目标 1. Android 能解析服务端已批准的可选 `priceGuard`。 2. Android 对 `priceGuard` 保持与服务端一致的严格字段和范围校验,不能通过简单忽略未知内容放宽规则安全边界。 3. 增加覆盖当前完整采购规则快照的跨端契约回归证据,防止服务端合法字段再次遗漏于 Agent。 ## 非目标 - 不改变服务端价格边界计算、任务状态机、重试权限或 Admin 页面。 - 不修改 CG44 数据,不自动重试 CG44。 - 不执行真机采购、创建订单或支付。 - 不新增任意脚本或放宽未知字段拒绝策略。 ## 前置依赖与并行性 - 依赖 #146 的 `priceGuard` 服务端契约和 #174 的 `dimensionAliases` Agent 契约,二者代码均已在当前 `main`。 - 可独立实施;CG44 必须等修复 APK 安装完成后再由用户单独授权重试。 ## 实施方案 1. 在 Android 采购规则契约中增加 `PurchasePriceGuard`(或等效严格解析结构)。 2. 顶层仅新增允许字段 `priceGuard`;显式提供时必须是对象,只允许 `minRatio`、`maxRatio`。 3. 与服务端保持一致:`minRatio` 为 0.1~1.0,`maxRatio` 为 1.0~3.0,最多 4 位小数,且 `minRatio <= maxRatio`;拒绝缺字段、非数值、NaN/Infinity、额外字段及越界值。 4. Agent 不使用规则比例重新计算任务价格区间;执行仍以服务端任务字段 `minUnitPriceCent` / `maxUnitPriceCent` 为唯一价格边界。 5. Android 自动测试加入同时包含 `priceGuard`、`probeSpecs.dimensionAliases` 和正式动作的当前完整规则快照;补充各类非法 `priceGuard` 拒绝测试。 6. 增加可被服务端与 Android 双方验证的共享采购规则样例,或等效的双端一致性回归门禁;不得复制一份无人校验的静态示例冒充共享契约。 ## 验收标准 - 合法 `priceGuard={minRatio:0.2,maxRatio:2}` 的 CG44 同形规则快照可被 Android 解析。 - 缺省 `priceGuard` 的旧任务快照继续兼容。 - 未知顶层字段仍被拒绝。 - 非对象、缺字段、额外字段、非数值、超过 4 位小数、越界及 `minRatio > maxRatio` 均被拒绝。 - 当前完整正式采购规则的服务端与 Android 契约测试均通过。 - Android 全量单元测试与 Debug APK 构建通过。 - 不执行 CG44 重试或真机采购;如用户后续要求安装,安装前重新确认设备无活动采集/采购任务。 ## 验证计划 - `go test ./app/goauto/purchasecontract ./app/goauto/purchase` - `android\gradlew.bat testDebugUnitTest` - `android\gradlew.bat assembleDebug` - `git diff --check` - 只读核对 CG44 保持失败且未产生新 attempt。 ## 风险与安全边界 - 采购属于高风险域;本工单只修正规则解析和自动测试,不授权任务重试、真机采购、创建订单或支付。 - 必须保持 Android fail-closed:只接受明确字段并逐项校验,不能整体忽略 `priceGuard` 或其他未知字段。 - 安装 APK 属于独立设备变更,仅在用户后续明确要求且设备无活动任务时执行。 ## 设计证据 - 恢复既有契约行为的非 UI 缺陷,不涉及页面结构、交互或文案变化,无需新增原型。 ## 子项目影响 - Android:规则解析与自动测试。 - Server:仅共享契约回归测试/样例(如方案采用),不改变运行行为。 - Web、数据库、权限、并发、状态机:无变化。 ## 文档影响 - 无长期文档影响:现有 Wiki 已明确 `priceGuard` 合法范围和用途,本工单恢复 Android 与既有契约一致,不产生新 API、业务规则或运维事实,因此跳过 Wiki 更新与同步。
Author
Owner

实施完成,待验收

实现:

  • Android PurchaseRuleParser 已将可选 priceGuard 纳入顶层严格白名单,并按服务端同一万分比语义校验 minRatio / maxRatio。
  • 显式字段必须为对象且字段完整;非数值、NaN/Infinity、额外字段、超过 4 位小数、越界及 minRatio > maxRatio 均拒绝;缺省字段的旧快照继续兼容,其他未知顶层字段仍拒绝。
  • Agent 仅保存校验后的比例,不使用它重新计算价格边界;执行仍使用任务下发的 minUnitPriceCent / maxUnitPriceCent。
  • 新增共享样例 contracts/purchase-rule-live-v1.json,同时包含 CG44 同形 priceGuard={0.2,2}、probeSpecs.dimensionAliases 和完整正式动作;服务端与 Android 测试直接消费同一文件。

验证:

  • cd server && go test ./app/goauto/purchasecontract ./app/goauto/purchase:通过。
  • android\gradlew.bat -p android testDebugUnitTest:BUILD SUCCESSFUL。
  • android\gradlew.bat -p android assembleDebug:BUILD SUCCESSFUL。
  • git diff --cached --check:通过。
  • Debug APK SHA-256:0117D831DC3C76E0180BCBD097A8E42D33A5D479C6F94945BE316847C82EC93A。
  • 只读核对 CG44:仍为采购失败,错误仍为 PURCHASE_RULE_INVALID:采购规则 包含未知字段: priceGuard;执行记录仍只有 #1,未新增重试,尚未取得订单号且保持待人工复核。

交付:

  • 提交并推送:13d291a。
  • 未安装 APK、未重试 CG44、未执行真机采购、未创建订单、未支付。
  • 无长期文档影响:现有 Wiki 已记录 priceGuard 的范围、默认值和价格快照语义,本次仅恢复 Android 对既有契约的兼容,因此跳过 Wiki 更新与同步。

工单保持开启,等待用户验收。

## 实施完成,待验收 实现: - Android `PurchaseRuleParser` 已将可选 `priceGuard` 纳入顶层严格白名单,并按服务端同一万分比语义校验 `minRatio` / `maxRatio`。 - 显式字段必须为对象且字段完整;非数值、NaN/Infinity、额外字段、超过 4 位小数、越界及 `minRatio > maxRatio` 均拒绝;缺省字段的旧快照继续兼容,其他未知顶层字段仍拒绝。 - Agent 仅保存校验后的比例,不使用它重新计算价格边界;执行仍使用任务下发的 `minUnitPriceCent` / `maxUnitPriceCent`。 - 新增共享样例 `contracts/purchase-rule-live-v1.json`,同时包含 CG44 同形 `priceGuard={0.2,2}`、`probeSpecs.dimensionAliases` 和完整正式动作;服务端与 Android 测试直接消费同一文件。 验证: - `cd server && go test ./app/goauto/purchasecontract ./app/goauto/purchase`:通过。 - `android\gradlew.bat -p android testDebugUnitTest`:BUILD SUCCESSFUL。 - `android\gradlew.bat -p android assembleDebug`:BUILD SUCCESSFUL。 - `git diff --cached --check`:通过。 - Debug APK SHA-256:`0117D831DC3C76E0180BCBD097A8E42D33A5D479C6F94945BE316847C82EC93A`。 - 只读核对 CG44:仍为采购失败,错误仍为 `PURCHASE_RULE_INVALID:采购规则 包含未知字段: priceGuard`;执行记录仍只有 `#1`,未新增重试,尚未取得订单号且保持待人工复核。 交付: - 提交并推送:`13d291a`。 - 未安装 APK、未重试 CG44、未执行真机采购、未创建订单、未支付。 - 无长期文档影响:现有 Wiki 已记录 `priceGuard` 的范围、默认值和价格快照语义,本次仅恢复 Android 对既有契约的兼容,因此跳过 Wiki 更新与同步。 工单保持开启,等待用户验收。
Author
Owner

最新 APK 已安装

用户于 2026-08-31 明确要求安装最新 APK。

安装前门禁:

  • 本地与远端 main 均为 13d291a。
  • ADB 仅发现一台在线设备:3B65BD02H7F00000(OnePlus PKG110)。
  • Admin 只读核对该设备为“在线 / 空闲 / 可选择”,无活动采集或采购任务。

构建与安装:

  • android\gradlew.bat -p android assembleDebug:BUILD SUCCESSFUL。
  • APK:android/app/build/outputs/apk/debug/app-debug.apk,大小 6441461 bytes。
  • SHA-256:0117D831DC3C76E0180BCBD097A8E42D33A5D479C6F94945BE316847C82EC93A。
  • adb -s 3B65BD02H7F00000 install -r ...:Success。
  • 安装后包版本:versionCode=48、versionName=0.9.35;本工单未提升版本号,以提交与 APK SHA-256 标识构建。
  • 无障碍服务安装后仍为启用状态。
  • Admin 再次刷新确认设备仍为“在线 / 空闲 / 可选择”,心跳已更新。

未重试 CG44、未创建订单、未支付。工单继续保持待验收。

## 最新 APK 已安装 用户于 2026-08-31 明确要求安装最新 APK。 安装前门禁: - 本地与远端 `main` 均为 `13d291a`。 - ADB 仅发现一台在线设备:`3B65BD02H7F00000`(OnePlus PKG110)。 - Admin 只读核对该设备为“在线 / 空闲 / 可选择”,无活动采集或采购任务。 构建与安装: - `android\gradlew.bat -p android assembleDebug`:BUILD SUCCESSFUL。 - APK:`android/app/build/outputs/apk/debug/app-debug.apk`,大小 `6441461` bytes。 - SHA-256:`0117D831DC3C76E0180BCBD097A8E42D33A5D479C6F94945BE316847C82EC93A`。 - `adb -s 3B65BD02H7F00000 install -r ...`:Success。 - 安装后包版本:`versionCode=48`、`versionName=0.9.35`;本工单未提升版本号,以提交与 APK SHA-256 标识构建。 - 无障碍服务安装后仍为启用状态。 - Admin 再次刷新确认设备仍为“在线 / 空闲 / 可选择”,心跳已更新。 未重试 CG44、未创建订单、未支付。工单继续保持待验收。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#176