历史 · 调度、执行与模型网关池
重构前档案,仅供追溯,不作为新版本执行指令
历史档案 · 2026-09-11 重构前快照。 本文中的“当前”“已冻结”和实施顺序属于旧基线。新版本以现行总览和实施计划为准。
本文中的“对账 / Reconciliation”若未明确写成 Reconciliation Case,只表示Gateway或消费Owner内的核对、Conflict/Blocked状态或Incident诊断。Gateway不得分配Case Ref;当前正式Operations Case仅有late_settlement_dimension | billing_finalization_run两个Billing来源。
本页是 OceanWay 模型执行链路的主规范。它回答五个问题:公开产品在哪里,用户和钱包在哪里,文本与媒体请求如何分流,长时媒体任务由谁恢复,以及供应成本和用户计费如何保持独立。管理员如何跨这些边界诊断、告警和处置,见管理员平台与运维控制面。
正式决策
OceanWay 正式采用“中心控制面 + 同级双网关池”,而不是网关层层嵌套:
| 边界 | 正式定位 | 唯一负责 | 明确不负责 |
|---|---|---|---|
| OceanWay Core / Execution Edge | 客户、产品和业务执行控制面 | 用户、企业、子账号、Developer Access Domain、商品目录、Surface、Run、钱包、账单、正式资产 | ProviderCredentialVersion、物理渠道选择 |
| Text Gateway Pool | UUMI/new-api 组成的私有文本网关池 | 文本、Embedding、Rerank 等协议适配、物理 Channel、流式传输,以及不可变 ProviderUsageEvidence / ProviderCostEvidence | 规范 MeterEvent / ProviderCostFact、客户产品目录、用户售价、钱包、正式资产 |
| Media Gateway Pool | oceanway-media-gateway 组成的私有媒体网关池 | 图片/视频 Provider 接入、Supply、ProviderCredentialVersion、媒体 Task、Provider Attempt、轮询恢复、结果归一化,以及不可变 ProviderUsageEvidence / ProviderCostEvidence | 规范 MeterEvent / ProviderCostFact、本地 User/CustomerGroup/APIKey 服务、模型广场、用户售价、钱包、正式资产 |
以下结论不再作为待决策项:
ai.oceanway.tech只承载无需登录的公开开发者中心,包括公开模型目录、文档、API 列表价、状态和进入控制台的入口;它不承载 App、密钥、用量、购买或账单管理。- 登录后的 Developer Control 固定在
console.oceanway.tech/ai,管理 Developer App、Environment、Service Account、DeveloperCredential、Webhook 和仅 API 用量;钱包、购买、订阅、账单和跨产品总览继续使用 Console 的统一商业与资源界面。 api.oceanway.tech/v1是独立的唯一公共机器入口,只接受 DeveloperCredential 或由 Console BFF 持有的短期 Playground Execution Grant,不接受 Customer Session 或门户页面请求。- UUMI/new-api 收敛为 Text Gateway Pool;它不再位于目标媒体执行主链路中。
oceanway-media-gateway是一个完整服务边界,直接连接图片和视频 Provider。- Media Gateway 内的 API、Registry、Dispatcher、Provider Adapter、Poller、Reconciler 和 Result Handling 是同一代码库与所有权边界内的模块,不是需要独立建设的四套平台。
- Text Pool 与 Media Pool 同级,互不级联,也不允许在运行中静默跨池降级。
最重要的产品边界
Media Gateway 后续不再提供,也不复制以下客户与商业能力:
- 任何本地 User/Customer 账号服务,包括本地管理员账号库;
- 客户组、用户分组或面向客户的渠道分组;
- API Key 的签发、自助管理、配额或客户鉴权服务;
- 面向客户的模型广场或模型商城;
- 用户售价、折扣、套餐、余额、订阅、订单和发票;
- OceanWay Workspace、Project、Canvas、Agent 或 MCP 的权限模型。
这些能力全部属于 OceanWay 共享核心域。Developer Access Domain 统一拥有 Developer App → Environment → Service Account → DeveloperCredential;其登录后控制面位于 console.oceanway.tech/ai。公开模型、文档和列表价由 ai.oceanway.tech 只读呈现,购买与账务由 Console 统一承载。Media Gateway 只验证 OceanWay Workload Principal 使用的短期 Workload Credential;内部运维使用 OceanWay 集中 SSO/RBAC 或基础设施 IAM,不落成本地用户。DeveloperCredential 只在 api.oceanway.tech/v1 的 Public API Edge 完成鉴权,绝不下发或转发到 Media Gateway。
Media Gateway 可以保留内部的 Provider 模型映射、Supply、Provider Account、ProviderCredentialVersion、能力约束、健康度、容量、路由策略和供应成本。它们是“内部供应目录”,不是 OceanWay 的公开模型商品。
目标拓扑
从产品表面看,公开发现、登录后管理和机器执行是三个明确入口;真正的模型执行统一进入 OceanWay Execution Edge。从基础设施看只有两个并列的私有网关边界。用户、浏览器、Developer App 和产品工作台都不能直接调用任一私有网关。
当前基线与目标状态
当前 pic-vps 上的 UUMI/new-api 已经承担实际模型接入,历史媒体调用可能仍经过该链路。这个事实应作为迁移基线记录,但不能再被描述为目标媒体架构。
oceanway-media-gateway 已具备媒体供应、版本化凭据、持久 Task/Attempt、路由快照、Dispatcher、Poller、Reconciler 和结果处理基础。目标不是再在它前后建设一套重复的 Adapter、Job Registry 或 Channel Layer,而是将其作为 Media Gateway Pool 的直接实现接入 OceanWay。
当前 UUMI/new-api 与 Media Gateway 可能已经返回名为 Usage、Cost 或 Cost Fact 的供应侧字段,但这些现有字段只能作为迁移输入,不能被认定为 OceanWay 的规范 MeterEvent 或 ProviderCostFact。目标契约要求两个 Gateway 先保存不可变 ProviderUsageEvidence / ProviderCostEvidence;关于 Usage/Cost 只向 Core 返回其完整内容寻址四元组,不返回 Evidence Payload 或规范 Fact,完整响应仍包含标准状态、AttemptRouteBinding 与 GatewayRouteSnapshot 四元组、执行锚点和受控结果。由 Metering 唯一完成规范化、幂等落账、更正与对账。该证据契约、Metering Writer 和结算闭环尚未实施,不能把本页目标状态解释成现有能力。
迁移期间允许旧媒体任务继续沿 UUMI/new-api 原路运行到终态;新的媒体模型按 Offering 逐个切换到 Media Gateway。不得在同一个 Attempt 中双写两个网关,也不得把已提交任务迁移到新网关。
三层调度职责
OceanWay Product Control
负责“卖什么、给谁看、按什么规则使用”:
- Logical Model、Model Offering 和稳定公开模型 ID;
web、api、internal等 Surface;- 能力、生命周期、协议、区域和数据策略;
- 面向用户的价格、套餐、折扣与合同;
- 企业、Workspace、Project、角色和预算;
- Offering 引用 Model Control 发布的 Model Deployment、Gateway Pool 与 Gateway Deployment 路由策略;Backend Model 映射只存在于对应私有 Gateway Route Snapshot。
codex-auto-review 一类模型可以只发布到 internal,因此不会进入网页或开发者公共目录。大量文本模型进入 API 时,也只会按 OceanWay 的能力、Family 和 Variant 组织,而不会把供应商原始 ID 平铺给用户。
OceanWay Execution Control
负责“一次业务调用应该怎样被可靠执行”:
- 创建 Run、Step、Execution Attempt 和 Output;
- 鉴权、配额、并发、预算预占与幂等;
- 根据冻结的 Offering Revision 选择 Text 或 Media Pool;
- 保存
gatewayDeploymentId和gatewayTaskId; - 接收或查询终态、登记正式资产;
- 将 Execution/Output 事实与 Gateway Evidence 引用提交给 Metering,并编排 Billing 的结算、释放、退款与待对账;
- 业务重试、用户取消意图、SSE 和客户 Webhook。
Private Gateway Execution
两个网关池分别负责自己的物理供应执行:
- Text Gateway 固定真实 Channel、Provider Model 和协议,返回流式内容并保存不可变 Provider Usage/Cost Evidence;响应中的 Usage/Cost Availability 两个严格联合均必填,只有各自
available分支返回对应 Evidence完整四元组。 - Media Gateway 固定 Supply、ProviderCredentialVersion、Provider Adapter 和请求快照,持久化媒体 Task 与 Provider Attempt,恢复长任务并保存不可变 Provider Usage/Cost Evidence;响应同样必须分别表达 available、not_reported、pending、unavailable 或 conflicting,不能用裸 Ref 的有无替代状态。
私有网关不得基于 OceanWay 用户余额或零售价改变路由,也不得自行创建 OceanWay Run、Asset 或账本记录。
Gateway Evidence 描述“供应商或网关实际报告了什么”,不是 OceanWay 计量事实。Gateway 不得铸造规范 MeterEvent / ProviderCostFact,也不得根据 Evidence、Observation、Poll 或 Callback 请求客户结算。Metering 是两类规范事实的唯一 Writer:它验证 Evidence 与 Execution Attempt 的绑定,统一单位与币种,执行幂等去重,并用追加式更正而不是改写历史事实。Billing 只消费具结算资格的 canonical MeterEvent、冻结 Price Snapshot 与 Billing Policy 执行客户账务;ProviderCostFact 只进入供应对账/毛利,不是 Billing 扣款输入。
每次 Gateway 受理 Attempt 前,必须先在读取客户 Payload 与任何 Provider Side Effect 之前按 (executionAttemptId, gatewayDeploymentId, AttemptExecutionManifest 完整四元组) 原子 reserve 唯一 GatewayAttemptDispatchSlot。Repository 首次生成稳定 gatewayAttemptDispatchSlotId + gatewayPreBindingRequestId;相同身份的请求、响应丢失重试或恢复必须返回同一 Slot/Request ID,Ref/Schema 相同但 Manifest Digest 不同视为冲突。Slot 只允许:
reserved
-> bound { AttemptRouteBinding }
| terminal_rejected { GatewayPreBindingRejectionFact }bound 与 Binding/Route/Invocation-or-Task/提交意图在同一 Gateway 事务 CAS 后,才允许调用 Provider;terminal_rejected 与两个 Pre-binding Availability Snapshot、Rejection Fact 在同一 Gateway 事务 CAS。两个终态吸收且严格互斥,不允许 rejected→bound、bound→rejected、第二个 Binding/Rejection 或换 Request ID 重入;reserved 崩溃恢复使用 Repository Lease/Fencing,且在终态提交前绝不能有 Provider Side Effect。重复调用命中 bound 只返回原 Binding,命中 terminal_rejected 只返回原 Rejection。Execution 收到终态拒绝后不得以同一 Attempt 重调;业务重试必须创建新的 Attempt,而 Gateway 的 Slot 约束仍作为最终防线。
用量与成本事实所有权
| 对象 | 唯一 Owner / Writer | 写入与更正规则 | 可驱动客户结算 |
|---|---|---|---|
ProviderUsageEvidence | 实际执行的 Text/Media Gateway | 从 Provider 响应、查询或账单来源追加;固定 source ref 与摘要;修订追加新 Evidence 并引用旧 ID | 否 |
ProviderCostEvidence | 实际执行的 Text/Media Gateway | 与对应 Invocation/Task/Provider Attempt 绑定;未知与缺失不能写成零;修订不可覆盖原证据 | 否 |
MeterEvent | OceanWay Metering | 从可信 Execution/Output 与可用 Evidence 规范化;按固定幂等键追加,冲突进入对账 | 是,作为 Billing 结算输入之一 |
ProviderCostFact | OceanWay Metering | 从 Provider Cost Evidence 规范单位/币种;更正追加替代 Fact,保留完整 lineage | 否,只用于供应对账、成本归集与毛利 |
| Operational Observation | 生产者提交、Core Operations 接受 | 只记录运行观测和 Evidence ref;不能复制 Evidence Payload 或声明规范 Fact | 否 |
providerUsageEvidenceRef / providerCostEvidenceRef 是不透明、稳定且按 Workload 授权的 Gateway Evidence 引用,不是签名下载 URL。Metering 只能通过版本化 Evidence Read Contract 解析它们,不能直连 Gateway 数据库。所有 Gateway Response 与 GatewayDiagnostic 都必须分别返回以下严格判别联合,不能用可空 Ref 压缩状态:
availabilityCommon =
availabilityRef / availabilitySchemaVersion
availabilityDigestAlgorithmVersion = jcs-sha256-v1
availabilityDigest / stateVersion
stateReasonCode
evidenceDimensionKey = attempt_aggregate@1
availabilityIdentity =
{ scope=attempt_bound; executionAttemptId; gatewayDeploymentId;
attemptRouteBindingRef; attemptRouteBindingSchemaVersion;
attemptRouteBindingDigestAlgorithmVersion; attemptRouteBindingDigest;
gatewayRouteSnapshotRef; gatewayRouteSnapshotSchemaVersion;
gatewayRouteSnapshotDigestAlgorithmVersion; gatewayRouteSnapshotDigest }
| { scope=pre_binding_no_execution; gatewayAttemptDispatchSlotId;
gatewayPreBindingRequestId; gatewayDeploymentId }
supersedesAvailability =
{ state=root }
| { state=supersedes; supersedesAvailabilityRef; supersedesAvailabilitySchemaVersion;
supersedesAvailabilityDigestAlgorithmVersion; supersedesAvailabilityDigest;
supersedesAvailabilityStateVersion }
usageEvidenceAvailability =
availabilityCommon & { providerEvidenceKind=provider_usage } &
( { state=available; providerUsageEvidenceRef; providerUsageEvidenceSchemaVersion;
providerUsageEvidenceDigestAlgorithmVersion; providerUsageEvidenceDigest }
| { state=not_reported|pending|unavailable|conflicting } )
costEvidenceAvailability =
availabilityCommon & { providerEvidenceKind=provider_cost } &
( { state=available; providerCostEvidenceRef; providerCostEvidenceSchemaVersion;
providerCostEvidenceDigestAlgorithmVersion; providerCostEvidenceDigest }
| { state=not_reported|pending|unavailable|conflicting } )每个分支都必须携带不可变 Availability Snapshot 的 Ref/Schema Version/Digest Algorithm Version/Digest/State Version、Kind、固定 Dimension、严格身份与前驱联合;attempt_bound 的 Binding 与 Route 都使用完整四元组。available 另外要求且只允许对应 Evidence 完整四元组,其他分支禁止携带两类 Evidence Ref、Schema、Digest 或伪造零值。Snapshot 必须与其 Attempt/Deployment/Binding/Route 逐项绑定。Binding 创建前且可证明未发生 Provider Side Effect 的拒绝只能创建 pre_binding_no_execution Snapshot:以同一 Attempt 唯一 Dispatch Slot 中、Gateway 在读取客户 Payload 前生成并返回的稳定 gatewayAttemptDispatchSlotId + gatewayPreBindingRequestId 作为身份,只允许 stateVersion=1 + supersedesAvailability.state=root + state=not_reported|unavailable,禁止 Attempt/Binding/Route/Evidence 字段;它仅用于请求诊断,永远不能进入 Metering、Eligibility 或 Billing Finalization。若不能证明无 Side Effect,必须先将同一 Slot CAS 为 bound、创建 Attempt/Binding 并使用 attempt_bound,不能借 pre-binding 分支绕过证据链。not_reported 表示受信来源在该权威状态版本没有报告,pending 表示仍可能形成证据,unavailable 表示冻结 Route/Adapter 明确不提供或证据无法取得,conflicting 表示多个来源尚未收敛;任何状态都不能生成零 Usage/Cost 或虚构 Fact。只有冻结 Billing Policy/Finalization Rule 明确把权威 attempt-bound not_reported | unavailable 解释为某个 Charge Dimension 的终态无用量时,才可形成 Terminal-none Eligibility Decision;pending | conflicting 永远阻塞成功终局。最终字段、枚举与状态转换以固定 Contracts Release 为准。
GatewayEvidenceAvailabilitySnapshot@1 是对应 Gateway 的不可变事实,不是 Observation。其严格 Candidate 覆盖上述 availabilityIdentity 联合、Evidence Kind、固定 Dimension、State Version、State/Reason Code,以及 available 时的 Current Evidence Head完整四元组和严格 supersedesAvailability 联合;使用上述 Digest 算法计算内容摘要,排除 Repository 生成的 Ref/RecordedAt 和摘要字段自身。attempt_bound 每条链只允许一个 {state=root} Snapshot;之后必须以 {state=supersedes} 携带直接前驱的完整 Ref/Schema Version/Digest Algorithm Version/Digest/State Version,且五项必须与前驱不可变记录逐项相等;任何半联合都拒绝。Repository 以 Candidate Digest 生成稳定 Idempotency Key,首次 insert 生成 Ref/Time,并在同一事务以 CAS 推进 (Attempt, Gateway Deployment, Evidence Kind, attempt_aggregate@1) 唯一 Current Availability Pointer;状态不变的重放返回原 Snapshot,同版本异 Candidate、第二 Root、分叉、循环、错版本或摘要、前驱 State Version 错配、State Version 回退、跳过当前前驱或 Pointer 竞争进入 conflicting。Snapshot 的 Attempt/Deployment/Binding/Route 必须与其所指 Evidence(如有)以及冻结 AttemptRouteBinding 逐项相等;非 Available 分支不得暗示一个 Evidence Head。pre_binding_no_execution 使用独立唯一键 (gatewayAttemptDispatchSlotId, gatewayPreBindingRequestId, gatewayDeploymentId, Evidence Kind, attempt_aggregate@1),只允许不可变 Root 和上述两个非 Available 状态,不创建可供 Billing 验证的 Current Attempt Pointer。Response 与 Operational Observation 只能引用/复制当前低敏 Snapshot 摘要,不能创建或改写它。Contracts 提供两种 Identity 的 Golden、Available/Not Reported/Pending/Unavailable/Conflicting 与 Root/Supersession/并发 CAS、跨 Scope/Attempt/Binding/Route/Kind/Dimension 负测。
Attempt-bound Current推进还必须形成面向Metering的必达输入,而不是依赖同步响应、Poll或best-effort GatewayDiagnostic。Gateway在追加Evidence(若有)、Availability Snapshot和CAS推进Current/Active Head的同一Gateway事务中,追加Contracts注册的gateway.evidence-availability.current-changed@1 Event、冻结Delivery Set并创建metering_input_processor Mandatory Delivery;任一步失败全部回滚。Pre-binding Snapshot严格不产生该Event。Payload是封闭DTO:
GatewayEvidenceAvailabilityCurrentChanged@1 = {
executionAttemptId / gatewayDeploymentId
attemptExecutionManifestRef / attemptExecutionManifestSchemaVersion
attemptExecutionManifestDigestAlgorithmVersion / attemptExecutionManifestDigest
attemptRouteBindingRef / attemptRouteBindingSchemaVersion
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest
providerEvidenceKind = provider_usage | provider_cost
evidenceDimensionKey
currentAvailabilityRef / currentAvailabilitySchemaVersion
currentAvailabilityDigestAlgorithmVersion / currentAvailabilityDigest / currentAvailabilityStateVersion
currentEvidence =
{ state=none }
| { state=available; evidenceRef / evidenceSchemaVersion;
evidenceDigestAlgorithmVersion / evidenceDigest }
supersedesAvailability =
{ state=root }
| { state=supersedes; ref; schemaVersion; digestAlgorithmVersion; digest; stateVersion }
}Event的aggregateId由Contracts按executionAttemptId + gatewayDeploymentId + providerEvidenceKind + evidenceDimensionKey确定性派生,aggregateRevision=currentAvailabilityStateVersion。Payload必须与Current Snapshot、Active Head、Binding/Route及其Attempt Manifest四元组逐项相等,Available/None联合与Snapshot状态同构;同一Current事务只允许一条同摘要Event。Metering Consumer只有在本地Inbox事务单调推进对应MeteringAttemptInputFence Watermark、insert-or-compare可恢复Work并写Versioned Consumer Receipt后才Ack;同Event同摘要幂等,较旧Revision可already_observed,同Revision异摘要或身份错配隔离。Execution Eligibility Event先到时Fence等待Gateway Usage,Gateway Event先到时等待Execution Eligibility;Cost Work不等待客户Eligibility。任一后继Availability Head都会用新Revision重新置Pending,不能被旧Receipt或已完成Work吞掉。
GatewayDiagnostic/Error Observation继续只用于运维;它们即使丢失也不影响上述Mandatory Event,且不能代替Event、推进Metering Watermark或驱动结算。必须覆盖A1/E1处理完成 → A2/E2 Current提交后同步响应与Observation丢失 → 无后续Poll仍由Outbox重建Eligibility/ProviderCost/SettlementInput,以及Event Ack后Worker崩溃、A2先于旧Work完成、Usage/Cost乱序、跨Attempt/Kind/Dimension重放和Event/Current原子回滚测试。
Binding 前的确定性拒绝另有执行协议事实,不能把诊断 Snapshot 偷换成计量输入:
GatewayPreBindingRejectionFact@1 {
gatewayPreBindingRejectionFactRef / gatewayPreBindingRejectionFactSchemaVersion
gatewayPreBindingRejectionFactDigestAlgorithmVersion = jcs-sha256-v1
gatewayPreBindingRejectionFactDigest
gatewayAttemptDispatchSlotId
gatewayPreBindingRequestId / gatewayDeploymentId
executionAttemptId
attemptExecutionManifestRef / attemptExecutionManifestSchemaVersion
attemptExecutionManifestDigestAlgorithmVersion / attemptExecutionManifestDigest
rejectionPhase = pre_binding
providerSideEffect = none
rejectionReasonCode
usageAvailabilityRef / usageAvailabilitySchemaVersion
usageAvailabilityDigestAlgorithmVersion / usageAvailabilityDigest / usageAvailabilityStateVersion
costAvailabilityRef / costAvailabilitySchemaVersion
costAvailabilityDigestAlgorithmVersion / costAvailabilityDigest / costAvailabilityStateVersion
rejectedAt
}Gateway 只有在 Provider Side Effect 之前、同一 Slot 仍为 reserved、未创建 Binding/Route/Invocation/Task,且 Usage/Cost 两个 Pre-binding Snapshot 均为同一 Slot/Request/Deployment 下的 stateVersion=1 + root + not_reported|unavailable 时,才能在同一 Gateway 事务追加该 Fact并将 Slot CAS 为 terminal_rejected 后返回。Fact 的严格 Candidate 摘要排除 Repository Ref/Time与摘要自身;providerSideEffect=none 是封闭枚举,不接受 unknown。同一 Slot/Request 只允许一条 Fact;Slot 已 bound、未知提交状态、已创建 Binding、任一 Provider 请求可能发出或两个 Snapshot 身份不等时必须拒绝铸造。
available 中的 Evidence完整四元组必须指向 Availability Snapshot stateVersion所见、与 Attempt + Deployment + Binding + Route + Evidence Kind/固定 Dimension对应的唯一 Current Active Head;历史 Head或历史 Availability Snapshot只读可追溯,不能重新公告为当前。Gateway状态机以同一 CAS推进 State Version、Current Availability Pointer与 Active Head四元组,先到新 Head、后到旧 Poll/Callback时只幂等确认旧 Evidence,禁止把 Active Head或状态倒退。Metering/Finalization收到 Snapshot时只能调用下述验证操作检查 Availability前驱链与 Evidence Supersession Chain到 Current Pointer;链暂不完整时等待,分叉、声明版本/摘要与记录不等或四元组非 Current的确定性矛盾返回内容寻址GatewayEvidenceConflictFact@1并令消费Work保持Blocked,不能挑一个较新的时间戳猜测,也不能由Gateway创建Operations Case。Finalization先固定 Input Manifest,再由 Gateway在锁定 Current Pointer的线性化点逐项验证并签发 Receipt;该点之后到达的新 Snapshot是明确的 post-boundary correction,不会追溯使 Receipt失效,而由终局后 Settlement State处理。
Gateway Availability 与 Evidence Read Contract
Gateway 对按操作和Purpose定向授权的领域Workload提供版本化内部操作;Availability/Evidence/Validation主体仍限Metering/Billing,Binding bootstrap另允许下文受限Execution与Operations分支。任何调用方都不能直连 Gateway 数据库:
GatewayEvidenceConflictFact@1 = {
gatewayEvidenceConflictFactRef / gatewayEvidenceConflictFactSchemaVersion
gatewayEvidenceConflictFactDigestAlgorithmVersion = jcs-sha256-v1
gatewayEvidenceConflictFactDigest
executionAttemptId / gatewayDeploymentId
attemptRouteBindingRef / attemptRouteBindingSchemaVersion
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest
providerEvidenceKind / evidenceDimensionKey
availabilityRef / availabilitySchemaVersion
availabilityDigestAlgorithmVersion / availabilityDigest / availabilityStateVersion
conflictStage = source_schema | source_identity | binding_validation | route_validation |
availability_validation | evidence_validation | current_pointer | receipt_repository
conflictContext =
{ kind=metering_source_event_bootstrap;
sourceEventId / sourceEventType / sourceEventSchemaVersion;
sourceEventEnvelopeDigestAlgorithmVersion / sourceEventEnvelopeSha256 }
| { kind=eligibility_consumption; eligibilityValidationOperationId;
eligibilityBasisDigestAlgorithmVersion / eligibilityBasisDigest;
eligibilityValidationScope = {
executionAttemptId / gatewayDeploymentId;
attemptRouteBindingRef / attemptRouteBindingSchemaVersion;
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest;
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion;
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest;
providerEvidenceKind=provider_usage / evidenceDimensionKey;
availabilityRef / availabilitySchemaVersion;
availabilityDigestAlgorithmVersion / availabilityDigest / availabilityStateVersion } }
| { kind=provider_cost_fact; providerCostValidationOperationId;
providerCostFactCandidateDigestAlgorithmVersion / providerCostFactCandidateDigest;
providerCostValidationScope = {
executionAttemptId / gatewayDeploymentId;
attemptRouteBindingRef / attemptRouteBindingSchemaVersion;
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest;
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion;
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest;
providerEvidenceKind=provider_cost / sourceEvidenceDimensionKey } }
| { kind=billing_finalization; billingFinalizationOperationId;
finalizationInputManifestRef / finalizationInputManifestSchemaVersion;
finalizationInputManifestDigestAlgorithmVersion / finalizationInputManifestDigest }
| { kind=operations_reconciliation_evidence_read;
reconciliationEvidenceReadGrantRef / reconciliationEvidenceReadGrantSchemaVersion;
reconciliationEvidenceReadGrantDigestAlgorithmVersion / reconciliationEvidenceReadGrantDigest;
reconciliationCaseRef / caseRevision;
caseEvidenceManifestRef / caseEvidenceManifestSchemaVersion;
caseEvidenceManifestDigestAlgorithmVersion / caseEvidenceManifestDigest;
historicalAvailabilityRef / historicalAvailabilitySchemaVersion;
historicalAvailabilityDigestAlgorithmVersion / historicalAvailabilityDigest;
historicalAvailabilityStateVersion }
reasonCode
detectedAt
}
GatewayBindingConflictFact@1 = {
gatewayBindingConflictFactRef / gatewayBindingConflictFactSchemaVersion
gatewayBindingConflictFactDigestAlgorithmVersion = jcs-sha256-v1
gatewayBindingConflictFactDigest
requestedAttemptRouteBindingRef / requestedAttemptRouteBindingSchemaVersion
requestedAttemptRouteBindingDigestAlgorithmVersion / requestedAttemptRouteBindingDigest
expectedExecutionAttemptId / expectedGatewayDeploymentId
bindingReadPurpose =
{ kind=domain_fact_verification; operationId; callerDomain=execution|metering|billing }
| { kind=operations_observation_intake; observationId; observationSchemaVersion;
submissionDigestAlgorithmVersion; submissionPayloadSha256; operationId? }
| { kind=operations_observation_projection; observationId; observationSchemaVersion;
observationDigestAlgorithmVersion; acceptedEnvelopeSha256; operationId? }
conflictStage = source_schema | source_identity | repository_binding
reasonCode
detectedAt
}
GatewayPreBindingConflictFact@1 = {
gatewayPreBindingConflictFactRef / gatewayPreBindingConflictFactSchemaVersion
gatewayPreBindingConflictFactDigestAlgorithmVersion = jcs-sha256-v1
gatewayPreBindingConflictFactDigest
gatewayAttemptDispatchSlotId / gatewayPreBindingRequestId / gatewayDeploymentId
providerEvidenceKind / evidenceDimensionKey
expectedExecution =
{ state=not_applicable }
| { state=identified; executionAttemptId;
attemptExecutionManifestRef / attemptExecutionManifestSchemaVersion;
attemptExecutionManifestDigestAlgorithmVersion / attemptExecutionManifestDigest }
conflictStage = source_schema | source_identity | slot_state | repository_binding
reasonCode
detectedAt
}
readAttemptRouteBinding(
attemptRouteBindingRef, attemptRouteBindingSchemaVersion,
attemptRouteBindingDigestAlgorithmVersion, attemptRouteBindingDigest,
expected executionAttemptId, gatewayDeploymentId,
bindingReadPurpose =
{ kind=domain_fact_verification; operationId; callerDomain=execution|metering|billing }
| { kind=operations_observation_intake; observationId; observationSchemaVersion;
submissionDigestAlgorithmVersion; submissionPayloadSha256; operationId? }
| { kind=operations_observation_projection; observationId; observationSchemaVersion;
observationDigestAlgorithmVersion; acceptedEnvelopeSha256; operationId? }
)
-> { result=found; binding=AttemptRouteBinding@N }
| { result=not_found }
| { result=conflicting;
gatewayBindingConflictFactRef / gatewayBindingConflictFactSchemaVersion;
gatewayBindingConflictFactDigestAlgorithmVersion / gatewayBindingConflictFactDigest }
readAvailability(
availabilityRef, availabilitySchemaVersion,
expected executionAttemptId, gatewayDeploymentId,
attemptRouteBindingRef, attemptRouteBindingSchemaVersion,
attemptRouteBindingDigestAlgorithmVersion, attemptRouteBindingDigest,
gatewayRouteSnapshotRef, gatewayRouteSnapshotSchemaVersion,
gatewayRouteSnapshotDigestAlgorithmVersion, gatewayRouteSnapshotDigest,
providerEvidenceKind, evidenceDimensionKey=attempt_aggregate@1,
sourceReadPurpose =
{ kind=metering_source_event_bootstrap;
sourceEventId; sourceEventType=gateway.evidence-availability.current-changed@1;
sourceEventSchemaVersion; sourceEventEnvelopeDigestAlgorithmVersion;
sourceEventEnvelopeSha256; sourceEventAggregateId; sourceEventAggregateRevision }
| { kind=billing_finalization; billingFinalizationOperationId;
finalizationInputManifestRef / finalizationInputManifestSchemaVersion;
finalizationInputManifestDigestAlgorithmVersion / finalizationInputManifestDigest }
)
-> { result=found; availability=GatewayEvidenceAvailabilitySnapshot@1 }
| { result=not_found }
| { result=conflicting;
gatewayEvidenceConflictFactRef / gatewayEvidenceConflictFactSchemaVersion;
gatewayEvidenceConflictFactDigestAlgorithmVersion / gatewayEvidenceConflictFactDigest }
readEvidence(
evidenceRef, evidenceSchemaVersion, evidenceDigestAlgorithmVersion, evidenceDigest,
expected executionAttemptId, gatewayDeploymentId,
attemptRouteBindingRef, attemptRouteBindingSchemaVersion,
attemptRouteBindingDigestAlgorithmVersion, attemptRouteBindingDigest,
gatewayRouteSnapshotRef, gatewayRouteSnapshotSchemaVersion,
gatewayRouteSnapshotDigestAlgorithmVersion, gatewayRouteSnapshotDigest,
executionAnchor,
providerEvidenceKind, evidenceDimensionKey=attempt_aggregate@1,
expectedAvailabilityRef, expectedAvailabilitySchemaVersion,
expectedAvailabilityDigestAlgorithmVersion, expectedAvailabilityDigest,
expectedAvailabilityStateVersion,
sourceReadPurpose =
{ kind=metering_source_event_bootstrap;
sourceEventId; sourceEventType=gateway.evidence-availability.current-changed@1;
sourceEventSchemaVersion; sourceEventEnvelopeDigestAlgorithmVersion;
sourceEventEnvelopeSha256; sourceEventAggregateId; sourceEventAggregateRevision }
| { kind=billing_finalization; billingFinalizationOperationId;
finalizationInputManifestRef / finalizationInputManifestSchemaVersion;
finalizationInputManifestDigestAlgorithmVersion / finalizationInputManifestDigest }
)
-> { result=found;
evidenceDigestAlgorithmVersion; evidenceDigest;
evidence=GatewayEvidence@N }
| { result=not_current;
currentAvailabilityRef; currentAvailabilitySchemaVersion;
currentAvailabilityDigestAlgorithmVersion; currentAvailabilityDigest;
currentAvailabilityStateVersion }
| { result=not_found }
| { result=conflicting;
gatewayEvidenceConflictFactRef / gatewayEvidenceConflictFactSchemaVersion;
gatewayEvidenceConflictFactDigestAlgorithmVersion / gatewayEvidenceConflictFactDigest }
readEvidenceForReconciliation(
ReconciliationEvidenceReadGrant完整四元组与签名,
reconciliationCaseRef, caseRevision,
caseEvidenceManifestRef, caseEvidenceManifestSchemaVersion,
caseEvidenceManifestDigestAlgorithmVersion, caseEvidenceManifestDigest,
evidenceRef, evidenceSchemaVersion, evidenceDigestAlgorithmVersion, evidenceDigest,
expected executionAttemptId, gatewayDeploymentId,
attemptRouteBindingRef, attemptRouteBindingSchemaVersion,
attemptRouteBindingDigestAlgorithmVersion, attemptRouteBindingDigest,
gatewayRouteSnapshotRef, gatewayRouteSnapshotSchemaVersion,
gatewayRouteSnapshotDigestAlgorithmVersion, gatewayRouteSnapshotDigest,
executionAnchor,
providerEvidenceKind, evidenceDimensionKey=attempt_aggregate@1,
historicalAvailabilityRef, historicalAvailabilitySchemaVersion,
historicalAvailabilityDigestAlgorithmVersion, historicalAvailabilityDigest,
historicalAvailabilityStateVersion
)
-> { result=found; evidence=GatewayEvidence@N;
historicalAvailability=GatewayEvidenceAvailabilitySnapshot@1 }
| { result=not_found }
| { result=conflicting;
gatewayEvidenceConflictFactRef / gatewayEvidenceConflictFactSchemaVersion;
gatewayEvidenceConflictFactDigestAlgorithmVersion / gatewayEvidenceConflictFactDigest }
readPreBindingAvailability(
availabilityRef, availabilitySchemaVersion,
expected gatewayAttemptDispatchSlotId, gatewayPreBindingRequestId, gatewayDeploymentId,
providerEvidenceKind, evidenceDimensionKey=attempt_aggregate@1
)
-> { result=found; availability=GatewayEvidenceAvailabilitySnapshot@1(scope=pre_binding_no_execution) }
| { result=not_found }
| { result=conflicting;
gatewayPreBindingConflictFactRef / gatewayPreBindingConflictFactSchemaVersion;
gatewayPreBindingConflictFactDigestAlgorithmVersion / gatewayPreBindingConflictFactDigest }
readPreBindingRejectionFact(
gatewayPreBindingRejectionFactRef, gatewayPreBindingRejectionFactSchemaVersion,
expected gatewayAttemptDispatchSlotId, gatewayPreBindingRequestId, gatewayDeploymentId, executionAttemptId,
attemptExecutionManifestRef, attemptExecutionManifestSchemaVersion,
attemptExecutionManifestDigestAlgorithmVersion, attemptExecutionManifestDigest
)
-> { result=found; fact=GatewayPreBindingRejectionFact@1 }
| { result=not_found }
| { result=conflicting;
gatewayPreBindingConflictFactRef / gatewayPreBindingConflictFactSchemaVersion;
gatewayPreBindingConflictFactDigestAlgorithmVersion / gatewayPreBindingConflictFactDigest }
validateAvailabilityCurrent(
executionAttemptId, gatewayDeploymentId,
attemptRouteBindingRef, attemptRouteBindingSchemaVersion,
attemptRouteBindingDigestAlgorithmVersion, attemptRouteBindingDigest,
gatewayRouteSnapshotRef, gatewayRouteSnapshotSchemaVersion,
gatewayRouteSnapshotDigestAlgorithmVersion, gatewayRouteSnapshotDigest,
providerEvidenceKind, evidenceDimensionKey=attempt_aggregate@1,
expectedAvailabilityRef, expectedSchemaVersion,
expectedDigestAlgorithmVersion, expectedDigest, expectedStateVersion,
expectedEvidence =
{ state=none }
| { state=available; evidenceRef / evidenceSchemaVersion;
evidenceDigestAlgorithmVersion / evidenceDigest },
validationPurpose =
{ kind=eligibility_consumption; eligibilityValidationOperationId;
eligibilityBasisDigestAlgorithmVersion; eligibilityBasisDigest }
| { kind=provider_cost_fact; providerCostValidationOperationId;
providerCostFactCandidateDigestAlgorithmVersion; providerCostFactCandidateDigest;
providerCostValidationScope = {
executionAttemptId; gatewayDeploymentId;
attemptRouteBindingRef / attemptRouteBindingSchemaVersion;
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest;
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion;
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest;
providerEvidenceKind=provider_cost; sourceEvidenceDimensionKey };
providerCostEvidenceRef; providerCostEvidenceSchemaVersion;
providerCostEvidenceDigestAlgorithmVersion; providerCostEvidenceDigest }
| { kind=billing_finalization; billingFinalizationOperationId;
finalizationInputManifestRef; finalizationInputManifestSchemaVersion;
finalizationInputManifestDigestAlgorithmVersion; finalizationInputManifestDigest }
)
-> { result=current; validationReceiptRef; validationReceiptSchemaVersion;
validationReceiptDigestAlgorithmVersion; validationReceiptDigest;
validationPurpose;
validatedAvailabilityRef; validatedSchemaVersion;
validatedAvailabilityDigestAlgorithmVersion; validatedDigest;
validatedStateVersion; validatedState;
validatedEvidence =
{ state=none }
| { state=available;
evidenceRef / evidenceSchemaVersion;
evidenceDigestAlgorithmVersion / evidenceDigest } }
| { result=not_current; currentAvailabilityRef; currentSchemaVersion;
currentDigestAlgorithmVersion; currentDigest; currentStateVersion; currentState }
| { result=conflicting;
gatewayEvidenceConflictFactRef / gatewayEvidenceConflictFactSchemaVersion;
gatewayEvidenceConflictFactDigestAlgorithmVersion / gatewayEvidenceConflictFactDigest }
readRouteCostBinding(
executionAttemptId, gatewayDeploymentId,
attemptRouteBindingRef, attemptRouteBindingSchemaVersion,
attemptRouteBindingDigestAlgorithmVersion, attemptRouteBindingDigest,
gatewayRouteSnapshotRef, gatewayRouteSnapshotSchemaVersion,
gatewayRouteSnapshotDigestAlgorithmVersion, gatewayRouteSnapshotDigest,
routeCostReadPurpose =
{ kind=metering_source_event_bootstrap;
sourceEventId; sourceEventType=gateway.evidence-availability.current-changed@1;
sourceEventSchemaVersion; sourceEventEnvelopeDigestAlgorithmVersion;
sourceEventEnvelopeSha256; sourceEventAggregateId; sourceEventAggregateRevision }
)
-> { result=found; binding=GatewayRouteCostBinding@1 {
routeCostBindingRef / routeCostBindingSchemaVersion
routeCostBindingDigestAlgorithmVersion = jcs-sha256-v1
routeCostBindingDigest
routeSnapshotRef / routeSnapshotSchemaVersion
routeSnapshotDigestAlgorithmVersion / routeSnapshotDigest
executionAttemptId / gatewayDeploymentId
attemptRouteBindingRef / attemptRouteBindingSchemaVersion
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest
providerCostMappingRevisionId / providerCostNormalizationPolicyVersion
} }
| { result=not_found }
| { result=conflicting;
gatewayEvidenceConflictFactRef / gatewayEvidenceConflictFactSchemaVersion;
gatewayEvidenceConflictFactDigestAlgorithmVersion / gatewayEvidenceConflictFactDigest }
validateRouteCostBinding(
expected GatewayRouteCostBinding@1 identity, digest algorithm version and digest,
expected providerCostMappingRevisionId,
expected providerCostNormalizationPolicyVersion,
providerCostValidationScope,
providerCostValidationOperationId,
providerCostFactCandidateDigestAlgorithmVersion,
providerCostFactCandidateDigest
)
-> { result=valid; validationReceiptRef; validationReceiptSchemaVersion;
validationReceiptDigestAlgorithmVersion; validationReceiptDigest;
providerCostValidationScope;
providerCostValidationOperationId;
providerCostFactCandidateDigestAlgorithmVersion; providerCostFactCandidateDigest;
validatedRouteCostBindingRef; validatedRouteCostBindingSchemaVersion;
validatedRouteCostBindingDigestAlgorithmVersion; validatedRouteCostBindingDigest;
validatedRouteSnapshotRef; validatedRouteSnapshotSchemaVersion;
validatedRouteSnapshotDigestAlgorithmVersion; validatedRouteSnapshotDigest;
validatedProviderCostMappingRevisionId;
validatedProviderCostNormalizationPolicyVersion }
| { result=not_valid; reasonCode }GatewayEvidenceConflictFact@1与GatewayBindingConflictFact@1都是Gateway Owner追加的内容寻址事实:摘要覆盖除Repository-owned Ref、detectedAt和摘要自身外的全部严格字段;Repository按摘要和所请求Source/Context唯一insert-or-compare,相同请求与冲突正文重放返回首次四元组,同Ref异摘要或同Context异正文继续隔离。每个Read的conflicting必须返回与该请求完整Expected身份、Purpose/Operation或Event/Grant上下文逐项相等的Fact,调用方重算摘要后才能写Blocked/Decision;临时网络、锁、容量或Owner不可用只返回retryable且不得铸造Conflict Fact。readAvailability覆盖Available与非Available Source Bootstrap;readRouteCostBinding覆盖Provider Cost Bootstrap,因此两条路径都不再依赖HTTP错误猜测确定性冲突。
validateRouteCostBinding刻意只有valid | not_valid:其请求不携带Availability五元组,因此不能返回必填Availability的GatewayEvidenceConflictFact@1,也不能读取另一验证端点的Current状态来补值。Route/Mapping/Normalization或Receipt构造的确定性失败由Metering写ProviderCostProcessingConflictEvidence@1.cause=metering_deterministic_validation、validationStage=route_validation_receipt和冲突Candidate带算法摘要,再以Provider Cost Lane外层Blocked Cause收敛;Gateway Source/Repository本身的冲突必须更早由readRouteCostBinding返回完整Conflict Fact。暂态失败仍只返回retryable且不写领域Fact。
eligibilityValidationOperationId 不是 Metering Worker 的随机请求 ID。Contracts 按固定 Namespace 对 purpose=eligibility_consumption + Eligibility Basis带算法摘要 + eligibilityValidationScope 确定性派生;其中 Scope 恰好由本次请求与 Gateway 冻结记录共同持有的 executionAttemptId + gatewayDeploymentId + AttemptRouteBinding完整四元组 + GatewayRouteSnapshot完整四元组 + providerEvidenceKind=provider_usage + evidenceDimensionKey + Usage Availability完整五元组 组成。Run/Step/Charge Dimension/Billing Policy等业务语义已由 Basis摘要承诺,不重复复制进 Gateway Token。Gateway逐项比较受信 JWT Scope、请求和冻结记录并复算 Operation,Purpose中的值不等时拒绝。相同 Basis/Scope在Receipt提交后崩溃或响应丢失时必须返回首次Receipt,Basis或Availability Head改变则派生新Operation;Receipt Digest覆盖完整 Scope和Operation,且不能反向引用最终Eligibility Decision或其Idempotency Key。
providerCostValidationOperationId 由 Contracts 固定 Namespace 对 purpose=provider_cost_fact + ProviderCostFact Candidate带算法摘要 + providerCostValidationScope 确定性派生。共享 Scope恰好包含两个验证端都能从请求和冻结记录验证的 executionAttemptId + gatewayDeploymentId + AttemptRouteBinding完整四元组 + GatewayRouteSnapshot完整四元组 + providerEvidenceKind=provider_cost + sourceEvidenceDimensionKey;其中sourceEvidenceDimensionKey必须逐项等于Gateway Cost Evidence和Availability请求里的evidenceDimensionKey,不能只做显示别名。providerCostDimensionKey、Mapping与Normalization等专属业务字段由 Candidate摘要和各自Receipt目标承诺,不伪装成两个端点都可独立验证的公共Claim。validateAvailabilityCurrent与validateRouteCostBinding两项验证请求、短期JWT及两份Receipt必须逐项携带同一共享Scope、Operation和Candidate摘要;前序Source Read使用独立Event-bound Bootstrap Scope。每份Receipt另行绑定自己的Availability/Evidence或Route/Mapping目标,并使用不同Receipt Schema与Idempotency Namespace,不能因Operation相同而互相替代。同 Candidate/Scope重放返回原 Receipt,任一改变都派生新Operation;随机Operation、共享Scope错配、同Operation异Candidate或两份Receipt Operation不等均拒绝。Candidate不含该Operation或Receipt,因此链路保持 Candidate → Digest → Validation Operation → 两份 Receipt → ProviderCostFact 单向无环。
readAvailability/validateAvailabilityCurrent 只接受 scope=attempt_bound,是Gateway attempt-bound Usage/Cost Availability的消费入口;Metering同时使用Usage与Cost,Billing Finalization只允许Usage分支。传入 pre-binding Ref 必须以 scope_not_billable 拒绝。两者的授权阶段严格分离:Metering第一次解引用只能使用已由Inbox接受的gateway.evidence-availability.current-changed@1完整Event身份与Envelope摘要作为metering_source_event_bootstrap,不能被要求预先提供尚未读到正文、无法构造的Eligibility Basis或ProviderCost Candidate;Billing则只能使用已持久Finalization Work和Input Manifest的billing_finalization分支,且providerEvidenceKind=provider_usage。Bootstrap只返回该Event明确列出的不可变Snapshot正文,不签发Current Receipt。readPreBindingAvailability 只供 Operations Intake/受限诊断验证完整性,不返回 Current Attempt Receipt,也不能被其结果直接构造 Eligibility Decision 或 Finalization Manifest。Execution 若要终结一个 Binding 前拒绝的 Attempt,只能使用精确 Execution Workload Audience/Attempt Scope 调用 readPreBindingRejectionFact,逐项验证 Fact、唯一 Dispatch Slot 终态与两个 Snapshot 摘要后,在自己的 Repository 追加 AttemptNotDispatchedFact@1;Metering/Billing 不能直接消费 Gateway Rejection Fact。
readEvidence 是 Metering获取下文严格 Evidence正文的唯一Current接口。合法首读使用与readAvailability相同的metering_source_event_bootstrap,Gateway先从自身不可变Outbox记录重算并验证Event Envelope摘要,再要求Event Payload中的Attempt/Deployment/Binding/Route/Kind/Dimension、Availability五元组与Available分支Evidence四元组和请求逐项相等;调用方不能换成同Attempt另一条Event、另一Kind或另一Head。Gateway在同一只读事务中验证 Availability为 attempt_bound + available、Expected Snapshot仍是 Current、其 Active Evidence Head完整四元组精确等于请求 Evidence,并逐项比较 Attempt/Deployment/Binding/Route/Anchor/Kind/Dimension后才返回 DTO。返回的 Evidence Digest覆盖完整严格 Evidence Candidate(排除 Repository-owned Ref/Time和摘要自身),算法/Schema未知、错类 Ref、非 Current、摘要或执行身份错配使用上面的显式结果,不能返回部分正文或零值。该读取只让 Metering构造Basis/Candidate;Metering仍须据正文确定性派生Operation,再取得绑定同一Basis/Candidate/Evidence的相应用途 Availability Receipt,以及 Provider Cost路径的 Route Receipt,才能写规范 Fact。单独读取成功不构成可持久的 Current线性化证据。
历史 Head只能使用独立 readEvidenceForReconciliation。Operations签发的短期 ReconciliationEvidenceReadGrant@1必须绑定 Case/Revision、CaseEvidenceManifest完整四元组、Manifest内一条完整 Gateway Evidence Link、目标 Gateway Audience、调用 Workload、唯一 JTI与有效期;Gateway验证签名并逐项比较 Evidence、历史 Availability、Binding、Route、Anchor、Attempt/Deployment/Kind/Dimension后才返回。该接口允许精确历史记录不再是 Current,但只服务调查/审计,不签发 Current Validation Receipt,也不得被 Metering用来创建新的 MeterEvent/ProviderCostFact。Grant或 Manifest半联合、Evidence不在 Manifest、跨 Case/Attempt、Anchor both/neither/wrong-pool、摘要篡改、过期/JTI重放或权限不足都拒绝且不泄露正文。
所有操作都要求面向该 Gateway Evidence Audience 的短期 Workload JWT。Attempt-bound Source Read与Current Validation使用不同Scope:metering_source_event_bootstrap的sub必须是登记的Metering Input Worker,aud精确为目标Gateway Evidence Read Service,并绑定已接受Event的ID、精确Type=gateway.evidence-availability.current-changed@1、Schema、Envelope摘要、Aggregate ID/Revision以及Event中唯一的Attempt、Deployment、Binding、Route、Kind/Dimension、Availability五元组和可选Evidence四元组;它不携带Operation或Basis/Candidate摘要。billing_finalization Source Read绑定已持久Operation与Input Manifest。只有validateAvailabilityCurrent及validateRouteCostBinding的Token才同时精确覆盖相应用途Operation、带算法Basis/Candidate摘要,以及Provider Cost时共享的providerCostValidationScope。Availability Validation Token另行绑定Availability/Evidence目标;Route Validation Token另行绑定Route Cost Binding、Route Snapshot、Mapping Revision和Normalization Policy目标,两种Token不能互换或伪装成携带同一目标对象。Gateway逐项比较Token、请求、自身Event/冻结记录,并仅用三方共同拥有的派生输入复算Operation;不能只因调用者有同租户的宽泛访问权即返回其他Attempt的事实,也不能要求Bootstrap Token携带尚未取得的正文摘要或Gateway无法验证的Run/Step/Billing字段。metering_source_event_bootstrap、eligibility_consumption、provider_cost_fact与billing_finalization使用独立Schema分支和Scope;Bootstrap授权不能调用Validation,Validation授权也不能枚举或替代Event首读。Contracts负向测试必须拒绝省略@1的无版本别名、其他Event Type、Type/Schema互换及同ID异Envelope摘要。
readAttemptRouteBinding另有三个封闭Audience分支。domain_fact_verification只接受登记的Execution/Metering/Billing Workload,并要求callerDomain、Operation与Token相等。operations_observation_intake只接受Operations Intake,在Accepted Envelope形成前绑定当前Canonical Submission的Observation ID/Schema与Submission完整摘要;operations_observation_projection只接受Operations Projector,绑定已接受Observation的ID/Schema与Accepted Envelope完整摘要。两个Operations分支的Token Scope还必须精确覆盖Tenant/Run(若存在)、Attempt、Deployment、Binding四元组和可选Operation,Gateway逐项比较Scope、请求和Binding创建时Owner Scope;不能从同Run、相近时间或相邻Observation猜补。它们只返回低敏不可变Binding正文,用于验证GatewayDiagnostic/Error的Slot、Attempt Manifest、Route四元组与Anchor,不能调用readAvailability/readEvidence/validateAvailabilityCurrent、取得Current Receipt或读取Route私有正文。错误Audience、Intake/Projector摘要类型互换、跨Observation/Attempt/Binding、未知算法或摘要错配均不泄露正文。
两种 Pre-binding 读取使用不同 Audience:readPreBindingAvailability 只接受 Operations Intake/受限诊断 Workload,Scope 精确覆盖 gatewayAttemptDispatchSlotId + gatewayPreBindingRequestId + Deployment + Evidence Kind/Dimension;readPreBindingRejectionFact 只接受 Execution Evidence Workload,Scope 精确覆盖 executionAttemptId + Attempt Manifest 四元组 + gatewayAttemptDispatchSlotId + gatewayPreBindingRequestId + Deployment。两者都禁止 Metering/Billing Audience,也不能互换 Token 或返回另一接口的正文。Gateway从受信调用上下文注入对应Purpose:Source Bootstrap注入Event身份与摘要,Validation注入Operation及Basis/Input Manifest或ProviderCost Candidate摘要,Operations分支注入Observation身份;它忽略调用方试图写入的主体/租户/审计字段。返回只含严格低敏DTO,不返回Supply、Channel、Credential、Provider Account、完整映射正文或原始Evidence。
validateAvailabilityCurrent 在 Gateway 内锁定 Current Pointer 后原子比较全部 Expected 字段并追加不可变 Validation Receipt;在该线性化点之前到达的新 Snapshot 使验证失败,之后到达的新 Snapshot属于该验证边界后的更正。Receipt 是严格 Purpose 联合:Eligibility Receipt 绑定 eligibilityValidationOperationId、Eligibility Basis Digest、Usage Snapshot 和其中的 Current Active Usage Evidence完整四元组(Terminal-none 则严格 state=none);Provider Cost Receipt 只接受 attempt_bound + available + provider_cost,绑定 providerCostValidationOperationId、ProviderCostFact Candidate Digest、Cost Snapshot 和其 Current Active Evidence完整四元组;Finalization Receipt 绑定 Billing Finalization Operation、FinalizationInputManifest 四元组、Usage Snapshot 及其 Manifest 已冻结的 Current Active Usage Evidence(Terminal-none 为 none)。expectedEvidence/validatedEvidence 必须与 Snapshot 状态同构:Available 恰好为 state=available 且四元组全等,其他状态恰好为 state=none。三类 Receipt 使用不同 Schema 分支、Idempotency Namespace、Workload Audience 与保留标签,不能复用或转换。相同 Purpose/Operation/Input/Snapshot/Evidence 幂等返回首次 Receipt,同 Operation 异 Input 或 Evidence 冲突。
Metering 先计算不含 Receipt 的 Eligibility Basis Digest,再取 eligibility_consumption Receipt,最后把两者写入 EligibilityDecision;Receipt 不绑定最终 Decision Digest,避免循环。Billing 先固定不含 Finalization Receipt 的 Input Manifest,再逐项取 billing_finalization Receipt,按 canonical 顺序组成独立 Validation Bundle;成功 Decision 同时固定 Input Manifest 与 Bundle。Billing 在客户 Ledger 事务前逐项验证 Bundle Receipt;缺失、Purpose/摘要不等、被线性化边界之前已经存在的 Head 否定或部分 Gateway 未验证均不得成功终局。Receipt 不使用隐含 TTL,边界之后到达的新 Head 进入 post-boundary correction;若最终事务失败,后续重试仍可对同一 Operation/Input 幂等取得原 Receipt,或在输入变化后生成新 Input Manifest/Operation。Receipt 本身从不表示已扣款。
readRouteCostBinding只允许Metering的metering_source_event_bootstrap Cost分支;Token与请求必须绑定同一已接受Gateway Event及其providerEvidenceKind=provider_cost、Attempt/Deployment/Binding/Route和Availability/Evidence,不要求尚未构造的Candidate。Gateway逐项验证Event与冻结Route后才返回不可变Binding;返回的GatewayRouteCostBinding@1自身具有稳定Ref/Schema Version/Digest Algorithm Version/Digest,Digest覆盖其余严格字段且不覆盖自身摘要。Metering先通过readEvidence取得Cost Evidence严格正文/摘要,并通过该Bootstrap读取Route Cost Binding,再基于完整Cost Fact业务字段、Current Availability四元组、Evidence四元组与Route Cost Binding四元组计算不含任何Receipt、Fact ID/Time的ProviderCostFactCandidate@1摘要。随后它分别以同一个 providerCostValidationOperationId 与 Candidate Digest调用validateAvailabilityCurrent(purpose=provider_cost_fact)和validateRouteCostBinding。前者锁定Availability/Active Evidence Current边界,后者验证不可变Route/Mapping/Normalization;两个Receipt都显式回显并摘要绑定各自完整输入。Source Bootstrap响应在Candidate形成后不能当作这两份Receipt,也不能直接写ProviderCostFact。
最终 ProviderCostFact 在单一 Metering Repository 事务中保存 Candidate Digest、Availability/Evidence 四元组、Availability Validation Receipt、Route Cost Binding 四元组和 Route Validation Receipt 后才能写入,形成 Candidate → 两份 Receipt → Fact 的无环链;任何 Receipt Ref 都不是 Candidate 摘要输入。两份 Receipt 的 Operation/Candidate 必须相等,Availability Receipt 的 Snapshot/Evidence 必须等于 Fact,Route Receipt 的 Binding/Route/Mapping/Normalization 必须等于 Fact。相同 Operation/Candidate/输入重放返回原 Receipt,首次响应丢失可确定收敛。同 Operation 异 Candidate、任一 Ref/Schema/Digest、Mapping/Normalization、Attempt/Binding/Route、Availability/Evidence、Audience/Scope 或 Candidate Digest 错配均拒绝:Metering追加内容寻址的ProviderCostProcessingConflictEvidence@1 + MeteringInputWorkAttemptBlocked@1,隔离Source、释放当前Lease但保留同Work/Operation/Generation为Active Blocked,不写Processing Fact、Finished或终态CAS;本地契约/映射修复后重试同Work,新Gateway Current Event也可用新Generation supersede它。只有Gateway权威Availability自身为conflicting时才写ProviderCostAvailabilityProcessingFact@1.outcome=reconciliation_required并终结本代,这一分支只由后继Availability Event重开。两者都绝不能回退读取当前 Registry或伪造Operations Case。部署测试覆盖过期/越权 JWT、跨 Attempt/Binding/Route 读取、Route Snapshot/Route Cost Binding 篡改、Mapping/Normalization 更新后的迟到 Evidence、两类 Receipt 响应丢失重放、Fact 偷换任一 Receipt/Candidate,以及 E1 read → Callback 推进 E2/A2 → E1 validate 必须失败、E1 validate → E2/A2 只形成后续更正而不能污染已提交 E1 Fact。
Metering 解引用后得到严格判别联合,而不是自由 JSON 或对 Gateway 私表的隐式 Join:
GatewayEvidence@N = ProviderUsageEvidence@N | ProviderCostEvidence@N
common:
evidenceRef / evidenceSchemaVersion / providerEvidenceKind
evidenceDigestAlgorithmVersion = jcs-sha256-v1 / evidenceDigest
evidenceDimensionKey
evidenceIdempotencyKey
executionAttemptId / gatewayDeploymentId
attemptRouteBindingRef / attemptRouteBindingSchemaVersion
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest
executionAnchor = text_invocation { gatewayInvocationId }
| media_task { gatewayTaskId }
providerAttemptId?
sourceNamespaceId / sourceRef / sourcePayloadSchemaVersion
sourcePayloadDigestAlgorithmVersion / sourcePayloadSha256
sourceClaimedOccurredAt? / capturedAt
supersedesEvidenceRef? / supersedesEvidenceSchemaVersion?
supersedesEvidenceDigestAlgorithmVersion? / supersedesEvidenceDigest?
ProviderUsageEvidence@N:
providerEvidenceKind = provider_usage
reportedUsageItems[] { metric, quantityDecimal, unit }
providerUsageVocabularyVersion
ProviderCostEvidence@N:
providerEvidenceKind = provider_cost
providerCostMappingRevisionId / providerCostNormalizationPolicyVersion
reportedAmountDecimal / reportedCurrency / reportedCostUnit
reportedQuantityDecimal?
providerCostVocabularyVersion共同字段与各分支未标 ? 字段全部必填。providerEvidenceKind 是 Gateway Read Contract 的两值判别项;不得复用 Operations 的五值 evidenceKind。Cost 分支暴露 Route Snapshot 已冻结的低敏 providerCostMappingRevisionId + providerCostNormalizationPolicyVersion,不暴露映射正文;Gateway 在 Read Contract 内验证二者与 Route Snapshot 相等,Metering 再以固定版本确定性映射/规范化并写入 ProviderCostFact。quantityDecimal、reportedAmountDecimal 与 reportedQuantityDecimal 使用 Contracts 的十进制定点字符串;sourcePayloadSha256 是受控源记录的内容摘要,不是 Secret。
sourceRef 本身就是 Contracts 中的 canonical source identity,不存在另一个未入 Schema 的 canonicalSourceRef;它只在不透明 sourceNamespaceId 内唯一。Namespace 由冻结 Route Snapshot 解析并绑定 Gateway Deployment、Adapter/Provider Account Scope 与 Evidence Kind,不暴露 Provider 账号或 Credential。每个 Adapter 必须把 Poll、Callback 或账单输入先映射为版本化、低敏、严格的 ProviderEvidenceSourceDTO@N,拒绝未知/错类型字段,再用 sourcePayloadDigestAlgorithmVersion=jcs-sha256-v1 的 UTF-8、重复 Key 拒绝、NFC、RFC 8785 与 SHA-256 规则计算摘要。这里的 @N 是 Adapter 契约族占位符,不是可部署的 Schema 名称:每个 Adapter Release Manifest 必须按 adapterId + adapterContractVersion + providerEvidenceKind 唯一解析到具体 Source Schema ID/Version、Digest Algorithm Version 与 Golden Vector Set;解析不到、仍含占位符、同一键映射多个 Schema 或 Schema 允许自由 payload/additionalProperties 时,Deployment Admission 必须失败。具体 Source DTO 必须在该 Adapter 的 Contracts 包中封闭列出全部字段、判别联合、枚举、十进制/时间规范和隐私分类,不能靠运行时样例、Provider 原始 JSON 或宽松 Map 补齐。Digest 覆盖完整 Source DTO,不覆盖原始传输 Header、Secret 或 Repository 时间;原始 Provider Bytes 如因审计需要保留,只能进入受限证据存储,不能改变该规范摘要。sourcePayloadSchemaVersion + sourcePayloadDigestAlgorithmVersion + sourcePayloadSha256 必须成组保存、归档和重放,算法或字段集变化升级相应版本,不能跨版本裸比较。Contracts 提供共享 Golden,Text/Media 每个 Adapter 提供同一 Provider 事实经 Poll/Callback、Key 重排与 Unicode 变化仍得到同 Source DTO/Namespace/Ref/Digest 的固定向量,并提供未知字段、错判别项、Release Manifest 未注册或 Schema 漂移的拒绝向量。
Gateway 必须维护不可变 GatewayEvidenceSourceRegistry。唯一键是 (sourceNamespaceId, sourceRef),首次登记原子绑定 sourcePayloadSchemaVersion + sourcePayloadDigestAlgorithmVersion + sourcePayloadSha256 + providerEvidenceKind + executionAttemptId + gatewayDeploymentId + evidenceDimensionKey + AttemptRouteBinding完整四元组 + GatewayRouteSnapshot完整四元组 + executionAnchor。每一次 Evidence 写入都采用同一个 Gateway Repository 事务:先对 Source Registry insert-or-compare,再追加或幂等取得 Evidence Candidate,CAS 推进对应 Active Head,最后追加并 CAS 推进匹配的 Availability Snapshot/Current Pointer;任何一步失败均回滚,禁止留下“已登记但无 Evidence”、已追加 Evidence 但未更新 Head、或已更新 Head 但 Source Registry 未绑定的中间态。首个 Root 只是该规则的一种情况,而不是唯一要求同事务的路径。完全相同重放返回原绑定、原 Evidence、原 Head 与原 Availability;同一 Source 换摘要、Schema、Attempt、Dimension、Binding/Route、Anchor 或 Usage/Cost Kind 一律不写新 Evidence,原子将 Availability 置为 conflicting 并建立Owner-local对账证据,不能靠新的 Evidence Idempotency Key 绕过,也不能据此直接创建Operations Case。Registry 与其不可变归档在 Source 命名空间生命周期内不得更新、删除或重绑;更正必须使用新的 Source Ref/版本并通过 Evidence Supersession 链连接。负向测试覆盖同 Source 异 Payload、跨 Attempt/Dimension、跨 Provider Account Namespace、Usage/Cost 错类、并发首次登记、更正 Append/CAS 原子回滚和 Payload 清理后的重放。
首期每个 (executionAttemptId, gatewayDeploymentId, providerEvidenceKind) 恰好只有一条累计 Evidence 链,其 evidenceDimensionKey 固定为 Contracts 注册常量 attempt_aggregate@1,并由数据库约束拒绝第二 Dimension。Usage Head 在这一条链内以 canonical 排序的 reportedUsageItems[] 承载多 Metric/Unit;Billing Policy 再把同一个 Usage Head 映射为完整 Charge Dimension 集合。Cost Head 同样是该 Attempt 的累计供应成本 Head。这样响应中的每类单一 Availability 与唯一 Active Head 一一对应,不会遗漏另一个 Dimension。未来若供应契约确需多 Evidence Head,必须升级 Response/Observation Schema 为按 Dimension canonical 排序、与冻结 Dimension Set 精确等值的严格列表,不能在当前标量字段下静默增加第二 Root。
evidenceDimensionKey 独立于 Vocabulary Version,不能由 Producer 自报。evidenceIdempotencyKey 固定由 evidenceSchemaVersion + providerEvidenceKind + evidenceDimensionKey + executionAttemptId + gatewayDeploymentId + AttemptRouteBinding完整四元组 + GatewayRouteSnapshot完整四元组 + executionAnchor + providerAttemptId? + sourceNamespaceId + sourceRef + sourcePayloadSchemaVersion + sourcePayloadDigestAlgorithmVersion + sourcePayloadSha256 + vocabularyVersion 的 Contracts 规范摘要确定,evidenceRef、capturedAt、Trace、Poll/Callback 传输方式和随机 Observation ID 不得进入。sourceRef 必须稳定标识 Provider 原生记录/状态版本;同一事实经重复 Poll、Callback 或恢复观察时必须产生同一 Source Namespace/Ref、Schema/Digest Version、摘要与 Key。Provider 没有稳定版本时,Gateway 以 Attempt/Route、Evidence Kind/Dimension、Source DTO Schema/Digest、规范 Payload Digest 和词汇版本构造内容寻址 Source Ref;若无法证明两个来源是同一事实,则 Availability 必须为 conflicting,不能各写一个可结算 Evidence。
Repository Primitive 接受的是不含存储生成字段的严格 Evidence Candidate;首次 insert 才生成并冻结 evidenceRef + capturedAt。相同 Key 重放时,只逐字段比较 Candidate 的规范业务字段(包括 sourceClaimedOccurredAt?,它已经由 Source Digest 绑定),不比较调用方不可提供的 Ref/Capture Time,并返回首次保存的完整 Evidence、原 Ref 与原 capturedAt;同键异 Candidate 隔离。负向测试必须覆盖相同来源在不同到达时间、不同 Poll/Callback 路径和调用方预生成随机 Ref 的重放:前两者收敛到首次记录,最后一种因未知字段被拒绝。
Gateway Read Contract 中的每个 Evidence Head 都是对应维度的完整累计替代值,不是增量命令。Usage Head 的 Metric/Unit 集合与 providerUsageVocabularyVersion,Cost Head 的 Currency/Cost Unit 与 providerCostVocabularyVersion 构成链身份;更正只能改变累计 Quantity/Amount、Source Ref/Digest、Capture Time 与 Provider 原生版本证据,不能跨维度或词汇版本。Provider 原生 Delta、Credit 或 Refund 只保存在不可变 Source Chain,Gateway 必须基于可验证前驱生成非歧义的完整累计 Head;无法闭合时返回 conflicting 并进入Gateway Owner-local供应核对状态,不能让 Metering 猜测或创建未定义Case。
reportedUsageItems[] 中每个 metric + unit 必须在该 providerUsageVocabularyVersion 注册、组合唯一,并按 Contracts 的 metric, unit canonical 顺序保存;Quantity 是允许精度内的非负规范十进制字符串。空数组不能伪装成“已报告零用量”:没有明细时使用 not_reported/unavailable,真实零值必须由一个已注册维度的 quantityDecimal="0" 明确表达。Cost Head 的 reportedAmountDecimal 与可选 reportedQuantityDecimal 同样必须为非负规范十进制,reportedCurrency + reportedCostUnit 必须是 providerCostVocabularyVersion 注册组合。重复 Pair、非 canonical 顺序、负数、指数、超精度、未知 Metric/Unit/Currency、错 Vocabulary Version 与同链维度变化全部拒绝;若矛盾已经成为Current Owner状态,则以conflicting Availability与内容寻址 Conflict Fact收敛,不能创建第三种Case。Contracts 必须提供 reorder、duplicate、negative、unknown-unit 和空数组负向测试。
更正 Evidence 必须保持同一 Evidence Kind/Dimension Key、Execution Attempt、Gateway Deployment、Binding/Schema Version、Route Snapshot/Schema Version、执行锚点、Source Payload Schema/Digest Algorithm Version 和上述维度身份,并通过 supersedesEvidenceRef + supersedesEvidenceSchemaVersion + supersedesEvidenceDigestAlgorithmVersion + supersedesEvidenceDigest 指向当前直接前驱;四项必须同时存在或同时缺失,并与实际不可变前驱逐项相等。Repository 对 (executionAttemptId, gatewayDeploymentId, providerEvidenceKind) 原子限制唯一 Chain Root,并强制其 Dimension 为 attempt_aggregate@1;首个 Head 同时冻结 Evidence/Source Schema、Digest Algorithm 与 Vocabulary Version。后续即使换 Dimension/Vocabulary/Schema 也不能创建第二 Root,只能因合法同版本更正进入原链,或以Owner-local冲突事实与conflicting Availability收敛。Gateway Repository 维持单一 Active Head 并拒绝第二 Root、第二 Dimension、分叉、循环、跨链、错版本或摘要、半联合或身份变化。Metering 只消费该 Read Contract,并逐项与 Attempt Manifest、Binding 和 Route Snapshot 等值校验。
模型目录与路由映射
模型目录分为公开商品和内部供应两套视图,但只有 OceanWay 是公开事实源:
OceanWay Model Offering
publicModelId
capability
surfaces[]
lifecycle
protocol
retailPricingSku
gatewayPool = text | media
modelOfferingRevisionId / logicalModelId
Text Gateway Supply
backendModelId
channel / provider model / credential
capability evidence / health / provider cost
Media Gateway Supply
backendModelId
supply / provider model / credential version
adapter capability / health / capacity / provider cost同步或手工录入的 Provider Model 只形成未发布 Observation。OceanWay 管理员完成能力、协议、价格、安全和可用性审核后,才能发布为 Offering。
Media Gateway 中即使保留 PublicModel 或类似对象,也只能把它解释为内部稳定路由别名。它不得形成第二个公开模型广场,也不得自行决定模型在哪个 OceanWay Surface 出现。
两级执行清单与私有路由快照
Run 准入事实与每次实际执行不能共用一份可变清单。OceanWay 固定两个不可变 Manifest;Gateway 再维护一份私有 Route Snapshot。三者的 Owner、生命周期和可见范围不同。
本节是下一版本的目标契约,不是对已发布 Schema 的追溯改写。当前 Contracts 0.2.0 与 Core 准入证据中的 ExecutionManifest 仍是 Organization-backed 的 Run 级历史基线;tenantKind / tenantId、modelRoutingPolicyRevisionId、Attempt Manifest、Route Binding 与 Route Snapshot 的跨层契约必须通过新的固定 Contracts 版本和消费者门禁后才可使用。Personal Space API Admission 在此之前保持禁用。
RunAdmissionManifest@N
Core Admission 在创建 Run 的同一事务中冻结一次 Run 级准入清单:
executionManifestRef / executionManifestSchemaVersion
executionManifestDigestAlgorithmVersion = jcs-sha256-v1
executionManifestDigest
actorPrincipalId / executionPrincipalId
authentication =
{ kind=developer_credential; developerAppId; environmentId; serviceAccountId; developerCredentialId }
| { kind=playground_execution_grant; developerAppId; environmentId; serviceAccountId;
playgroundExecutionGrantId; playgroundExecutionGrantSchemaVersion;
playgroundExecutionGrantClaimsDigestAlgorithmVersion; playgroundExecutionGrantClaimsDigest }
| { kind=customer_session; customerAuthenticationAssertionRef;
customerAuthenticationAssertionSchemaVersion;
customerAuthenticationAssertionClaimsDigestAlgorithmVersion; customerAuthenticationAssertionClaimsDigest;
productSurface }
| { kind=delegated_agent; delegationGrantRef; delegationGrantSchemaVersion;
delegationGrantClaimsDigestAlgorithmVersion; delegationGrantClaimsDigest;
agentRevisionId; originatingSurface }
tenantKind = organization | personal_space
tenantId / workspaceId / projectId?
billingAccountId
requestId / traceId? / correlationId / operationId / runId
source = { surface; apiVersion; operation }
product
authorizationDecisionId / authorizationDecisionSchemaVersion
authorizationDecisionInputDigestAlgorithmVersion / authorizationDecisionInputDigest
authorizationEvidenceEvaluationSetRef / authorizationEvidenceEvaluationSetSchemaVersion
authorizationEvidenceEvaluationSetDigestAlgorithmVersion / authorizationEvidenceEvaluationSetDigest
authorizationEvidenceArchiveCutRevision
authorizationEvidenceEvaluationCount
authorizationEvidenceEvaluations[] = sorted {
evidenceKind;
authorizationEvidenceEvaluationRef / authorizationEvidenceEvaluationSchemaVersion;
authorizationEvidenceEvaluationDigestAlgorithmVersion / authorizationEvidenceEvaluationDigest;
archiveRevision
}
modelOfferingRevisionId / logicalModelId
modelDeploymentId # initial admitted target
modelRoutingPolicyRevisionId
gatewayPool = text | media
capabilityContractVersion
inputAssetVersions[]
outputContractRef / outputContractSchemaVersion
outputContractDigestAlgorithmVersion = jcs-sha256-v1
outputContractDigest
executionAuthorization = {
authorizationScopeSnapshotRef / authorizationScopeSnapshotSchemaVersion
authorizationScopeSnapshotDigestAlgorithmVersion / authorizationScopeSnapshotDigest
allowedAssetVersionRefs[] / allowedModelOfferingRevisionIds[] / allowedToolVersionRefs[]
authorizationActionCount
authorizationActionIds[]=sorted
}
budgetAuthorization = {
billingAccountId / billingReservationId
budgetPolicyRevisionId
reservedValue =
{ kind=credits; amount }
| { kind=entitlement; entitlementKey; quantity; unit }
| { kind=money; money={ amount; currency } }
}
pricingSnapshotId / billingPolicyRevisionId / billingReservationIdexecutionAuthorization.authorizationActionCount 必须等于 authorizationActionIds[] 的排序去重后长度。Scope Snapshot 四元组、Action Count 与 Action 集合必须和 AuthorizationEvidenceValidationRecord@1、AuthorizationEvidenceEvaluationSet@1 及 run.created@2.0 逐项相等;缺失 Count、Count 与数组不等或仅靠 Count 替代成员集合都拒绝。
executionManifestDigest 以 UTF-8 NFC、严格 Schema、RFC 8785 Canonical JSON 与 SHA-256 覆盖除 Repository-owned Ref/Time 和摘要自身外的完整 Manifest Candidate;未知算法、未知字段、摘要错配或同 Ref 绑定不同正文必须拒绝。Contracts 为每个 Schema Version 发布 Golden JSON/Canonical Bytes/Digest,字段或规范化算法变化必须升级 Schema/Algorithm Version。run.created@2.0 中的 executionManifestRef / executionManifestSchemaVersion 专门指向这份 RunAdmissionManifest,其 Actor/Execution Principal、Tenant、完整 Authentication Evidence、Source/Product、Authorization Evidence/Evaluation Set、Model、Gateway Pool、Output Contract、Pricing、Billing Policy 与 Reservation 字段必须逐项相等。事件与 Manifest 的等值关系由同一 Core Admission 事务内的 Producer Constraint 保证;Operations Projector 只消费事件,不在投影时跨服务读取 Manifest。outputContractDigest 内容寻址严格 Output Contract Candidate,Contracts 固定 Canonicalization/Golden;Ref/Schema/Digest Algorithm/Digest 缺一不可。事件中的 modelDeploymentId 是首次准入目标,不是“此 Run 永远只能执行这个 Deployment”的声明;后续重试不修改 Manifest 或创建事件。
Core 为受信 Workload 提供版本化 readRunAdmissionManifest,请求必须携带 executionManifestRef + executionManifestSchemaVersion + executionManifestDigestAlgorithmVersion + executionManifestDigest,以及期望的 runId + tenantKind + tenantId + audienceWorkloadId;响应只返回该 Schema Version 的严格 DTO 与同一四元组。服务端先校验调用方 Workload 身份、精确 Audience、Tenant/Run 归属、不可变 Repository 绑定与重算摘要,任何不一致都 fail-closed;调用方仍须以 Contracts 对 DTO 做严格未知字段、Schema、算法与摘要验证。不存在“按 Ref 读最新版本”、宽松 JSON、跨 Tenant 查询、只比 Ref/Schema 或在读失败时回退当前配置的路径。
authentication 是严格四分支联合。正式 API 以 Service Account 同时作为 Actor 和执行主体,并保存 DeveloperCredential 的稳定 ID;Playground 以 Customer User 为 Actor、Service Account 为执行主体,并保存 Playground Execution Grant 的 Ref/Schema Version/Claims Digest Algorithm Version/Claims Digest。交互式 Canvas/Studio/Drama/Commerce 产品使用 customer_session:Actor 与 Execution Principal 都是已验证 Customer Principal,只保存 Identity Authorization 签发的稳定 Authentication Assertion Ref/Schema Version/Claims Digest 与 Product Surface,不保存 Session ID、Cookie 或 Token。脱离当前页面继续执行的 Agent 使用 delegated_agent:Actor 是授权发起者,Execution Principal 必须是 Principal Registry 中与本 runId 一对一、同 Tenant/Workspace/Project、kind=agent_run 且与 agentRevisionId 不可变绑定的临时 Principal;Delegation Grant 的 Ref/Schema Version/Claims Digest 冻结 subject、audience、Tenant、资源、工具、预算与有效期。四个分支互斥,分支外字段按未知字段拒绝;serviceAccountId 只在前两个分支必填,后两个分支必须省略。内部 Workload Principal 只进入服务跳转或 Gateway Invocation Audit,不覆盖业务 Actor/Execution Principal。
Playground Grant、Customer Authentication Assertion、Delegation Grant 与 Authorization Decision 都进入不可变 AuthorizationEvidenceArchive。每个 Ref/ID 首次写入时以 jcs-sha256-v1 原子绑定 Schema Version、严格 Claims/Input、Issuer、Audience、Actor/Execution Principal、Tenant/Workspace/Project、Scope 与有效期;Ref 永不复用。高敏 Claims 正文可按保留策略清理,但以下低敏记录和撤销事实必须永久保留为封闭 DTO:
AuthorizationEvidenceValidationRecord@1 = {
authorizationEvidenceValidationRecordRef / authorizationEvidenceValidationRecordSchemaVersion
authorizationEvidenceValidationRecordDigestAlgorithmVersion = jcs-sha256-v1
authorizationEvidenceValidationRecordDigest
evidenceIdentity =
{ kind=playground_execution_grant;
playgroundExecutionGrantId / playgroundExecutionGrantSchemaVersion;
playgroundExecutionGrantClaimsDigestAlgorithmVersion / playgroundExecutionGrantClaimsDigest }
| { kind=customer_authentication_assertion;
customerAuthenticationAssertionRef / customerAuthenticationAssertionSchemaVersion;
customerAuthenticationAssertionClaimsDigestAlgorithmVersion / customerAuthenticationAssertionClaimsDigest }
| { kind=delegation_grant;
delegationGrantRef / delegationGrantSchemaVersion;
delegationGrantClaimsDigestAlgorithmVersion / delegationGrantClaimsDigest }
| { kind=authorization_decision;
authorizationDecisionId / authorizationDecisionSchemaVersion;
authorizationDecisionInputDigestAlgorithmVersion / authorizationDecisionInputDigest }
issuerId / audienceId
actorPrincipalId / executionPrincipalId
tenantKind / tenantId / workspaceId / projectId?
scope = {
authorizationScopeSnapshotRef / authorizationScopeSnapshotSchemaVersion;
authorizationScopeSnapshotDigestAlgorithmVersion / authorizationScopeSnapshotDigest;
authorizationActionCount;
actionIds[]=sorted
}
issuedAt / notBefore / expiresAt
revocationSubjectKey
archivedAt
}
AuthorizationEvidenceRevocationFact@1 = {
authorizationEvidenceRevocationFactRef / authorizationEvidenceRevocationFactSchemaVersion
authorizationEvidenceRevocationFactDigestAlgorithmVersion = jcs-sha256-v1
authorizationEvidenceRevocationFactDigest
authorizationEvidenceValidationRecordRef / authorizationEvidenceValidationRecordSchemaVersion
authorizationEvidenceValidationRecordDigestAlgorithmVersion / authorizationEvidenceValidationRecordDigest
revocationSubjectKey
effectiveAt / reasonCode / revokedAt
}
AuthorizationEvidenceEvaluation@1 = {
authorizationEvidenceEvaluationRef
authorizationEvidenceEvaluationSchemaVersion
authorizationEvidenceEvaluationDigestAlgorithmVersion = jcs-sha256-v1
authorizationEvidenceEvaluationDigest
purpose = run_admission
authorizationEvaluationOperationId
evaluationAt / archiveRevision
record = AuthorizationEvidenceValidationRecord@1
revocationFacts[] = sorted AuthorizationEvidenceRevocationFact@1
validityAtEvaluation =
{ state=valid }
| { state=not_yet_valid }
| { state=expired }
| { state=revoked;
decisiveRevocationFactRef / decisiveRevocationFactSchemaVersion;
decisiveRevocationFactDigestAlgorithmVersion / decisiveRevocationFactDigest }
}
AuthorizationEvidenceEvaluationSet@1 = {
authorizationEvidenceEvaluationSetRef / authorizationEvidenceEvaluationSetSchemaVersion
authorizationEvidenceEvaluationSetDigestAlgorithmVersion = jcs-sha256-v1
authorizationEvidenceEvaluationSetDigest
purpose = run_admission
authorizationEvaluationOperationId
authenticationKind = developer_credential | playground_execution_grant |
customer_session | delegated_agent
actorPrincipalId / executionPrincipalId
tenantKind / tenantId / workspaceId / projectId?
authorizationScopeSnapshotRef / authorizationScopeSnapshotSchemaVersion
authorizationScopeSnapshotDigestAlgorithmVersion / authorizationScopeSnapshotDigest
authorizationActionCount
actionIds[]=sorted
evaluatedAt # Archive 服务端权威时间
archiveCutRevision
expectedEvidenceCount
expectedEvidenceIdentities[]=sorted AuthorizationEvidenceValidationRecord@1.evidenceIdentity
evaluationCount
evaluations[]=sorted {
evidenceKind;
authorizationEvidenceEvaluationRef / authorizationEvidenceEvaluationSchemaVersion;
authorizationEvidenceEvaluationDigestAlgorithmVersion / authorizationEvidenceEvaluationDigest;
archiveRevision
}
result = valid | not_valid
recordedAt
}Validation Record Scope 与 Evaluation Set 的 authorizationActionCount 都必须等于各自 actionIds[] 的排序去重后长度,并与请求、Run Manifest 和 Run Event 的同名 Count/集合全等。Count 参与各自摘要,但不能替代精确 Action 成员;缺失、错 Count、重复或错序均 fail-closed。
Record 与 Revocation Fact 的摘要分别覆盖除 Repository-owned Ref/Time和摘要自身外的完整严格 Candidate;Evidence Identity 四分支严格互斥,Scope Snapshot 四元组和 Action 集合必填。后续撤销只追加新的 Revocation Fact,不更新 Validation Record;每条 Fact 必须引用完整 Record 四元组并具有同一 revocationSubjectKey。普通 Revocation 是前瞻式事实,effectiveAt 必须等于 Archive 写入的权威 revokedAt,调用方不得回填过去时间。单项 Evaluation 只能作为下述原子 Evaluation Set 事务的成员产生;同一 Set内全部成员共享 Archive 服务端 evaluatedAt + archiveCutRevision,并分别按 (effectiveAt, Revocation Fact Ref) 排序包含截至该 Cut的完整 Revocation Fact集。状态只由 Record时间窗、服务端 evaluatedAt 与该 Cut下的排序 Timeline计算。Evaluation作为持久化内容制品具有完整四元组,Digest覆盖 Purpose、Operation、完整 Record、全部 Fact、Revision、时间与严格状态,只排除 Repository-owned Evaluation Ref/Recorded Time和摘要自身。Set Digest则覆盖期望身份集合、分支、主体/租户/Scope/Action、同一服务端 Cut、完整成员四元组/Count和总结果,排除 Set Ref/Recorded Time与摘要自身;任一成员不为 valid 时 Set总结果必须为 not_valid。正文清理墓碑必须引用完整 Validation Record四元组,不能删除 Record、Revocation Timeline、已冻结 Evaluation/Set或只剩一个无法解释的 Payload Digest。
Archive 提供原子准入签发与历史读取。evaluateAuthorizationEvidenceSetForAdmission 的请求携带唯一 authorizationEvaluationOperationId=operationId、Authentication Kind、该分支完整且精确的期望 Evidence Identity集合、期望 Issuer/Audience、Actor/Execution Principal、Tenant/Workspace/Project、Scope Snapshot四元组和 Action集合;禁止请求携带 evaluationAt、Archive Revision或任何历史 Cut。Owner 与 Revocation Writer共用一个可串行化 Archive Revision Fence,在单一事务内取得服务端时间、锁定一个全局 archiveCutRevision、完整读取所有成员及截至该 Cut的撤销、持久化各 Evaluation与 Set后才返回。响应严格为 {result=valid; evaluationSet=AuthorizationEvidenceEvaluationSet@1} | {result=not_valid; evaluationSet=AuthorizationEvidenceEvaluationSet@1} | {result=not_found} | {result=conflicting; conflictRecordRef / conflictRecordSchemaVersion; conflictRecordDigestAlgorithmVersion / conflictRecordDigest}。同 Operation/完整期望集合幂等返回原 Set;同 Operation绑定不同成员、Scope或主体冲突。Set事务与撤销事务在同一 Revision Fence上形成全序:先提交的撤销必然进入新 Set并阻止 Valid,Set先提交则仅授权这个已冻结 Operation,随后撤销不追溯改写它。
readAuthorizationEvidenceEvaluationSet 要求 Set完整四元组,以及期望 Purpose/Operation/Authentication Kind、完整期望 Evidence Identity集合、Archive Cut与主体/租户/Scope,只返回已冻结严格 Set或 not_found | conflicting;读方再按 Set中每个成员完整四元组调用 readAuthorizationEvidenceEvaluation,后者要求期望 Operation/Evidence Identity/同一 Archive Revision/Evaluation Time。两种读取都绝不按当前 Revision重算历史,也不存在供 Admission逐成员签发的 evaluateAuthorizationEvidenceAt 路径。
Owner 在所有操作中都校验精确调用方 Workload Audience/Scope、Evidence→Record 唯一绑定、Authentication分支期望成员、所有四元组和摘要;读方重新严格解码并复算 Set与每个 Evaluation。未知字段/Schema/算法、分支混合、Ref重绑、Fact指向其他 Record、成员漏项/夹带/重复、不同 Archive Cut、Timeline漏项、排序/Revision/状态错配都 fail-closed。新 Revocation Fact只产生更高 Archive Revision,阻止之后的新 Operation获得 valid Set;它不改写已经持久化的 Set、Evaluation、Record或旧 Fact。若之后发现证据在历史时点已被攻破,必须追加新的 Security Incident与Owner-local影响事实和处置动作;若未来需要正式Case,先发布独立来源契约。不能用回填 effectiveAt 或重算 Evaluation改写已提交 Run的准入结论。
过期或撤销阻止新的 Admission。Core在创建 Run前为 Authorization Decision及当前 Authentication分支所需的 Playground/Customer/Delegation Evidence一次提交完整期望集合,并且只接受 purpose=run_admission + authorizationEvaluationOperationId=operationId + result=valid 的原子 Set。Developer Credential分支的 Set只有 Authorization Decision;其余三个分支恰好再包含一份对应 Authentication Evidence。Core把 Set完整四元组、统一 Archive Cut以及 Set内精确排序、去重的成员四元组固定到 Run Manifest;authorizationEvidenceEvaluationCount 必须同时等于数组长度、Set Count和该分支期望集合,漏项、夹带、重复、Kind错配或不同 Cut都拒绝。历史重放先按 Manifest/Event冻结的 Set四元组调用 readAuthorizationEvidenceEvaluationSet,再读取其固定成员;不按 run.createdAt、当前时钟或当前 Archive Revision重算,也不查询当前 Session、Membership、Grant或 Policy。Core Admission事务验证分支证据、Set/Evaluation、Authorization Decision和 Manifest的 Actor/Execution Principal、Tenant、Scope、Audience、服务端评估时间、Operation逐项相等;Set签发是该 Operation的授权线性化边界,Run事务只能使用相同 Operation一次提交,不能把另一个 Operation或客户端时间嫁接到旧 Set。未知算法/Schema、摘要不符、Validation Record/Scope Snapshot/Set/Evaluation缺失、Set或成员非 valid、已过期/撤销的新请求或 Ref重绑一律拒绝。Contracts发布四类 Record/Evaluation、Set、四个 Authentication分支集合、每种证据的 Golden Claims/Canonical Bytes/Digest,以及过期、撤销、Claims清理后重放、单成员检查之间撤销、服务端 Cut前后并发撤销、调用方回填过去时间、响应丢失、同 Operation异成员集合、同 Ref异 Claims、Timeline漏项/乱序/Revision错误和追溯撤销不能改写旧 Run的负向测试;保留期限不得短于其引用的 Run/Event/账务证据。
product 是冻结经济身份,唯一规范来源是 source.surface。Developer Credential 分支必须为 developer_api,Playground Grant 必须为 developer_playground;Customer Session 要求 productSurface == source.surface == product,Delegated Agent 要求 originatingSurface == source.surface == product。agentRevisionId 仅 Delegated Agent 分支允许并必须进入后续 MeterEvent,其他三分支的 MeterEvent 必须省略它。Run Event、RunAdmissionManifest、MeterEvent 与 Operations Admission Snapshot 对 product(以及 Delegated 分支的 agentRevisionId)逐项相等,禁止 Worker、Gateway 或 Metering 自行改写产品归因。
executionAuthorization 是 Core 对发起人、Service Account(如有)、Delegation/Agent、Workspace/Project、MCP Grant、企业策略与 Offering 取交集后的不可变最大权限,不是客户端声明。三个 Allowed Resource数组与 authorizationActionIds[]按 Contracts注册键排序且元素唯一;Action ID是 Authorization Contracts中的规范可执行动作,不再使用含义未定义的宽泛 scopes[]与它隐式互换。Scope Snapshot四元组内容寻址整个授权输入与结果,并且该四元组与 Action集合必须和 AuthorizationEvidenceEvaluationSet@1、run.created@2.0逐项相等。budgetAuthorization 与顶层 billingAccountId/billingReservationId 必须逐项相等;reservedValue 复用 Contracts 的严格 BillingValue 联合,并与同事务 wallet.reserved@2.0.reservation.value 完全相等。Credits、Entitlement 和 Money 不能互换或相加,Entitlement Key/Unit 与 Money Currency 都是经济身份的一部分。RunExecutionToken@1 只能取授权集合的子集;其付款账户/Reservation/Policy 必须相等,Token Budget Cap 必须与 Reservation 同 Kind,且 Amount/Quantity 不超过 reservedValue,同时 Entitlement Key/Unit 或 Currency 必须逐项相等。签发器通过版本化 Manifest Read Contract 验证,不能让 Executor 根据 Token 自报字段反推权限。
首次 run.created@2.0 + wallet.reserved@2.0 Producer Cutover 仍只启用 Organization 下的 developer_credential | playground_execution_grant。customer_session | delegated_agent 虽在目标 Contracts 中有严格 Schema,但必须等各产品的 Assertion/Delegation、Actor/Execution Principal、Billing 与端到端门禁通过后按 Producer Capability Registry 单独启用;不得把未支持产品 Run 填成开发者分支或伪造 Service Account。
Run 清单不包含 runStepId、executionAttemptId、gatewayDeploymentId、backendModelId、Raw Idempotency Key、完整价格快照或供应商私有字段。它创建后不可修改;重放准入只返回原 Run 和原 Manifest 引用。
AttemptExecutionManifest@N
Execution 为每个实际 Attempt 单独冻结执行清单:
attemptExecutionManifestRef / attemptExecutionManifestSchemaVersion
attemptExecutionManifestDigestAlgorithmVersion = jcs-sha256-v1
attemptExecutionManifestDigest
executionManifestRef / executionManifestSchemaVersion
executionManifestDigestAlgorithmVersion / executionManifestDigest
runId / runStepId / executionAttemptId / attemptNo
modelDeploymentId # this attempt's actual OceanWay target
modelRoutingPolicyRevisionId
gatewayPool = text | media
gatewayDeploymentId
routeSelectionReason? / retryCausationId?
outputContractRef / outputContractSchemaVersion
outputContractDigestAlgorithmVersion / outputContractDigestattemptExecutionManifestDigest 以 UTF-8 NFC、严格 Schema、RFC 8785 Canonical JSON 与 SHA-256 覆盖除 Repository-owned Ref/Time 和摘要自身外的完整 Manifest Candidate;未知算法、未知字段、摘要错配或同 Ref 绑定不同正文必须拒绝。Contracts 为每个 Schema Version 发布 Golden JSON/Canonical Bytes/Digest,字段或规范化算法变化必须升级 Schema/Algorithm Version。Attempt 必须逐项复制 RunAdmissionManifest 的 Ref/Schema/Digest Algorithm/Digest 四元组与 Output Contract 四元组,Execution 在创建 Attempt 前通过上述版本化 Read Contract 验证完整 Run Manifest;不得按当前产品配置重算、只传裸 Ref 或把同一 Ref 重新绑定到其他正文。首次 Attempt 的 modelDeploymentId 必须等于 Run 准入清单中的 initial target。后续 Attempt 只有在准入时冻结的 modelRoutingPolicyRevisionId 明确允许时才能选择不同 modelDeploymentId,并必须记录规范 routeSelectionReason 与前次 Attempt/重试因果;“使用最新路由策略”或原地覆盖旧 Deployment 都不允许。每次用户重试、系统安全恢复或故障切换都创建新的 executionAttemptId 与 AttemptExecutionManifest,不修改 RunAdmissionManifest。
Execution Owner正式提供以下版本化读取,而不是让 Gateway按 Ref猜正文:
readAttemptExecutionManifest(
attemptExecutionManifestRef, attemptExecutionManifestSchemaVersion,
attemptExecutionManifestDigestAlgorithmVersion, attemptExecutionManifestDigest,
expectedExecutionAttemptId,
manifestReadPurpose =
{ kind=gateway_execution_bootstrap;
expectedRunId; expectedRunStepId;
expectedModelDeploymentId; expectedGatewayDeploymentId; expectedGatewayPool }
| { kind=metering_execution_eligibility;
expectedRunId; expectedRunStepId;
sourceEventId / sourceEventType / sourceEventSchemaVersion;
sourceEventEnvelopeDigestAlgorithmVersion / sourceEventEnvelopeSha256;
sourceOwner=execution_eligibility }
| { kind=metering_gateway_availability;
sourceEventId / sourceEventType / sourceEventSchemaVersion;
sourceEventEnvelopeDigestAlgorithmVersion / sourceEventEnvelopeSha256;
sourceOwner=gateway_availability }
)
-> { result=found; manifest=AttemptExecutionManifest@N }
| { result=not_found }
| { result=conflicting; conflictManifestRef / conflictManifestSchemaVersion;
conflictManifestDigestAlgorithmVersion / conflictManifestDigest }该入口有三个互斥的短期Workload Purpose。gateway_execution_bootstrap只接受目标Text/Media Gateway用于本次Deployment的精确Scope,并要求返回Manifest与请求中的Run/Step、Model/Gateway Deployment和Pool全等。metering_execution_eligibility只接受登记的Metering Input Worker,绑定已接受的execution.attempt-eligibility.finalized@1 Event及其Run/Step/Attempt。metering_gateway_availability是Provider Cost可独立启动的bootstrap:Token和请求绑定已接受的gateway.evidence-availability.current-changed@1 Event ID/Type/Schema/完整Envelope摘要、Manifest完整四元组与Attempt,但不要求Metering预先知道只能从Manifest正文取得的Run/Step、Model Deployment或Pool;响应后Metering必须把这些字段与Binding、Gateway Event Owner Scope和Run Admission Manifest逐项验证,不能把“省略expected”解释为宽泛查询。Execution按完整四元组读取不可变正文,严格解码、重算摘要并验证Repository绑定与Attempt;对前两个分支再验证expected Run/Step。它还必须验证正文引用的RunAdmissionManifest完整四元组和Output Contract完整四元组仍等于创建Attempt时已验证并持久化的值;调用方取得正文后再把Deployment/Pool/Run Manifest/Output Contract与Eligibility Fact、Gateway Event/Binding及自身Candidate逐项比较。错误Audience/Scope/Purpose、Event摘要类型互换、裸Ref、latest、同Ref/Schema异Digest、跨Run/Step/Attempt/Deployment、Output Contract或Run Manifest重绑都返回不泄露正文的失败。Contracts发布三Purpose请求/响应DTO、Golden JSON/Canonical Bytes/Digest,并覆盖Cost Event先到且无Eligibility Event时只凭Event+Manifest四元组bootstrap、Metering进程重启、响应丢失和Gateway/Metering Token互换。
Attempt 清单在发起 Gateway 调用前完成,因此不能包含尚未产生的 gatewayRouteSnapshotRef。Execution 将 attemptExecutionManifestRef + attemptExecutionManifestSchemaVersion + attemptExecutionManifestDigestAlgorithmVersion + attemptExecutionManifestDigest 完整四元组交给已选 Gateway Deployment;Gateway 在读取客户 Payload 或产生任何 Provider Side Effect 前,必须调用 readAttemptExecutionManifest验证精确 Audience、Attempt/Run、Gateway Deployment、Schema、算法、Repository绑定与重算摘要,不能只按 Ref/Schema接受或读取最新正文。Gateway 只有在实际选择内部 Channel/Supply 时才创建 Route Snapshot,并返回追加式绑定:
AttemptRouteBinding@N
attemptRouteBindingRef / attemptRouteBindingSchemaVersion
attemptRouteBindingDigestAlgorithmVersion = jcs-sha256-v1
attemptRouteBindingDigest
gatewayAttemptDispatchSlotId
attemptExecutionManifestRef / attemptExecutionManifestSchemaVersion
attemptExecutionManifestDigestAlgorithmVersion / attemptExecutionManifestDigest
executionAttemptId / gatewayDeploymentId
gatewayExecutionAnchor = text_invocation { gatewayInvocationId }
| media_task { gatewayTaskId }
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest
boundAtAttemptRouteBinding 由 Gateway 在任何 Provider Side Effect 之前,与 Task/Invocation、Route Snapshot、提交意图和同一 Dispatch Slot 的 reserved→bound CAS 在同一持久化边界生成。其摘要覆盖除 Repository-owned Ref/Time和摘要自身外的完整严格 Candidate,包括 Attempt Manifest 与 Route Snapshot 四元组、Slot、Attempt/Deployment 和 Anchor。Text 调用响应与 Media Task 创建/查询响应都必须返回 Binding 完整四元组;Execution 在消费结果、Evidence 或推进后续状态前,以 append-only 方式保存该四元组。不得事后把 Ref 补写进不可变 Attempt Manifest。重复调用只能返回同一 Slot、Attempt Manifest 四元组、Gateway Deployment、执行锚点与 Route Snapshot 四元组完全相同的绑定;同一 Ref/Schema 携带不同 Digest、同一 Attempt 出现不同 Slot/绑定、已 terminal_rejected Slot 尝试绑定,或 Binding 中的 Manifest 四元组与版本化读取结果不等,都必须在 Provider Side Effect 前拒绝或隔离,并以GatewayBindingConflictFact@1提供Owner-local阻塞锚点,不得直接创建Operations Case。
Gateway 提供版本化 readAttemptRouteBinding,并把它定义为历史重放的 bootstrap read:请求只携带 Binding 完整四元组、调用方已经从自身规范Fact或待验证Observation获得的期望 Attempt/Deployment,以及上述严格bindingReadPurpose,不要求调用方预先知道正要从 Binding 正文验证出来的 Slot、Attempt Manifest、Route Snapshot或 Anchor。Gateway必须先按当前认证 Workload 的精确 Audience/Scope、Purpose与 Binding创建时保存的 Owner Scope做授权,再按完整四元组读取不可变正文;期望 Attempt/Deployment和Observation摘要只用于附加相等校验,绝不能替代授权。响应严格为 {result=found; binding=AttemptRouteBinding@N} | {result=not_found} | {result=conflicting; GatewayBindingConflictFact完整四元组}。服务端和读方都必须严格解码、重算摘要并校验 Repository唯一绑定;领域读方取得正文后,再把其中 Slot、Attempt Manifest四元组、Route Snapshot四元组与 Anchor逐项对照 Availability、Evidence和自身规范Fact,Operations读方则只能对照同一Submission/Accepted Observation的GatewayDiagnostic或Error。不存在裸 Ref、按 Ref读最新、跨 Attempt枚举、未授权探测,或要求消费者从相邻记录猜补 bootstrap字段的路径。Contracts/Gateway测试必须覆盖仅凭持久化Fact或Accepted Observation中的Binding四元组在进程重启后恢复、Intake在Accepted Envelope形成前使用Submission摘要验证、Projector使用Accepted Envelope摘要重放、错误Audience/Scope/Purpose、跨Observation/摘要类型互换、同 Ref/Schema异 Digest、摘要算法未知、正文/Slot/Manifest/Route/Anchor篡改、Binding重放、响应丢失后同 Attempt重调、rejected/bound CAS竞争与双终态拒绝。
一个 OceanWay Execution Attempt 只能拥有一个 AttemptRouteBinding 和一个 GatewayRouteSnapshot。Gateway 在同一 Task 内仅可对完全相同的 Supply/Channel、ProviderCredentialVersion、Provider Model、Adapter 与配置快照执行经证明确认无副作用的协议重试;任何需要改变 Supply、Channel、凭据、Provider Model、Adapter 或其他路由事实的故障切换,都必须在 Provider 尚未产生 Side Effect 时返回标准 route_change_required 结果,由 Execution 创建新的 OceanWay Attempt、AttemptExecutionManifest、Gateway Task/Invocation 与 Binding。Provider 已接受或提交结果未知时不得自动重试、换路或双投,只能保留同一任务查询和恢复;若最终阻止账务安全终局,只能由Billing Finalization按自己的Run级协议决定是否创建Case。
GatewayRouteSnapshot@N
实际 Gateway 以 gatewayRouteSnapshotRef 维护该 Attempt 的私有、不可变路由快照:
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
gatewayRouteSnapshotDigestAlgorithmVersion = jcs-sha256-v1
gatewayRouteSnapshotDigest
executionAttemptId / gatewayDeploymentId
backendModelId
providerCostMappingRevisionId / providerCostNormalizationPolicyVersion
route =
{ kind=text; channelId; providerModelId;
providerCredentialVersionId; adapterVersion; configRevision }
| { kind=media; supplyId; providerModelId;
providerCredentialVersionId; adapterVersion; configRevision }route 是严格判别联合:Text 必须且只能有 Channel,Media 必须且只能有 Supply,两者都必须固定 Provider Model、Credential Version、Adapter 与配置。Gateway 对不含 Repository 生成字段的完整 Route Snapshot Candidate 按 jcs-sha256-v1 计算并冻结 gatewayRouteSnapshotDigest,读方不得以相同 Ref 猜测不同内容。providerCostMappingRevisionId + providerCostNormalizationPolicyVersion 在 Route Snapshot 创建时由该 Adapter/Config 的已激活、不可变成本 Registry 解析并冻结;Metering 首次或迟到处理 Cost Evidence 时必须经 readRouteCostBinding + validateRouteCostBinding 取得并验证这两个版本,禁止读取当前映射或规范化策略。route.kind 必须与 AttemptExecutionManifest.gatewayPool 和 Gateway Deployment 注册的 Pool 同时一致;both/neither、错 Pool、缺 Provider Model/Credential/Adapter/Config/Cost Mapping/Normalization Revision 或出现另一分支字段都必须拒绝。若未来出现不以 Provider Model 为锚点的能力,必须新增明确版本化分支,不能把现有字段改成可空。该快照只属于 Text/Media Gateway 私有执行域。普通 Operations、产品页面和公共 API 只能看到受控引用与低敏 Deployment 状态;不能读取 Provider Credential、物理账号、供应商原始价格或完整路由正文。Metering 可通过定向 Workload 授权和版本化 Evidence Read Contract 验证引用,但不能直连 Gateway 数据库。Contracts/Gateway 测试必须覆盖两类路由 round-trip、both/neither、wrong-pool、各必填字段缺失、Snapshot 摘要篡改,以及 Cost Evidence 在 Mapping/Normalization 更新后才首次到达仍使用冻结版本。
三层关联校验固定为:
MeterEvent.modelOfferingRevisionId + pricingSnapshotId + billingPolicyRevisionId与RunAdmissionManifest及run.created@2.0相等,Actor/Execution Principal、Tenant/Workspace/Project、Billing Account、Run、Correlation 与 Operation 也逐项相等;MeterEvent.executionAttemptId + modelDeploymentId与对应AttemptExecutionManifest相等;AttemptRouteBinding必须反向匹配 Attempt Manifest、Gateway Deployment 与 Gateway 创建的 Route Snapshot;- Provider Usage Evidence 的 Attempt、Gateway Deployment 与 Route Snapshot Ref 必须与该
AttemptRouteBinding和GatewayRouteSnapshot相等; ProviderCostFact的 Attempt、Gateway Deployment、Cost Evidence、providerCostMappingRevisionId与providerCostNormalizationPolicyVersion必须与相同 Binding/Route Snapshot 关联一致;迟到首次摄取不能选择当前 Mapping/Normalization。
两条路径分别 fail-closed:Offering/Pricing/Model/Usage/Eligibility 任一已证明本地错配都追加EligibilityProcessingConflictEvidence@1 + MeteringInputWorkAttemptBlocked@1、保留Active Work且不产出可结算 MeterEvent;Attempt/Gateway Deployment/Binding/Route/Cost Evidence/执行锚点的已证明本地错配则追加ProviderCostProcessingConflictEvidence@1 + MeteringInputWorkAttemptBlocked@1、保留Active Work且不产出可信ProviderCostFact。两者都不写Finished/terminal CAS/Operations Case;只有Gateway权威Cost Availability自身为conflicting时才形成Metering-owned供应成本reconciliation_required Processing Fact,并只由后继Availability Event重开。ProviderCostFact 不要求 Offering、Pricing、成功 Output、MeterEvent 或 Settlement;两条路径间的关联冲突在本阶段只形成Metering定向诊断状态与明确不完整的告警,不能删除、覆盖或阻断另一条路径中已由自身Lineage证明的事实,也不能宣称Operations已可靠摄取。当前两分支Operations Case联合不包含Provider Cost;可靠Admin队列需要新增Canonical Processing Event/Mandatory Delivery/Owner Read,可指派/终结的供应商对账Case还必须另行定义Identity、Owner、终态Authority与恢复协议。RunAdmissionManifest@N、AttemptExecutionManifest@N、AttemptRouteBinding@N 与 GatewayRouteSnapshot@N 是唯一规范名称;其他页面只引用它们,不另造 offeringRevision、pricingSnapshot、policyDecisionId 或 executionPool 同义字段。
文本同步与流式链路
文本、Embedding 和 Rerank 请求走 UUMI/new-api Text Gateway Pool:
- Public API Edge 验证 DeveloperCredential,或验证 Console BFF 持有的短期 Playground Execution Grant;网页产品由各自 BFF 鉴权 Customer Session。Customer Session、长期开发者凭据与内部 Grant 不得互换。
- Product Control 解析 Offering,Execution Control 创建 Attempt 并预占预算。
- Capability Router 选择 Text Pool 的具体 Gateway Deployment。
- Text Gateway 在 Provider Side Effect 前原子保存 Invocation、提交意图、Route Snapshot 与 Attempt Route Binding,再按该快照向 Provider 发起请求。
- Text Gateway 透传标准化流式事件,持久化 Provider 返回的不可变 Usage/Cost Evidence,并向 OceanWay 返回 Attempt Route Binding完整四元组、Gateway Route Snapshot完整四元组、
usageEvidenceAvailability与costEvidenceAvailability;只有available分支携带对应 Evidence完整四元组。 - Metering 分两条独立链处理:
Attempt + Execution/Output Eligibility Fact + ProviderUsageEvidence + billingPolicyRevisionId先形成不可变EligibilityDecision,再生成带单一 Charge Type 的 canonicalMeterEvent;Attempt + AttemptRouteBinding + GatewayRouteSnapshot + ProviderCostEvidence独立生成ProviderCostFact,不要求成功 Output、Asset、MeterEvent 或 Settlement。Billing 只按settlementEligibility=eligible的 canonical MeterEvent、不可变 Decision、冻结 Billing Policy 与价格快照计算目标净额;必须由BillingFinalizationDecision证明完整 Attempt×Charge Dimension 集合封闭后,才可原子结算并释放余量,未知或冲突进入对账。
断流重连不能自动重放一个可能已产生 Provider 消费的请求。只有 Provider 或 Gateway 提供可证明安全的幂等语义时,才允许透明恢复。
Text Gateway 每次物理调用至少返回稳定 Gateway Invocation ID、Attempt Route Binding完整四元组、Gateway Route Snapshot完整四元组、低敏 Gateway Deployment、标准状态、规范化错误,以及必填的 usageEvidenceAvailability + costEvidenceAvailability;只有 available 分支携带相应 Evidence完整四元组。普通响应不得返回 Channel、Supply、ProviderCredentialVersion 或其他私有路由详情。若当前 UUMI/new-api 不能可靠暴露 Provider Attempt 或供应侧 Evidence,OceanWay 使用准确的非 Available 状态记录“未报告/待定/不可用/冲突”,不能读取其数据库后拼装未经契约化的事实。
媒体异步执行链路
图片和视频使用同一业务协议;同步图片只是这个协议在较短时间内返回终态的特例。
当前可靠性基线是主动查询和对账。Provider Callback 不是第一阶段依赖;未来某个 Provider 确有必要时,回调入口作为 Media Gateway 的内部可选模块增加,而不是拆成另一个独立平台。
Media Gateway 单一边界与内置模块
下列模块属于同一个产品、同一代码库和同一运维所有权。实现上可以按进程角色独立扩缩,但架构上不形成新的客户平台或额外控制面。
| 内置模块 | 职责 |
|---|---|
| Internal API | 接受 OceanWay 工作负载身份,处理创建、查询和结果读取 |
| Supply / Provider Credential Control | 管理 Provider Supply、账号、ProviderCredentialVersion、能力和供应成本 |
| Task / Provider Attempt Registry | 保存提交意图、Task、Attempt、冻结路由、上游 ID、状态和恢复事实 |
| Dispatcher | 选择符合内部供应策略的 Supply,创建并提交 Provider Attempt |
| Provider Adapters | 翻译 Provider 的创建、查询和结果协议 |
| Poller | 使用原 Attempt 与凭据版本查询已存在的上游任务 |
| Reconciler | 处理提交不确定、状态冲突和需要继续核验的事实 |
| Result Handling / Spool | 取回、校验和暂存 Provider 输出,向 OceanWay 报告可导入结果 |
| Usage / Cost Evidence | 保存 Provider 响应或账单来源引用、内容摘要和规范化前的不可变 ProviderUsageEvidence / ProviderCostEvidence;不创建 Metering Fact |
Provider Callback、Cancel Adapter 和共享 Result Spool 是后续增强能力。它们即使实现,也仍然处于 Media Gateway 边界内。
两级任务与 Attempt
OceanWay 与 Media Gateway 各有一层 Attempt,命名和所有权不能混用:
OceanWay Run
└── OceanWay Execution Attempt
└── gatewayTaskId
└── Media Gateway Task
├── Provider Attempt 1
└── Provider Attempt 2(仅在网关策略证明安全时)- OceanWay Execution Attempt 表示一次面向用户的业务执行与计费身份。
- Media Gateway Task 是该 Attempt 在媒体基础设施中的不透明执行锚点。
- Provider Attempt 表示 Media Gateway 对真实 Provider 的一次提交尝试。
- 一个 OceanWay Execution Attempt 只创建一个 Media Gateway Task。
- Media Gateway 在同一 Task 内只允许复用同一
GatewayRouteSnapshot做经证明无副作用的有界协议重试;不得换 Supply、Channel、凭据、Provider Model 或 Adapter。 - 如需改变任何路由事实,Gateway 只能在确认未产生 Provider Side Effect 时返回
route_change_required,由 OceanWay Execution 创建新的 Execution Attempt 和 Media Gateway Task;Provider 已接受或提交未知时只允许查询、恢复或对账。 - 用户在终态失败后显式重试,必须创建新的 OceanWay Execution Attempt 和新的 Media Gateway Task。
OceanWay 不复制 Provider Attempt 细节,只保存 gatewayTaskId、Attempt Route Binding完整四元组、低敏 Gateway Deployment、标准状态、两类 Evidence Availability,以及 available 分支中的 Evidence完整四元组和审计关联。Media Gateway 不复制用户、钱包和业务资源。
Media Gateway 持久事实
Media Gateway 至少需要可靠保存:
gatewayTaskId / requestId
operationId / correlationId / executionAttemptId / traceId
backendModelId / capability
supplyId / providerCredentialVersionId / adapterVersion
attemptRouteBindingRef / attemptRouteBindingSchemaVersion
attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest
gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest
requestFingerprint / idempotencyKeyHash
providerAttemptId / providerRequestId / upstreamTaskId
providerSideEffectState
normalizedStatus / stateVersion
resultRefs
providerUsageEvidence? / providerCostEvidence?
providerUsageSourceRef? / providerCostSourceRef?
sanitizedError / reconciliationState
createdAt / submittedAt / terminalAt其中 executionAttemptId 是不透明关联,不要求复制 OceanWay 用户或企业资料。每条 Evidence 必须实现本页固定的 GatewayEvidence@N Read Contract,并通过稳定 Evidence Ref 对应 Invocation/Task、可选 Provider Attempt、Binding、Route Snapshot、来源引用与内容摘要;源系统后续修正时追加带 supersedesEvidenceRef 的新 Evidence,不原地覆盖。providerUsageSourceRef / providerCostSourceRef 只能指向 Gateway 内受控来源记录,不能是 Provider Secret 或长期可公开 URL。Registry 不保存 DeveloperCredential、用户余额、零售价、完整 Prompt、媒体二进制、长期签名 URL 或 Provider Secret。
提交前必须先持久化 Task、Attempt 与请求指纹。调用超时且无法证明 Provider 是否创建任务时,状态进入 UNKNOWN / RECONCILING;禁止直接换 Supply 再次提交。
一旦获得 upstreamTaskId,或 Provider 副作用可能已经发生,原 supplyId + providerCredentialVersionId + adapterVersion + routeSnapshot 必须冻结。后续 Poll、Reconcile 和结果取回使用同一 Provider Attempt,不能按照最新路由重新选择。
状态映射
Media Gateway 可维护更细的内部状态,但对 OceanWay 只发布稳定投影:
| Media Gateway 内部事实 | OceanWay Execution 状态 |
|---|---|
| created / submitting | dispatching |
| accepted / queued | queued |
| processing | running |
| unknown / reconciling | reconciliation_required |
| provider_succeeded / result_ready | running,等待正式资产登记 |
| succeeded + result report complete | output_pending |
| provider_failed / failed | failed |
| cancelled(未来能力确认) | cancelled |
Provider 返回 Success 不等于 OceanWay Run 成功。只有输出经过安全取回、格式与内容校验、对象存储写入、AssetVersion 登记和账务终态后,OceanWay 才能将业务 Output 标记为成功。
终态不得因迟到的 Poll 或未来 Callback 回退。若 Provider 成功事实与失败事实冲突,应保留两份不可变来源、把Current Availability收敛为conflicting并提供内容寻址Owner Conflict Fact,而不是按“最后写入”覆盖或由Gateway创建Case。
标准诊断投影与错误契约
两个私有网关向 OceanWay 发布 OperationalObservationSubmission@1.0 的严格 Gateway Refinement,不另造第二套 ID 或时间字段:
observationId / schemaVersion / sourceClaimedObservedAt?
requestId / traceId? / correlationId? / operationId? / runId?
surface=internal / operation
payload.type=GatewayDiagnostic@1
payload =
gatewayPool / gatewayDeploymentId
gatewayAttemptDispatchSlotId
gatewayPreBindingRequestId?
executionAttemptId?
executionAnchor? =
{ kind=text_invocation; gatewayInvocationId }
| { kind=media_task; gatewayTaskId }
providerAttemptId?
capability / configRevision
normalizedStatus / stateVersion / submissionCertainty
attemptRouteBindingRef? / attemptRouteBindingSchemaVersion?
attemptRouteBindingDigestAlgorithmVersion? / attemptRouteBindingDigest?
gatewayRouteSnapshotRef? / gatewayRouteSnapshotSchemaVersion?
gatewayRouteSnapshotDigestAlgorithmVersion? / gatewayRouteSnapshotDigest?
usageEvidenceAvailability / costEvidenceAvailability
resultSummary = GatewayDiagnosticResultSummary@1
GatewayDiagnosticResultSummary@1 =
{ state=not_available; reason=not_terminal|not_reported|not_applicable }
| { state=available; outputDisposition=no_output;
outputItemCount=0; outputModalitySet=[] }
| { state=available; outputDisposition=reported;
outputItemCount=positive_integer_up_to_contract_limit;
outputModalitySet[]=sorted_unique(text|embedding|rerank|image|video|audio) }GatewayDiagnostic@1 是 Contracts 固定字段、类型、长度与分类的判别 Payload,不是任意 JSON 日志袋。规范字段固定为 gatewayPool=text|media,不存在 gatewayPoolId 同义字段。resultSummary必填且只能使用上述封闭低敏联合:reported要求正数Count和至少一个与已注册Capability相容的规范模态,no_output固定零Count与空集合,not_available禁止全部输出字段;Count上限来自Contracts资源保护常量,模态按注册顺序去重。Summary只表达当前观察到的结果数量/模态,不携带文本、Prompt、URL、文件名、MIME、尺寸、Hash、Asset ID、Provider原始状态或任意扩展Map,也不能驱动Run/Output成功。两类 Availability 均必填且分别对应首期唯一的 Usage/Cost attempt_aggregate@1 Active Head;每类都携带完整 Snapshot Ref/Schema Version/Digest Algorithm Version/Digest/State Version、Kind、Dimension、Identity、前驱联合与 Reason,available 才另外要求 Evidence Head完整四元组。缺任一 Snapshot/Evidence 字段、非 Available 偷带 Evidence、声明版本/摘要错配、错类 Ref、第二 Evidence Dimension 或未知状态都必须拒绝。
两类 Availability 必须共享且只共享一种严格身份。attempt_bound 要求外层 gatewayAttemptDispatchSlotId + executionAttemptId + AttemptRouteBinding完整四元组 + GatewayRouteSnapshot完整四元组 + executionAnchor 全部存在并与两个 Snapshot、Binding/Evidence Read Contract 逐项相等,同时必须省略 gatewayPreBindingRequestId。pre_binding_no_execution 仅用于 Binding 创建前且可证明未发生 Provider Side Effect 的拒绝:外层 gatewayAttemptDispatchSlotId + gatewayPreBindingRequestId 必填并与两个 Snapshot和 Rejection Fact 相等,必须省略 Attempt/Binding/Route/Anchor;两个 Snapshot 只能是 stateVersion=1 + root + not_reported|unavailable、resultSummary.state=not_available,禁止 Evidence四元组,也不能进入 Metering、Eligibility 或 Finalization。不能证明无 Side Effect 时必须走 Attempt-bound。Attempt-bound 的 Anchor 严格二选一,且 gatewayPool=text 只能使用 text_invocation,gatewayPool=media 只能使用 media_task;同时提供、全部缺失、错 Pool 或错 ID 都拒绝。四元组的任一半联合或同 Ref/Schema 异 Digest 都进入 Quarantine。若 Gateway 内部保留旧 GatewayDiagnostic DTO,受信 Adapter 必须逐字段映射:gatewayObservationId → observationId、observedAt → sourceClaimedObservedAt、oceanwayOperationId → operationId,其余字段只进入上述 Payload 白名单;映射后再以严格 Canonical Submission 校验,不能直接发送旧 DTO。Gateway Producer 必须通过 Canonical Schema round-trip、未知字段拒绝、两 Scope 混合、Pre-binding 偷带 Attempt/Evidence、同 Attempt 换 Slot/Request ID、ID/时间/Binding/Route/Anchor/Availability 映射,以及Result Summary缺失、分支混合、零/负/超限Count、重复/未知/错Capability模态与内容/URL/自由Map注入负向测试。
需要提交规范错误时使用独立 ErrorOccurrence@1 分支,错误码字段统一为 normalizedCode,并携带实际 Adapter 使用的 errorNormalizationPolicyVersion、固定 phase、severity、retryDisposition、compensationDisposition 与 Error Template Key/白名单参数;不把错误字段混入 Gateway Payload,也不携带任意自由文本。Gateway Error 在 Binding 创建前且确定无 Provider Side Effect 时只提交真实已知关联;一旦 Binding 已创建或副作用可能发生,必须在同一 Error Payload 中携带 runStepId + executionAttemptId 与严格 gatewayExecution,后者固定 Gateway Pool/Deployment、Binding/Route,并以 text_invocation + gatewayInvocationId 或 media_task + gatewayTaskId 二选一锚定执行。Core 必须与 Run/Step/Attempt、Binding、Route 和 Evidence Read Contract 交叉验证,禁止根据同 Run 的相邻 Diagnostic 猜 Attempt。Producer 不提交 service、errorFingerprint 或 errorFingerprintVersion;Core 从受信 Workload Registry 注入 Service,Projector 按 Contracts 固定算法生成 Fingerprint。媒体提交确定性使用 not_submitted / submitted / provider_accepted / unknown 等可解释事实;unknown 不得被翻译成普通失败后自动重试。
OceanWay Operational Read Model 只保存这些标准摘要、两类 Availability 与 Available 分支的不透明引用。sourceClaimedObservedAt 只是 Gateway 的可选时间声明;进入 Core Accepted Observation 后,排序、健康窗口、Retention、Freshness 与 Summary 只能使用 Core acceptedAt,claimed time 只在 Timeline 展示。Operational Observation 可以引用 Available Evidence,但不能携带或冒充规范 MeterEvent / ProviderCostFact,更不能触发结算。ProviderCredentialVersion、原始 Payload、完整 Prompt、媒体内容和网关私有路由细节不进入中央投影。若 Observation 或 Evidence 缺失,后台按联合显示“未报告/待定/不可用/冲突”,不能按时间、模型名或状态猜测。
两级重试所有权
为了同时避免重复生成和重复调度,重试分为两层。
Media Gateway 内部恢复
Media Gateway 可以:
- 在请求尚未发出时恢复连接或重新领取 Worker 租约;
- 在能证明 Provider 未创建任务时,按已发布策略创建新的 Provider Attempt;
- Provider 已接受后继续 Poll/Reconcile;
- Provider 已成功后只重试结果取回和暂存,不重新生成。
Media Gateway 不可以:
- 在
accepted或unknown后换 Supply 重新提交; - 跨到 Text Pool 或另一个 OceanWay Offering;
- 根据用户等级、余额或零售价决定重试;
- 为用户的显式“再生成”复用旧业务 Attempt。
OceanWay 业务重试
OceanWay 决定用户是否可以重试、是否再次预占和是否生成新 Attempt。重试只能在旧 Attempt 已有可解释终态或完成正式人工处置后开始;新 Attempt 可以重新执行当前路由策略,但不覆盖旧记录。
用户计费与供应成本
用户价格和 Provider 成本是两条独立事实链:
OceanWay Product Price
Offering Revision + Retail Rate + Contract / Discount
→ Quote → Reserve → Settle / Release / Refund / Reconcile
Private Gateway Evidence
Provider response / bill source
→ immutable ProviderUsageEvidence / ProviderCostEvidence + source refs
OceanWay Metering usage path
Execution Attempt + Execution/Output Eligibility + ProviderUsageEvidence + Policy
→ canonical MeterEvent → Billing Settlement
OceanWay Metering cost path
Execution Attempt + AttemptRouteBinding/GatewayRouteSnapshot + ProviderCostEvidence
→ canonical ProviderCostFact → Margin Analytics / Provider ReconciliationGateway 只保存供应商返回或账单来源形成的不可变 Evidence。响应与 Gateway Observation 都必须携带 usageEvidenceAvailability 和 costEvidenceAvailability 两个严格判别联合:available 必须且只能带对应 Evidence完整四元组,其他 not_reported | pending | unavailable | conflicting 状态禁止携带任何 Evidence四元组。Metering 是规范 MeterEvent 与 ProviderCostFact 的唯一 Writer,负责将 Evidence 绑定到同一 Execution Attempt、规范单位与币种、按稳定幂等键去重、追加更正并发起差异对账。Gateway 不保存用户售价、用户余额、订阅、折扣或客户结算记录,也不拥有扣款权限;ProviderCostEvidence / ProviderCostFact 只进入供应核对和毛利链,迟到或缺失不能阻塞、改变或重算已经由规范 MeterEvent 与 Price Snapshot 决定的客户费用。
异步媒体的账务语义固定为:
- 提交前由 OceanWay 预占;
- Gateway 返回
accepted/queued时保持预占,不立即结算; - 按准入时冻结的版本化产品/Billing Policy 判断 MeterEvent 结算资格;成功且 OceanWay 正式登记输出的用量可以结算,失败/取消若仍有合格 canonical MeterEvent 也按该政策结算;
- 确定未提交,或失败/取消且没有合格 MeterEvent 时,仍须等
BillingFinalizationDecision封闭完整 Attempt×Charge Dimension 集合后才释放;已结算后的合格补偿使用追加式退款/调整; - Usage Evidence 缺失或冲突、提交/输出事实未知时进入待对账,不猜测 Usage、成功或失败;ProviderCostFact 永不单独触发客户账务。
同一 billingReservationId + executionAttemptId + chargeDimensionKey(并校验冻结的 chargeType + chargeTypeRegistryVersion + unit)只能产生一笔 Base Settlement;MeterEvent 更正只能让 Billing 以新 canonical chain head 的 meterEventId 对差额追加一次幂等 Adjustment/Refund,不能重做 Base。Gateway 的重复状态、Evidence、Poll 结果、Operational Observation 或未来回调不得直接触发任何一次扣款;它们只能作为 Metering 的幂等输入和对账证据。
结果与正式资产
Media Gateway 的 Result Spool 是执行恢复与结果交接层,不是全局素材库。它可以保存受控的临时结果和校验信息,但不会获得 OceanWay Asset 的所有权、ACL、版本、分享或删除语义。
OceanWay Asset Service 负责:
- 校验真实 MIME、大小、可解码性和内容哈希;
- 写入统一对象存储或受控外部存储;
- 创建 Asset、AssetVersion、Rendition 和 Lineage;
- 绑定 Organization、Workspace、Project、Run 和业务对象;
- 生成权限受控的内容读取或下载地址。
Developer API 的内容访问仍经过 OceanWay owner-scoped 接口。Gateway 地址、内部 Workload Identity 和 Provider 临时 URL 不能暴露给开发者。
身份、网络与管理面
- 产品用户和企业成员只在 Identity/Tenant Domain 中存在;Developer App、Environment、Service Account 与 DeveloperCredential 只在 Developer Access Domain 中存在。
ai.oceanway.tech不接受登录后开发者配置;console.oceanway.tech/ai使用 Customer Session 调用 Developer Access Domain,api.oceanway.tech/v1使用 DeveloperCredential 或受限 Playground Execution Grant 调用 Execution Edge。- OceanWay Runtime 以 Workload Principal 使用短期 Workload Credential 或 mTLS assertion 调用私有网关;DeveloperCredential 不会被交换、复用或转发为该认证材料。
- Text Pool 与 Media Pool 的 Workload Credential、数据库凭据和 ProviderCredentialVersion 完全分离。
- ProviderCredentialVersion 由对应网关持有,版本化并可审计;OceanWay 客户域不读取其明文。
- DeveloperCredential、WebhookSigningSecretVersion、MCPConnectionSecret、ProviderCredentialVersion 与 Workload Credential 是不同信任边界的凭据类型,不能共享 Secret、Audience、校验器或轮换记录。
- Text/Media Gateway 的人类运维统一通过
admin.oceanway.tech的 Workforce SSO/RBAC 或基础设施 IAM;Break-glass 也由外部 IAM 管理,Media Gateway 不建设本地用户与 API Key 服务。 - 私有网关只允许通过内网、服务网格或受控入口访问;浏览器和 DeveloperCredential 不能直达。
- Gateway 获得的输入和输出权限应按单次任务收窄,不获得 OceanWay 对象存储管理权限。
中央后台查询 Gateway 的规范化运行投影,不直连 Gateway 数据库。暂停新调度、排空 Supply、查询原 Task、重取原结果或撤销 ProviderCredentialVersion 等动作只能通过 Admin Command Gateway 调用网关拥有的受控命令,并携带权限、幂等、原因、影响预览和 Audit;后台不得提供任意 Provider 请求或直接改写 Task 状态。
Cancel、Callback 与多实例边界
以下内容是明确的后续增强,不应在当前文档中伪装成现有能力。
Cancel
只有 Provider Adapter 明确声明支持、并能返回可验证取消结果时,Media Gateway 才能暴露取消命令。OceanWay 的 cancel_requested 表示用户意图,不等于 Provider 已取消;Provider 先完成时必须保留成功事实并按业务和账务规则处理。
Provider Callback
当前主链路使用 Poller/Reconciler。未来若加入 Provider Callback,应作为 Media Gateway 内部入口,执行原始 Body 验签、重放保护、持久收据、去重、乱序处理,并与 Poller 进入同一状态机。客户 Webhook 由 Developer Access Domain 使用独立的 WebhookSigningSecretVersion 发出,两者不是同一个服务,也不复用 DeveloperCredential 或 ProviderCredentialVersion。
多实例 Result Handling
当前本地 Result Spool 在单实例阶段可用。扩展到多机前,必须迁移到共享对象存储或等价的耐久介质,并验证跨节点租约、幂等取回、崩溃接管和恢复;不能只增加 Worker 数量后假定安全。
从嵌套链路迁移到同级双网关
G0:冻结边界
- 记录 pic-vps 的 UUMI/new-api 部署、模型、Channel、凭据引用和存量媒体任务。
- 冻结 Media Gateway 产品化范围:不建设本地 User、CustomerGroup、APIKey、模型广场和用户售价服务。
- 确认 OceanWay 是 Product Catalog、Developer Access、Wallet、Run 和 Asset 的唯一事实源。
G1:冻结服务间契约
- 定义工作负载鉴权、
Idempotency-Key、X-OceanWay-Operation-ID、Task 状态和错误映射。 - 定义 Request/Trace/Correlation 传播、Gateway Observation 与标准诊断错误契约。
- 建立 OceanWay
AttemptExecutionManifest ↔ Gateway Task/Invocation ↔ AttemptRouteBinding ↔ GatewayRouteSnapshot的持久绑定。 - 对齐图片/视频创建、统一任务查询、结果读取,以及
ProviderUsageEvidence/ProviderCostEvidence与 source ref 契约。 - Gateway Response 返回 Binding/Route完整四元组与两类严格 Evidence Availability;Operational Observation 只携带受控 Binding/Route四元组、Availability及 Available 分支中的 Evidence四元组,规范
MeterEvent/ProviderCostFact由 Metering 唯一追加。 - 将 Cancel 与 Callback 标为 capability-gated 的未来契约。
G2:接通端到端闭环
- 先灰度一条同步图片 Offering,验证结果进入 OceanWay Asset。
- 再灰度异步图片和一条视频 Offering。
- 修正公共异步查询、内容读取和预占保持;按版本化 Billing Eligibility 计算目标净额,并只在
BillingFinalizationDecision封闭完整 Attempt×Charge Dimension 集合后结算或释放,未知/冲突进入对账。 - 验证 Provider Accepted 或 Unknown 时不会重复提交。
G3:开发者入口与控制面收口
ai.oceanway.tech只提供公开模型、文档、API 列表价和状态,不承载登录后写操作。- Developer App、Environment、Service Account、DeveloperCredential、Webhook 和 API 使用记录只通过
console.oceanway.tech/ai管理;购买、钱包、订阅和账单使用 Console 的统一商业界面。 - 所有公共机器流量只进入
api.oceanway.tech/v1,DeveloperCredential 只在该 Edge 终止。 - Media Gateway 中删除本地 User、CustomerGroup、APIKey、公开模型广场和用户价格簿服务;内部鉴权改用外部签发的短期 Workload Credential。
- OceanWay 只同步媒体能力、可用性和 Provider Evidence 引用,不同步 Gateway 客户域数据,也不把 Gateway 旧 Cost 字段直接升级为规范 Fact。
G4:媒体流量切换
- 按 Offering Revision 对新 Attempt 做 canary,不做同请求双写。
- 存量 UUMI/new-api 媒体任务继续原路到终态。
- 核对成功率、延迟、Evidence 完整性、Metering 规范事实、幂等、资产和账务后,排空并移除旧媒体 Channel。
- Text Gateway Pool 保持运行,不受媒体切换影响。
G5:按需增强
- Provider Cancel;
- Provider Callback;
- 共享 Result Spool 与多实例接管;
- 更完整的自动 Reconciliation;
- 生产负载、故障和恢复演练。
回滚只改变新 Attempt 的路由,不迁移或重写已经发生的 Provider Task、钱包账本和正式资产。
第一阶段验收门禁
- 新媒体 Attempt 直接进入
oceanway-media-gateway,不再经过 UUMI/new-api。 - Text 与 Media Pool 的路由、凭据和运行记录彼此隔离。
- 两个 Pool 都能发布带 Correlation/Operation、状态、确定性和规范化错误的诊断投影。
- Gateway 对每份 Provider Usage/Cost 只追加不可变 Evidence 与 source ref;响应和 Observation 必须分别返回严格 Evidence Availability,只有
available分支携带对应 Evidence完整四元组,缺任一项、算法/版本/摘要错配、错类 Ref 或非 Available 携带任一项均被拒绝。 - 只有 Metering 可以创建规范
MeterEvent/ProviderCostFact;重复 Evidence 幂等收敛,供应商更正追加新 Evidence/Facts 并保留替代链。 - Media Gateway 不存在本地 User、CustomerGroup、APIKey、模型广场和用户售价服务。
- OceanWay 可以持久映射
AttemptExecutionManifest ↔ Execution Attempt ↔ AttemptRouteBinding ↔ Gateway Route Snapshot ↔ gatewayInvocationId/gatewayTaskId,并按 Owner 鉴权查询。 - Media Task/Provider Attempt 在服务重启后可从数据库恢复。
- Poll/Reconcile 使用创建时冻结的 Supply、ProviderCredentialVersion 和上游 Task ID。
- Provider Accepted 或提交 Unknown 时不会盲目重提。
- Provider 成功但结果取回失败时只恢复结果,不重新生成。
- Gateway Result 不会被误当作 OceanWay 正式 Asset。
- 异步
202/queued保持预占;只有正式 Output 与账务终态均完成才把 Run 标记为succeeded,Run 成功状态不与 Settlement Eligibility 混为一条规则。 - Operational Observation、Poll、Callback 或 Provider Cost Evidence 均不能直接驱动客户结算;Billing 只按版本化 Billing Policy、合格 canonical MeterEvent、冻结价格与 Execution/Output Eligibility 计算目标净额,并只在
BillingFinalizationDecision封闭完整集合后结算或释放;ProviderCostFact永不作为客户结算输入。 - 重复查询、状态事件和恢复不会产生重复资产或重复扣款。
- DeveloperCredential、用户售价、余额和账本事实不会进入私有网关。
-
admin.oceanway.tech只读取标准投影,不直连 Text/Media Gateway 数据库;所有写操作经过受控命令和 Audit。 - 存量媒体任务可以沿旧链路排空,切换和回滚只影响新 Attempt。
不可妥协的规则
- OceanWay 是客户身份、产品模型、Surface、用户售价、钱包、Run、正式资产和最终业务状态的唯一事实源。
- UUMI/new-api 只属于 Text Gateway Pool;Media Gateway 在目标链路中直接连接媒体 Provider。
- Media Gateway 是单一服务边界,其 Registry、Worker 和 Adapter 只是内部模块。
- Media Gateway 不建设本地 User、CustomerGroup、APIKey、模型广场和用户售价服务。
- 一个 OceanWay Execution Attempt 只对应一个 Gateway Task/Invocation、一个
AttemptRouteBinding和一个GatewayRouteSnapshot;同路由的安全协议重试可以留在该 Task 内,任何换路都创建新的 OceanWay Attempt 与 Gateway 执行锚点。 - Provider 调用前先持久化提交意图,
UNKNOWN状态禁止盲目重提。 - Provider 接受后冻结原 Supply、ProviderCredentialVersion、Adapter 与 Upstream Task。
- Provider Success 不等于业务 Success;正式资产登记完成是 Run 进入
succeeded的门禁,但不是 Settlement Eligibility 的替代条件。客户结算始终由冻结 Billing Policy、合格 canonical MeterEvent 与冻结价格决定,失败或取消也必须按该契约处理。 - Gateway 只拥有不可变
ProviderUsageEvidence/ProviderCostEvidence与 source ref;Metering 是规范MeterEvent/ProviderCostFact的唯一 Writer,任何 Gateway 或 Operational Observation 都不能驱动客户结算。 - Text Pool 与 Media Pool 同级、互不级联、互不跨池静默降级。
- Cancel、Provider Callback 和多机 Result Spool 是后续能力,未实现前必须明确暴露能力限制。
- 迁移只影响新 Attempt;存量任务、账本和资产不被重写。
- Gateway 诊断通过版本化 Observation 契约进入中央运维投影;管理员不得直接改网关数据库或绕过状态机。
ai.oceanway.tech只负责公开开发者发现,console.oceanway.tech/ai负责登录后 Developer Control,api.oceanway.tech/v1是唯一机器入口。- Developer Access Domain 统一拥有
Developer App → Environment → Service Account → DeveloperCredential;DeveloperCredential 只在 Public API Edge 终止。 - DeveloperCredential、WebhookSigningSecretVersion、MCPConnectionSecret、ProviderCredentialVersion 与 Workload Credential 必须分型,不能跨信任边界复用。