来源:用户,2026-09-12 会话。排查「线上采购 PAYMENT_REPEATED 占比回升」时发现根因分析无法进行——Agent 上报的诊断证据没有落库。
用户确认先做服务端这一条,拿到真实证据后再决定 Agent 侧参数怎么改。
server/app/goauto/purchase/lifecycle.go 约 386-401 行:
server/app/goauto/purchase/lifecycle.go
case "order_result_unknown": failureCode, failureMessage, failureErr := normalizeOrderUnknownFailure(req.ErrorCode, req.ErrorMessage) ... a.ErrorCode, a.ErrorMessage = &failureCode, &failureMessage // Agent 证据被替换 t.ErrorCode, t.ErrorMessage = &failureCode, &failureMessage case "failed": t.ErrorCode = &req.ErrorCode t.ErrorMessage = &req.ErrorMessage // Agent 证据原样保留
normalizeOrderUnknownFailure(约 450 行)无条件返回固定文案,Agent 的 message 只用来判断非空:
normalizeOrderUnknownFailure
message
canonicalMessage, ok := allowedOrderUnknownFailures[code] if !ok || message == "" { return "", "", fail(CodeInvalidRequest, "订单核单失败阶段无效") } return code, canonicalMessage, nil
PurchaseRehearsalExecutor.kt:154 把 live.lastOrderReadFailure 的 code 和 message 原样上报。PurchaseLiveAutomation.kt:410-417 构造的消息带诊断后缀:
PurchaseRehearsalExecutor.kt:154
live.lastOrderReadFailure
code
PurchaseLiveAutomation.kt:410-417
"支付页安全返回后持续无订单证据,已停止自动核单[paymentBackAttempts=N;consecutivePaymentSamplesAfterBack=M]"
purchase_task_attempt.error_message 与 purchase_task.error_message 均为 size:1000,空间充足。
purchase_task_attempt.error_message
purchase_task.error_message
size:1000
PURCHASE_ORDER_PAYMENT_REPEATED
error_message
支付页重复出现,已停止自动核单
irreversible_at
pdd_order_no
"failed"
[type=UNKNOWN;scrollables=1;headings=2;options=8;summary=false;quantity=true;orderAction=false;pageEvidence=true]
#210 加入的 paymentBackAttempts / consecutivePaymentSamplesAfterBack 从未进入数据库,因此无法区分以下三种情形,而三者的修法完全不同:
#210
paymentBackAttempts
consecutivePaymentSamplesAfterBack
500 + 3×200 = 1.1
60×200 = 12
ORDER_CONTEXT_MARKERS
UNPAID_MARKERS
保留固定文案作为面向人的稳定摘要,在其后附加 Agent 证据。
normalizeOrderUnknownFailure 改为返回 canonicalMessage 与 Agent 证据的拼接:
canonicalMessage
allowedOrderUnknownFailures[code]
[必须]
同时修正第二处不一致:"failed" 分支只写 t.ErrorCode / t.ErrorMessage,未写 a.ErrorCode / a.ErrorMessage,导致该路径产生的 attempt 行 error_code 为 NULL(线上任务 170/171 的 spec_probe attempt 即是如此)。本单一并补齐,使两条路径的 attempt 都带错误码与消息。
t.ErrorCode
t.ErrorMessage
a.ErrorCode
a.ErrorMessage
error_code
ORDER_RESULT_PAYMENT_POST_BACK_MAX_SAMPLES
ORDER_RESULT_SAMPLE_INTERVAL_MS
allowedOrderUnknownFailures
无。可与 #242 并行(不同交付单元)。
server/
app/goauto/purchase/lifecycle.go
web/
android/
order_result_unknown
lifecycle.go
go build ./...
go test -p 1 ./...
key=value
docs/08-agent-api-contract.md(Wiki Android-Agent-API-Contract):订单核单失败的 errorMessage 语义由「服务端固定文案」变为「固定文案 + Agent 证据」,属于共享契约变化,须先改线上 Wiki 再同步镜像。
docs/08-agent-api-contract.md
Android-Agent-API-Contract
errorMessage
提交 c14f5f5,已合并 main 并推送:8293b27..c14f5f5。
c14f5f5
8293b27..c14f5f5
1. 保留 Agent 证据
normalizeOrderUnknownFailure 返回「固定文案 + Agent 证据」。固定文案仍由错误码唯一决定并排在最前,Agent 文本仅作为追加证据,不作为权威描述。
新增 appendAgentEvidence / flattenAgentEvidence:
appendAgentEvidence
flattenAgentEvidence
orderFailureMessageLimit = 1000
…
INVALID_REQUEST
2. 补齐 "failed" 分支的 attempt 字段
原来只写 t.ErrorCode / t.ErrorMessage,attempt 上为 NULL,导致按 attempt 统计失败时该路径的记录隐形(线上规格失败即是如此)。现同时写入 a.ErrorCode / a.ErrorMessage。
python dev_scripts/harness.py sync --check
order_failure_evidence_test.go
本单无数据库迁移、无前端改动,仅替换后端二进制。
GOOS=linux GOARCH=amd64 CGO_ENABLED=0
9fdc9145c760bfe5
/home/goauto/releases/20260912-c14f5f5
20260912-8293b27
goauto-server
current
systemctl restart goauto.service
active
http://185.216.248.75:9527/
/api/admin/v1/syb-product-filters
回滚方式:ln -sfn /home/goauto/releases/20260912-8293b27 /home/goauto/current 后重启服务。上一 release 目录完整保留。
ln -sfn /home/goauto/releases/20260912-8293b27 /home/goauto/current
顺带核实:线上 #269 的两个迁移(1789112900000、1789113000000)已应用,syb_product_filter 8 行就位,SYB 同步过滤正常。
1789112900000
1789113000000
syb_product_filter
[必须] 线上尚未出现新的 PURCHASE_ORDER_PAYMENT_REPEATED,因此还没有拿到真实的 paymentBackAttempts 与 consecutivePaymentSamplesAfterBack。
下一次该错误发生后,须核对 purchase_task.error_message 与 purchase_task_attempt.error_message 是否包含这两个值。拿到后才能区分:
三者修法不同,Agent 侧参数调整须待此证据到手后另建工单。
本单只恢复可观测性,不降低 PAYMENT_REPEATED 发生率(2026-09-07 至 09-11 共 61 次,占比 20%~100% 波动)。这 61 单 irreversible_at 全部置位、订单号全部未恢复,单号补回属 #242 范围。
先改线上 Wiki 并回读 revision,再同步镜像:
ba259178
契约原文「服务端只接受白名单并按错误码写入固定提示,不信任或保存页面原文」已改为「固定提示 + Agent 诊断证据」,并写明压平/截断规则、failed 分支 attempt 写入要求及改动原因。
failed
No dependencies set.
The note is not visible to the blocked user.
原始需求
来源:用户,2026-09-12 会话。排查「线上采购 PAYMENT_REPEATED 占比回升」时发现根因分析无法进行——Agent 上报的诊断证据没有落库。
用户确认先做服务端这一条,拿到真实证据后再决定 Agent 侧参数怎么改。
当前事实(代码事实 + 线上数据,2026-09-12 核验)
问题:同一个 switch 的两个分支对 Agent 证据处理相反
server/app/goauto/purchase/lifecycle.go约 386-401 行:normalizeOrderUnknownFailure(约 450 行)无条件返回固定文案,Agent 的message只用来判断非空:Agent 侧确认在发送
PurchaseRehearsalExecutor.kt:154把live.lastOrderReadFailure的code和message原样上报。PurchaseLiveAutomation.kt:410-417构造的消息带诊断后缀:purchase_task_attempt.error_message与purchase_task.error_message均为size:1000,空间充足。线上数据佐证
PURCHASE_ORDER_PAYMENT_REPEATED共 61 次,error_message全部是固定文案支付页重复出现,已停止自动核单,零条带诊断后缀。irreversible_at置位 61/61(订单极可能已创建),pdd_order_no恢复 0/61。"failed"分支,证据完整落库:[type=UNKNOWN;scrollables=1;headings=2;options=8;summary=false;quantity=true;orderAction=false;pageEvidence=true]。由此导致的分析盲区
#210加入的paymentBackAttempts/consecutivePaymentSamplesAfterBack从未进入数据库,因此无法区分以下三种情形,而三者的修法完全不同:500 + 3×200 = 1.1秒,而整体预算60×200 = 12秒)ORDER_CONTEXT_MARKERS/UNPAID_MARKERS未命中)方案
保留固定文案作为面向人的稳定摘要,在其后附加 Agent 证据。
normalizeOrderUnknownFailure改为返回canonicalMessage与 Agent 证据的拼接:allowedOrderUnknownFailures[code]决定,不采用 Agent 文本作为主文案(避免把不可信自由文本当作权威描述,也保持界面文案稳定)。message作为证据附加在固定文案之后。[必须]附加前做边界处理:去除换行与控制字符、压缩连续空白、按error_message的size:1000截断(固定文案优先保留,证据部分被截断时以省略号结尾)。[必须]Agent 文本为空时行为不变(仍按现有规则拒绝,见normalizeOrderUnknownFailure现有校验)。同时修正第二处不一致:
"failed"分支只写t.ErrorCode/t.ErrorMessage,未写a.ErrorCode/a.ErrorMessage,导致该路径产生的 attempt 行error_code为 NULL(线上任务 170/171 的 spec_probe attempt 即是如此)。本单一并补齐,使两条路径的 attempt 都带错误码与消息。非目标
ORDER_RESULT_PAYMENT_POST_BACK_MAX_SAMPLES、ORDER_RESULT_SAMPLE_INTERVAL_MS,不改 Back 次数限制。参数如何调整取决于本单上线后拿到的真实证据,届时另建工单。allowedOrderUnknownFailures的固定文案内容与错误码集合。前置依赖
无。可与 #242 并行(不同交付单元)。
子项目影响
server/:app/goauto/purchase/lifecycle.goweb/:无(error_message已在采购管理页展示)android/:无验收
order_result_unknown上报后,purchase_task.error_message与purchase_task_attempt.error_message均包含固定文案和 Agent 证据message为空时行为与现在一致"failed"分支产生的 attempt 行带error_code与error_message验证
lifecycle.go相关单元测试:拼接、清理、截断、空消息、两条分支的 attempt 写入go build ./...、go test -p 1 ./...PURCHASE_ORDER_PAYMENT_REPEATED时,error_message中应能读到paymentBackAttempts与consecutivePaymentSamplesAfterBack的实际值风险
error_message会出现 Agent 提供的自由文本。已通过「固定文案仍为主、证据仅追加、清理控制字符、限长截断」控制。该路径与现有"failed"分支的做法一致,不引入新的信任假设。key=value结构,不含账号、地址、订单个人信息。实施时须确认所有allowedOrderUnknownFailures对应的 Agent 消息都不携带此类内容。文档影响
docs/08-agent-api-contract.md(WikiAndroid-Agent-API-Contract):订单核单失败的errorMessage语义由「服务端固定文案」变为「固定文案 + Agent 证据」,属于共享契约变化,须先改线上 Wiki 再同步镜像。实施完成并已部署线上(2026-09-12,待验收)
提交
c14f5f5,已合并 main 并推送:8293b27..c14f5f5。实现
1. 保留 Agent 证据
normalizeOrderUnknownFailure返回「固定文案 + Agent 证据」。固定文案仍由错误码唯一决定并排在最前,Agent 文本仅作为追加证据,不作为权威描述。新增
appendAgentEvidence/flattenAgentEvidence:orderFailureMessageLimit = 1000(对应error_message列宽)截断,固定文案优先完整保留,被截断的证据以…结尾INVALID_REQUEST2. 补齐
"failed"分支的 attempt 字段原来只写
t.ErrorCode/t.ErrorMessage,attempt 上为 NULL,导致按 attempt 统计失败时该路径的记录隐形(线上规格失败即是如此)。现同时写入a.ErrorCode/a.ErrorMessage。验证
go build ./...通过go test -p 1 ./...33 个包全绿(合并到 main 后重跑确认),既有order_result_unknown相关用例未被破坏python dev_scripts/harness.py sync --check一致order_failure_evidence_test.go,覆盖:诊断值必须出现在消息中、换行/制表符/BOM 压平、4000 字证据截断且固定文案完整、空消息仍拒绝、未批准错误码仍拒绝、证据等于固定文案时不重复拼接、端到端两张表均写入、"failed"分支 attempt 带错误码与消息线上部署(2026-09-12 11:20)
本单无数据库迁移、无前端改动,仅替换后端二进制。
GOOS=linux GOARCH=amd64 CGO_ENABLED=0,静态链接,与线上原二进制构建方式一致9fdc9145c760bfe5,本地与服务器一致/home/goauto/releases/20260912-c14f5f5,以上一 release20260912-8293b27为基础复制后替换goauto-servercurrent软链并systemctl restart goauto.serviceactive,路由注册与 JobCore 启动正常,无 error/panic;http://185.216.248.75:9527/返回 200;/api/admin/v1/syb-product-filters返回 401(鉴权正常)回滚方式:
ln -sfn /home/goauto/releases/20260912-8293b27 /home/goauto/current后重启服务。上一 release 目录完整保留。顺带核实:线上 #269 的两个迁移(
1789112900000、1789113000000)已应用,syb_product_filter8 行就位,SYB 同步过滤正常。未验证(本单验收的关键一步仍待完成)
[必须]线上尚未出现新的PURCHASE_ORDER_PAYMENT_REPEATED,因此还没有拿到真实的paymentBackAttempts与consecutivePaymentSamplesAfterBack。下一次该错误发生后,须核对
purchase_task.error_message与purchase_task_attempt.error_message是否包含这两个值。拿到后才能区分:500 + 3×200 = 1.1秒,整体预算60×200 = 12秒)ORDER_CONTEXT_MARKERS/UNPAID_MARKERS未命中三者修法不同,Agent 侧参数调整须待此证据到手后另建工单。
本单不改变的事
本单只恢复可观测性,不降低 PAYMENT_REPEATED 发生率(2026-09-07 至 09-11 共 61 次,占比 20%~100% 波动)。这 61 单
irreversible_at全部置位、订单号全部未恢复,单号补回属 #242 范围。文档影响(已完成)
先改线上 Wiki 并回读 revision,再同步镜像:
Android-Agent-API-Contract→ revisionba259178(镜像docs/08-agent-api-contract.md)契约原文「服务端只接受白名单并按错误码写入固定提示,不信任或保存页面原文」已改为「固定提示 + Agent 诊断证据」,并写明压平/截断规则、
failed分支 attempt 写入要求及改动原因。