修复完整采集任务详情 missing=null 导致 Agent 加载失败 #170

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

原始需求摘要

  • 来源:用户于 2026-08-31 反馈手机 Agent 查看采集任务 113 详情失败,错误为 value null at missing of type org.json.JSONObject$1 cannot be converted to JSONArray,确认分析后要求建工单并实施。
  • 目的:确保无缺失项的完整采集任务及历史 missing=null 任务均能正常查看详情。

当前事实与根因

  • 代码基线:d89a027,Agent 0.9.34(47)。
  • 任务 113 状态 completed,包含 2 个规格维度、5 个颜色价格、20 个 SKU,无采集错误,数据本身完整。
  • 数据库 missing_json 实际保存字符串 null;详情服务返回 JSON "missing":null。
  • #160 的结果规范化使用 append([]string(nil), request.Missing...),空输入被退化为 nil;持久化后成为 null。
  • 详情读取时把数据库 null 反序列化到已初始化空切片,又变回 nil。
  • Android 详情解析强制 getJSONArray("missing"),遇到 JSON null 时抛出类型转换异常。
  • Gitea MCP 当前会话未提供可调用工具,本工单回退 Gitea API 创建;凭据仅从已忽略的 gitea.env 读取。

目标

  1. 新提交的空缺失项必须持久化为 [],服务端详情必须稳定返回数组。
  2. 兼容数据库 SQL NULL、字符串 null 和异常空值,现有任务 113 无需修改数据即可读取。
  3. Android 对服务端缺失、null 或数组形式的 missing 均安全解析,默认空列表。

非目标

  • 不修改、重置或重采任务 113。
  • 不做数据库迁移或批量数据修复。
  • 不改变采集状态机、规格安全门禁或采购流程。
  • 不涉及下单、付款、控件树或截图。

前置依赖与并行性

  • 前置依赖:#160 的规格规范化门禁保留。
  • 可并行:否;服务端输出和 Android 消费端应在同一单元工单闭环验证。
  • 子项目影响:server、android;共享字段类型不变,只恢复既有数组契约。

方案

  • 服务端复制 missing 时显式创建长度为 0 的非 nil 切片。
  • 详情读取增加统一缺失项解码:只有合法 JSON 字符串数组才采用结果;SQL NULL、JSON null 或无效值统一返回空数组。
  • Agent 历史详情继续输出非 nil 空数组。
  • Android 使用 optJSONArray("missing")?.strings().orEmpty() 防御旧服务端响应。
  • 增加结果规范化、历史 null 详情序列化与 Android 响应解析测试。

设计证据

非 UI、恢复既有 API 数组语义的缺陷,不需要原型。依据为任务 113 结构化数据库与服务层响应;未读取或保存控件树/整屏截图。

验收标准

  • 完整任务空 missing 持久化为 [],详情 JSON 返回 "missing":[]。
  • 历史 missing_json 为 SQL NULL、null 或无效 JSON 时详情仍返回空数组且不崩溃。
  • 非空缺失项保持原值。
  • Android 对 missing 数组、null 和缺失字段均可打开详情。
  • 任务 113 无需重采即可查看详情。
  • server 相关测试、Android 单元测试与 Debug APK 构建通过。

风险

  • 服务端不得把无效历史内容扩散成 null;统一空数组是安全降级。
  • Android 宽容读取不能影响非空缺失项展示。
  • 不通过迁移修改历史任务,避免不必要的数据写入风险。

文档影响

无长期文档影响:字段仍是既有 missing 数组,只修复实现偏离;不更新 Wiki。

