From 644ac0d3b2d5b758aef7150f6004ea755561988f Mon Sep 17 00:00:00 2001 From: ila Date: Fri, 7 Aug 2026 16:37:13 +0800 Subject: [PATCH] docs: import wiki at afc651f75a3a --- T-275.-.md | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 T-275.-.md diff --git a/T-275.-.md b/T-275.-.md new file mode 100644 index 0000000..717af0f --- /dev/null +++ b/T-275.-.md @@ -0,0 +1,89 @@ + +> 同步来源:[`docs/tasks/T-275.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-275.md) · commit `afc651f75a3a` + +--- +id: T-275 +title: 修复超长执行事件阻塞任务同步 +phase: 2 +deps: + - T-207 + - T-274 +status: DONE +created: 2026-08-01 +context_ref: f3f59fb +work_branch: null +write_paths: + - docs/tasks/T-275.md + - docs/current-state.md + - docs/04-architecture.md + - docs/05-coding-rules.md + - android-buyer/app/src/main/** + - android-buyer/app/src/test/** +--- + +## 问题 / 背景 + +安装 T-274 后,Roubao 任务模块持续提示“后台暂时离线,将在授权截止前重试”,但真机 +日志证明手机已连接后台,上传 execution outbox 时收到不可重试的 HTTP 422 +`EXECUTION_RESULT_INVALID`。候选搜索事件原长约 889 字节;T-274 追加六个 locator +诊断键后达到 1014 字节,超过后台单条事件 `message` 的 1000 字节契约。 + +当前同步循环还把所有非本地异常统一标记为离线,并将不可重试的 4xx 项永久保留在 +outbox 队首,导致后续事件和 heartbeat 均无法执行。 + +## 行为契约 + +1. 候选搜索的状态事件与聚合诊断事件分开发送;每条 `message` 的 UTF-8 长度必须在 + 后台 1000 字节上限内,核心状态、轮次、失败码和全部聚合计数均保留。 +2. T-274 已持久化但尚未被后台接受的超长候选事件,在上传前按稳定分隔点确定性拆成 + 两条合法事件;保持原事件 ID,派生诊断事件 ID 必须稳定,网络重试不能产生新事件。 +3. 迁移只处理可确认来源的 `CANDIDATE_SEARCH`/`CANDIDATE_SEARCH_*` 超长事件;其它 + 非法 payload 不得截断、丢弃或伪装成功。 +4. App 解析后台结构化错误中的非敏感字段校验详情。HTTP 已收到响应时后台状态保持在线; + 仅连接、TLS、DNS、超时等 I/O 错误和可重试 5xx 显示后台暂时不可用。 +5. `retryable=false` 的 outbox 上传失败进入持久化阻塞状态,不再自动重试同一项,也不越过 + 该项继续 heartbeat 或自动化;UI 显示稳定错误码和安全字段,不显示响应正文、凭证、 + 商品信息或服务端内部信息。 +6. 更新后必须能自动修复当前手机里由 T-274 产生的 1014 字节候选事件并恢复队列同步, + 不要求清除 App 数据、重新登录或丢弃任务。 + +## 方案 + +1. 将候选尝试核心消息与 `CandidateSearchDiagnostics` 消息组装为同一 EVENTS payload 中 + 的两条事件,并增加共享 UTF-8 长度校验常量和单测。 +2. 在 outbox 上传边界增加窄范围 legacy payload 规范化器:识别单条超限候选事件,按 + ` cards=` 分隔,使用原 event ID 派生稳定 UUID 后形成两条事件。 +3. 扩展 `ProcurementApiException` 保存经过白名单裁剪的 `details.fields`;同步状态按是否 + 收到 HTTP 响应和 `retryable` 分类。 +4. 为 outbox 项增加可持久化 rejection 元数据。不可重试响应只记录一次并安全停止同步; + legacy 修复在发请求前完成,因此当前已知超长项不会进入 rejection 状态。 + +## 验收要点 + +- [x] 新候选搜索状态和诊断事件分别小于等于 1000 UTF-8 字节,聚合字段完整。 +- [x] T-274 的 1014 字节 legacy payload 被稳定拆分并成功上传,重复迁移结果相同。 +- [x] HTTP 422 显示“后台拒绝执行结果”及安全字段,`backendOnline=true`,且不再重试。 +- [x] I/O/超时和可重试 5xx 仍保留 outbox 并按既有授权边界重试。 +- [x] 不可重试阻塞跨进程重启保持,不继续 heartbeat、拼多多动作或越过队首结果。 +- [x] Android 单测、lint、Debug/Release APK 构建通过,Debug APK 覆盖安装到 PKG110。 + +## 边界 + +- 不提高后台 1000 字节限制,不放宽敏感内容检查。 +- 不丢弃不可重试结果,不自动取消任务,不清除登录、claim、候选或下单状态。 +- 不修改三轮搜索、SKU/价格匹配、候选数量、VLM、支付边界或订单提交授权。 + +## 执行记录 + +- 2026-08-01:根据真机 HTTP 422 日志和 T-274 消息长度复现创建任务,状态 `TODO`。 + 已确认网络、TLS 和 Bearer 鉴权不是本次错误;直接失败字段为 execution event + `message` 超过 1000 UTF-8 字节。 +- 2026-08-01:候选状态和诊断改为同一 EVENTS payload 内两条有界事件;上传边界只对 + T-274 单条超长候选格式执行确定性拆分,原 event ID 保留并稳定派生诊断 ID。App 只从 + `EXECUTION_RESULT_INVALID` 的显式字段白名单读取字段名,不读取字段值或响应正文。 + 不可重试 outbox 拒绝会加密持久化错误码、HTTP 状态和字段名,停止同步、候选采集、 + dry-run 和提交;I/O/可重试 5xx 仍保持原重试语义。 +- 2026-08-01:Debug/Release 各 462 项单测、`lintDebug`、`assembleDebug`、 + `assembleRelease` 全部通过。Debug APK 以保留数据方式覆盖安装到 PKG110;安装后原持续 + 422 的任务恢复为等待后台确认商品。最终 APK 再覆盖安装并运行一个同步周期,logcat + 未出现 `EXECUTION_RESULT_INVALID`、同步异常或崩溃,状态改为 `DONE`。