aps-agent/docs/round-68-sap-outbound-p3-wo...

5.9 KiB
Raw Permalink Blame History

Round 68 工作计划:SAP Outbound P3 Evidence Envelope

日期:2026-08-03

1. 背景与风险

sap.sync.outbound 会调用 SAP client push_receipt,属于外部副作用,但当前被标为 P2:单审批、无 execution grant、无批准载荷摘要、无世界指纹绑定。执行阶段重新预览,审批后版本/工单/数量变化可能被静默带入外部回写。

GitNexus 影响:

  • apply_outbound:HIGH,2 个直接依赖、24 个总影响。
  • stage_sap_sync:HIGH,3 个直接依赖、33 个总影响,影响 handle_intent 流程。
  • execute_confirmed:HIGH,17 个直接依赖、22 个总影响。
  • power_of:LOW,4 个直接依赖、10 个总影响。

动态 action 分派会低估流程影响,本轮按 HIGH 门禁处理。

2. 目标

  1. 将 sap.sync.outbound 从 P2 升为 P3;inbound 保持 P2。
  2. stage 时冻结版本、canonical outbound items、idempotency keys、payload digest、world fingerprint 和 evidence refs,并由 confirmation paramsHash 绑定。
  3. 第二位不同审批人批准后,任何 SAP 调用之前校验:confirmId、execution grant、checkpoint、version、payload digest、world fingerprint、evidence refs、idempotency keys。
  4. 校验通过后一次性消费 execution grant;重放失败。
  5. 成功/拒绝/异常/部分失败均写 P3 审计,包含 approvers、confirmId、beforeSnapshot、evidenceRefs、payloadDigest、worldFingerprint 和 pushed/duplicate/failed idem keys。
  6. 维持 Mock SAP 幂等;同 idem key 不产生第二次真实 receipt。

3. 契约

Approval params

{direction:'outbound', versionId, versionNo, payloadDigest, worldFingerprint, idemKeys, evidenceRefs}

Evidence refs

  • sap-outbound-version:<versionId>
  • sap-outbound-payload:<sha256>
  • sap-outbound-world:<sha256>

World fingerprint

只包含审批相关切片:目标 flex schedule version、该版本非冻结 work orders、关联 flex orders 的数量/外部 AUFNR;剔除 audit/journal/技术时间。

执行顺序

stage-time checkpoint + canonical approvalParams -> final execution recompute once -> validate current/checkpoint/approvalParams completely -> persist READY execution record -> consume grant with the exact stored approvalParams -> push the frozen approved items without rereading world -> per-item durable result -> final audit/save。任何 pre-push 失败调用次数必须为 0。

4. 写边界

  • W68-SAP:server/aps_domain/sap_sync.py
  • W68-WORKFLOW:server/aps_domain/workflow.py、server/agent_core/harness.py
  • W68-TEST:tests/golden/test_sap_sync.py 与新增 tests/golden/test_sap_outbound_evidence.py
  • 主 agent:集成、运行验证、文档、detect_changes、独立审计。

5. 验收

  • P3 双人 SOD:第一次审批零调用,第二个不同用户后才 push。
  • approval 后版本/WO/订单数量/外部 AUFNR 任一漂移均拒绝,push=0。
  • digest/action/params/grant/checkpoint/evidence 替换或缺失均拒绝。
  • grant 重放拒绝;成功后相同 idem key 幂等。
  • success/failed audit evidence envelope 字段齐全。
  • direct apply 不携带 P3 envelope 必须拒绝。
  • SAP focused、gateway/confirmation/evidence 相关 suites、full golden、真实 Mock SAP 运行、服务健康、现场 hash 不变。

6. Out of scope

  • 真实 SAP RFC/PI 凭据、白名单、网络和客户回执 schema。
  • 分布式 Saga 补偿/撤销 SAP receipt;部分失败仅留结构化审计和幂等重试证据。
  • inbound P2、folder.schedule TOCTOU、Automation G4。
  • commit/push/merge/publish。

7. 首轮 Plan Audit 修订(权威覆盖前文歧义)

  1. Checkpoint 在 stage 时创建:stage_sap_sync 在出确认卡前创建 approval-time checkpoint;beforeSnapshot 写入唯一 approvalParams。final confirm 只能读取并验证该 pairId,禁止重新创建。
  2. 唯一 canonical approvalParams:helper 生成并排序全部字段;stage_confirmation 原样存储,workflow/apply 原样透传,consume_execution_grant 使用同一对象。当前重算 projection 仅用于逐字段比较,不能替代批准对象。
  3. consume 前完成全部 world 读取和校验:execution 使用已批准 items 的深拷贝;consume 后不再读取 world。任何漂移都在 grant 消费前拒绝。
  4. 可恢复 execution/outbox:sapOutboundExecutions 以 confirmId + payloadDigest 为身份;push 前持久化 READY/PENDING;grant consumed 后持久化 GRANT_CONSUMED;每个 idem key 逐条持久化 PUSHED/DUPLICATE/FAILED。部分失败写 FAILED/PARTIAL_FAILED 审计;恢复必须重新 P3 审批,并通过 previousExecutionId 关联前次 attempt,外部幂等键复用。
  5. 纯 projection:新增无 client 调用的 projection helper。完整候选 WO 稳定排序,fingerprint 覆盖 version id/no/status、候选总数、每个 WO 的 versionId/id/orderNo/flexOrderNo/operation/equipment/start/end/frozen、关联订单 quantity/AUFNR;排除 audit/journal/sapLinks/actor/time/client status。保持现有 50 条发送上限:先全量 canonical sort,再选前 50;fingerprint 同时包含 fullCandidateDigest/totalCount/limit,确保第 51 条漂移也被发现。
  6. Client 边界:stage/preview 可调用只读 status();安全门禁明确针对 push_receipt。纯 projection 与所有失败路径不得调用 push;client 实例化应位于 grant consume 后。
  7. HTTP/调用边界:apply_outbound 的 P3 envelope 均为无默认值 keyword-only 必填;盘点全部 callers。preview/stage 路由永不 push,只有 /api/actions/confirm 最终 P3 分支可执行 push。
  8. 可信审批身份:requester/approvals 只取 take_confirmation 返回的审批存储 decision record,不能取请求 params;沿用现有策略:两名 approver userId 必须不同,requester 是否可参与由既有 RBAC/allowed 决定。审计记录 requester、两名 approver、顺序/角色、confirmId 和 grant consumption。