## 原始需求摘要 - 来源:用户于 2026-08-31 反馈手机 Agent 查看采集任务 113 详情失败,错误为 `value null at missing of type org.json.JSONObject$1 cannot be converted to JSONArray`,确认分析后要求建工单并实施。 - 目的:确保无缺失项的完整采集任务及历史 `missing=null` 任务均能正常查看详情。 ## 当前事实与根因 - 代码基线:`d89a027`,Agent 0.9.34(47)。 - 任务 113 状态 `completed`,包含 2 个规格维度、5 个颜色价格、20 个 SKU,无采集错误,数据本身完整。 - 数据库 `missing_json` 实际保存字符串 `null`;详情服务返回 JSON `"missing":null`。 - #160 的结果规范化使用 `append([]string(nil), request.Missing...)`,空输入被退化为 nil;持久化后成为 `null`。 - 详情读取时把数据库 `null` 反序列化到已初始化空切片,又变回 nil。 - Android 详情解析强制 `getJSONArray("missing")`,遇到 JSON null 时抛出类型转换异常。 - Gitea MCP 当前会话未提供可调用工具,本工单回退 Gitea API 创建;凭据仅从已忽略的 `gitea.env` 读取。 ## 目标 1. 新提交的空缺失项必须持久化为 `[]`,服务端详情必须稳定返回数组。 2. 兼容数据库 SQL NULL、字符串 `null` 和异常空值,现有任务 113 无需修改数据即可读取。 3. Android 对服务端缺失、null 或数组形式的 `missing` 均安全解析,默认空列表。 ## 非目标 - 不修改、重置或重采任务 113。 - 不做数据库迁移或批量数据修复。 - 不改变采集状态机、规格安全门禁或采购流程。 - 不涉及下单、付款、控件树或截图。 ## 前置依赖与并行性 - 前置依赖:#160 的规格规范化门禁保留。 - 可并行:否;服务端输出和 Android 消费端应在同一单元工单闭环验证。 - 子项目影响:server、android;共享字段类型不变,只恢复既有数组契约。 ## 方案 - 服务端复制 `missing` 时显式创建长度为 0 的非 nil 切片。 - 详情读取增加统一缺失项解码:只有合法 JSON 字符串数组才采用结果;SQL NULL、JSON null 或无效值统一返回空数组。 - Agent 历史详情继续输出非 nil 空数组。 - Android 使用 `optJSONArray("missing")?.strings().orEmpty()` 防御旧服务端响应。 - 增加结果规范化、历史 null 详情序列化与 Android 响应解析测试。 ## 设计证据 非 UI、恢复既有 API 数组语义的缺陷,不需要原型。依据为任务 113 结构化数据库与服务层响应;未读取或保存控件树/整屏截图。 ## 验收标准 - [ ] 完整任务空 `missing` 持久化为 `[]`,详情 JSON 返回 `"missing":[]`。 - [ ] 历史 `missing_json` 为 SQL NULL、`null` 或无效 JSON 时详情仍返回空数组且不崩溃。 - [ ] 非空缺失项保持原值。 - [ ] Android 对 missing 数组、null 和缺失字段均可打开详情。 - [ ] 任务 113 无需重采即可查看详情。 - [ ] server 相关测试、Android 单元测试与 Debug APK 构建通过。 ## 风险 - 服务端不得把无效历史内容扩散成 null;统一空数组是安全降级。 - Android 宽容读取不能影响非空缺失项展示。 - 不通过迁移修改历史任务,避免不必要的数据写入风险。 ## 文档影响 无长期文档影响:字段仍是既有 `missing` 数组,只修复实现偏离;不更新 Wiki。
Author
Owner

实施完成,待验收

最终方案与差异

  • 服务端结果规范化显式保留非 nil 空 missing,新结果持久化为 [],不再退化为 null。
  • 服务端详情统一兼容 SQL NULL、JSON null 和无效历史 JSON,稳定输出非 nil 空数组;非空缺失项保持原值。
  • Agent 历史详情将 missing 数组、JSON null 或字段缺失统一安全解析,旧服务端响应不再导致详情页崩溃。
  • 不做数据库迁移或历史数据写入,任务 113 可通过读取兼容直接恢复。
  • Agent 升级为 0.9.35(versionCode 48),同步更新仓库 APK 版本绑定测试。

验证

  • go test ./app/goauto/task:通过。
  • go test ./app/goauto/apprelease ./app/goauto/task:通过。
  • go test ./app/goauto/...:通过。
  • android\\gradlew.bat testDebugUnitTest --tests "cn.ilapage.goauto.agent.AgentApiClientJsonTest":通过。
  • android\\gradlew.bat testDebugUnitTest assembleDebug:通过。
  • git diff --check / 暂存差异检查:通过。
  • APK SHA-256:627AF14F28A2DD02D3E78E715B52DF6DC8C60CE943AB4314543E13B61ABC524F。

提交与推送

  • 提交:60f01f73f0736e1e59c4bd4554a665ec024c0f43
  • 已推送到 origin/main。

真机安装

  • 已覆盖安装到设备 3B65BD02H7F00000,安装成功并保留应用数据。
  • 设备回读:versionName=0.9.35、versionCode=48。
  • GoAuto 无障碍服务保持启用,应用进程正常运行。
  • 未重置或重采任务 113;请直接打开任务 113 详情验收。

未执行与文档影响

  • 未部署服务端正式进程;当前 APK 已具备对旧服务端 missing:null 的兼容,服务端新持久化语义将在正常部署该提交后生效。
  • 无长期文档影响:字段仍是既有数组契约,仅修复实现偏离,按规则跳过 Wiki 更新与同步。
  • Gitea MCP 当前会话未提供可调用工具,本次创建与回写回退 Gitea API,凭据未写入工单、代码或日志。
## 实施完成,待验收 ### 最终方案与差异 - 服务端结果规范化显式保留非 nil 空 `missing`,新结果持久化为 `[]`,不再退化为 `null`。 - 服务端详情统一兼容 SQL NULL、JSON `null` 和无效历史 JSON,稳定输出非 nil 空数组;非空缺失项保持原值。 - Agent 历史详情将 `missing` 数组、JSON null 或字段缺失统一安全解析,旧服务端响应不再导致详情页崩溃。 - 不做数据库迁移或历史数据写入,任务 113 可通过读取兼容直接恢复。 - Agent 升级为 `0.9.35`(versionCode 48),同步更新仓库 APK 版本绑定测试。 ### 验证 - `go test ./app/goauto/task`:通过。 - `go test ./app/goauto/apprelease ./app/goauto/task`:通过。 - `go test ./app/goauto/...`:通过。 - `android\\gradlew.bat testDebugUnitTest --tests "cn.ilapage.goauto.agent.AgentApiClientJsonTest"`:通过。 - `android\\gradlew.bat testDebugUnitTest assembleDebug`:通过。 - `git diff --check` / 暂存差异检查:通过。 - APK SHA-256:`627AF14F28A2DD02D3E78E715B52DF6DC8C60CE943AB4314543E13B61ABC524F`。 ### 提交与推送 - 提交:`60f01f73f0736e1e59c4bd4554a665ec024c0f43` - 已推送到 `origin/main`。 ### 真机安装 - 已覆盖安装到设备 `3B65BD02H7F00000`,安装成功并保留应用数据。 - 设备回读:`versionName=0.9.35`、`versionCode=48`。 - GoAuto 无障碍服务保持启用,应用进程正常运行。 - 未重置或重采任务 113;请直接打开任务 113 详情验收。 ### 未执行与文档影响 - 未部署服务端正式进程;当前 APK 已具备对旧服务端 `missing:null` 的兼容,服务端新持久化语义将在正常部署该提交后生效。 - 无长期文档影响:字段仍是既有数组契约,仅修复实现偏离,按规则跳过 Wiki 更新与同步。 - Gitea MCP 当前会话未提供可调用工具,本次创建与回写回退 Gitea API,凭据未写入工单、代码或日志。
Author
Owner

更正上一条回写中的完整提交哈希:60f01f744765c30f796a5651eed4853a4cfacc66。已再次核对本地 HEAD 与远端 origin/main 完全一致。

更正上一条回写中的完整提交哈希:`60f01f744765c30f796a5651eed4853a4cfacc66`。已再次核对本地 HEAD 与远端 `origin/main` 完全一致。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/goauto#170