OceanWayOceanWay
运维事件与读模型

事件与 Observation 契约

准入、结算、对账经济边界事件、Legacy v1、Observation Submission/Accepted Envelope 与数据最小化规则

运维读模型只能消费稳定、低敏、可验证的契约,不能解析应用日志,也不能在投影时回查 Domain Query 来猜测创建时上下文。本章固定首期领域事件与入口观测契约。

证据种类不能混用

evidenceKind含义可靠性可作为领域权威事实
domain_fact已由领域事务提交的状态变化Transactional Outbox + at-least-once可以;权威范围仅限事件明确表达的事实
operational_observationEdge 或未来 Gateway 观察到的一次请求、响应或错误首期 best-effort不可以;只能表达“该来源曾观测到”
operations_runtimeDelivery、Attempt、Receipt、Quarantine、Projection Build 等 Core 运维状态Core PostgreSQL 受控写入不可以;只对运维管道自身状态负责
telemetry_reference指向日志或 Trace 的受控引用可采样、可丢失、按策略保留不可以
derived_summary从已标注证据计算的摘要可重建不可以

Observation 不能伪装成 Domain Event;Domain Event 也不能塞入原始 HTTP Body、Prompt、Secret 或 Provider Payload 以满足调试需求。

ErrorOccurrence 时间字段

所有 Error Occurrence Schema 统一暴露以下可选字段,并由 evidenceKind 做条件校验:

occurredAt? / sourceClaimedObservedAt? / acceptedAt? / derivedAt?
  • domain_factoperations_runtime 分别要求其事实 Owner/Core Runtime 生成的 occurredAt,其他三项必须缺失;
  • operational_observation 要求 Core Intake 生成的 acceptedAt,允许 Producer 提供可选 sourceClaimedObservedAtoccurredAt/derivedAt 必须缺失;
  • telemetry_reference 要求表示受控引用生成时间的 derivedAt,可保留来源声明时间,occurredAt/acceptedAt 必须缺失;
  • derived_summary 要求 derivedAt,其他三项必须缺失;输入事实时间通过 Field Evidence 保留,不能生成替代时间。

不满足组合约束的记录必须在 Contracts 或 Projector 边界拒绝/隔离,不能在反序列化、数据库默认值或 UI 中互相回填。对于 operational_observationacceptedAt 是排序、accepted health window、Retention/Archive、Freshness 与 Summary 首次/最近时间的唯一权威时间;sourceClaimedObservedAt 只允许进入 Timeline 展示。

Canonical Event Envelope

已发布的 run.created@1.0wallet.reserved@1.0 保持原 Canonical Envelope,不改写历史 Schema:

eventId / eventType / schemaVersion / occurredAt / producer
actorPrincipalId
organizationId / workspaceId / projectId?
aggregateId / aggregateRevision
correlationId / operationId? / causationId? / traceId?
payload

面向个人与企业统一生态的新事件版本使用 Tenant-aware Canonical Envelope:

eventId
eventType
schemaVersion
occurredAt
producer
actorPrincipalId
tenantKind = organization | personal_space
tenantId
workspaceId
projectId?
aggregateId
aggregateRevision
correlationId
operationId?
causationId?
traceId?
payload

tenantKind + tenantId 是严格判别联合:organization + OrganizationIdpersonal_space + PersonalSpaceId,不可同时或缺失。旧 Envelope 的 organizationId 只能确定性映射为 tenantKind=organization + tenantId=organizationId 并保留 Source Lineage;不能把 Personal Space 伪造成 Organization,也不能给既有 @1.0 静默增加字段。run.created@2.0wallet.reserved@2.0 都使用 Tenant-aware Envelope;首个 Producer/Cutover 门禁仍只允许 tenantKind=organization。Personal Space 必须等两个 v2 Event、tenant-aware Manifest、Contracts/Core/API Edge、授权与 Billing 的真实门禁同时通过后才启用。

规则:

  • eventId 在 Producer 首次提交前生成,重投、重建和跨进程传递时保持不变。
  • aggregateRevision 是对应 Aggregate 的正整数版本;Consumer 只据此判断单 Aggregate 缺口或乱序。
  • correlationId 用于关联业务链,operationId 用于稳定业务操作,traceId 只代表可采样的遥测链。
  • Event Envelope 与 Payload 一经提交不可修改;更正通过新领域事实或新事件完成。
  • PostgreSQL Trigger 与 Column Grant 必须拒绝对 Envelope、Payload、eventEnvelopeDigestAlgorithmVersion、Canonical Event SHA-256、deliverySetVersion + deliverySetDefinitionSchemaVersion + deliverySetDefinitionDigestAlgorithmVersion + deliverySetDefinitionDigest 和创建时间的 UPDATE;应用 Role 没有绕过权限。Delivery Set 四元组是不纳入 Canonical Event Digest 的独立不可变投递元数据,其 DeliverySetDefinition@N 严格 DTO、规范排序与摘要规则以 Outbox Publisher 契约为唯一规范;每个Member还冻结Expected Receipt Type/Schema,core_operations额外冻结精确Projection Name/Version。Producer、Dispatcher、Ack 和 Archive不得用当前Registry、响应或Receipt自报值补Target。
  • 严格 Schema 的字段增加、移除或语义变化必须发布新版本,不能静默扩展旧版本。
  • Canonical Event 摘要固定为 eventEnvelopeDigestAlgorithmVersion=jcs-sha256-v1:使用与下文 Observation Digest 相同的 UTF-8/重复 Key/NFC/严格 Schema/RFC 8785/SHA-256 规范,覆盖对应 Event Version 的完整严格 Canonical Envelope(包括 Payload),只排除 eventEnvelopeDigestAlgorithmVersion + eventEnvelopeSha256 自身和数据库投递元数据。算法版本与 eventEnvelopeSha256 一起写入 Event、Ack 与 Receipt;同一 eventId 的 Envelope 任一 Actor/Tenant/Aggregate/Revision/Correlation/Operation/Causation/Producer/Time/Payload 字段被替换,或算法版本/摘要不同,都属于完整性错误并隔离。Contracts Release 必须提供完整 Event Golden JSON/Canonical Bytes/摘要,Producer、Consumer、Archive 与 Rebuild 使用同一制品;如实现另存 Payload-only 摘要,它只能用于局部诊断,不能满足 Delivery、Receipt、Completeness 或 Cutover。

run.created@2.0

现有 run.created@1.0 只包含基础 Run Summary,没有 requestId、认证链、模型、Execution Manifest 与价格快照等首期 Explorer 所需字段。由它产生的记录必须在 limitations[] 中包含 partial_legacy_event;Projector 不得通过查询当前 Domain State 回填历史创建快照,因为当前状态可能已经变化。

run.created@2.0 是新的严格事件版本。Canonical Envelope 与 Payload 合在一起构成低敏、自包含的 Admission Snapshot;Envelope 已有的字段不在 Payload 中重复保存。

Envelope
  aggregateId = runId
  actorPrincipalId
  tenantKind / tenantId / workspaceId / projectId?
  correlationId / operationId / traceId?
  occurredAt

Payload
  run.billingAccountId
  run.status / run.createdAt / run.updatedAt
  run.executionManifestRef / run.executionManifestSchemaVersion
  admission.requestId
  admission.source.surface / apiVersion / operation
  admission.executionPrincipalId
  admission.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 }
  admission.product
  admission.authorizationDecisionId / authorizationDecisionSchemaVersion
  admission.authorizationDecisionInputDigestAlgorithmVersion / authorizationDecisionInputDigest
  admission.authorizationEvidenceEvaluationSetRef / authorizationEvidenceEvaluationSetSchemaVersion
  admission.authorizationEvidenceEvaluationSetDigestAlgorithmVersion / authorizationEvidenceEvaluationSetDigest
  admission.authorizationEvidenceArchiveCutRevision
  admission.authorizationScopeSnapshotRef / authorizationScopeSnapshotSchemaVersion
  admission.authorizationScopeSnapshotDigestAlgorithmVersion / authorizationScopeSnapshotDigest
  admission.authorizationActionCount
  admission.authorizationActionIds[] = sorted
  admission.authorizationEvidenceEvaluationCount
  admission.authorizationEvidenceEvaluations[] = sorted {
    evidenceKind = authorization_decision | playground_execution_grant |
                   customer_authentication_assertion | delegation_grant
    authorizationEvidenceEvaluationRef / authorizationEvidenceEvaluationSchemaVersion
    authorizationEvidenceEvaluationDigestAlgorithmVersion / authorizationEvidenceEvaluationDigest
    archiveRevision
  }
  admission.model.publicModelId
  admission.model.logicalModelId
  admission.model.modelOfferingRevisionId
  admission.model.modelDeploymentId  # initial admitted target
  admission.model.modelRoutingPolicyRevisionId
  admission.model.gatewayPool
  admission.outputContractRef / outputContractSchemaVersion
  admission.outputContractDigestAlgorithmVersion / outputContractDigest
  admission.billing.billingReservationId
  admission.billing.pricingSnapshotId
  admission.billing.billingPolicyRevisionId

字段以正式 Contracts Schema 为准,但必须满足以下不变量:

  • Snapshot 描述准入事务创建时已经验证并冻结的引用,不携带可变对象全文。
  • run.created@2.0 对 Canonical Envelope 做严格 Refinement:correlationIdoperationId 都是必填、非空的稳定 ID;虽然通用 Envelope 允许其他事件省略 operationId,本事件缺少任一字段都必须拒绝。
  • executionManifestRef 是稳定、不透明、受授权解析的内部引用,executionManifestSchemaVersion 是创建时的严格版本;二者专门指向 Run 级 RunAdmissionManifest(已发布 Contracts 中 Run-level ExecutionManifest 的语义角色),首期 Explorer 只展示引用和版本,不通过它读取或复制正文。
  • aggregateIdrunId,租户、Actor 与关联 ID 统一使用 Envelope;Payload 不维护第二份可漂移副本。
  • requestId 是首次成功准入的公开 Request ID。幂等重放产生的新 Request ID 不改写该事件。
  • status 在本事件中只能表达创建时准入终点;当前纵切为 reserved,不能表示模型已执行或已结算。
  • Authentication 是严格四分支联合,只保存不透明资源 ID/Assertion/Delegation、严格 Schema Version 与 Claims Digest,不保存 Raw Session ID、Cookie、Secret、Authorization Header、Credential Digest 或可重放 Token。Developer Credential 与 Playground 分支必须含 Service Account;Customer Session 分支要求 actorPrincipalId == executionPrincipalId;Delegated Agent 分支要求 Execution Principal 是与本 Run 一对一的 agent_run Principal、同 Tenant 且与 Agent Revision 不可变绑定,Actor/授权范围与 Delegation Grant 相等。分支外字段、缺项、两个分支混合和伪造 Service Account 都拒绝。
  • Playground Grant、Customer Authentication Assertion、Delegation Grant 与 Authorization Decision 的 Ref/ID、Schema Version、Digest Algorithm Version、Digest 必须成组出现并与不可变 AuthorizationEvidenceArchive 相等。事件必须冻结准入时原子持久化的 AuthorizationEvidenceEvaluationSet@1 完整四元组、统一 authorizationEvidenceArchiveCutRevision、Authorization Scope Snapshot完整四元组、规范排序去重的authorizationActionIds[]authorizationActionCount和精确排序成员;authorizationActionCount必须等于Action数组长度,参与Event、Scope与Evaluation Set摘要,但不能替代精确成员集合。Set的Purpose/Operation/Authentication Kind、Actor/Execution Principal、Tenant/Scope/Audience、Action Count/集合、Archive Cut、成员集合与总结果必须和事件、Validation Record及RunAdmissionManifest逐项相等且result=valid。Scope Snapshot四元组还必须等于RunAdmissionManifest的executionAuthorization.authorizationScopeSnapshot*。Developer Credential恰好一项authorization_decision;Playground、Customer Session与Delegated Agent分别恰好再多一项对应Evaluation,不得漏项、夹带、重复、Kind错配或混用不同Cut。历史Projector先以事件冻结的Set四元组、Operation/AuthKind/主体/租户、Scope四元组、Action Count/集合与Cut调用readAuthorizationEvidenceEvaluationSet,严格验证Set/Count/成员全等后,再按Set内成员四元组与同一Cut调用readAuthorizationEvidenceEvaluation;不得把逐成员读取拼成原子Set,不按run.createdAt读取当前Revision,也不回查当前Session、Membership、Grant或Policy。事件只携带低敏Set/Scope/Action/成员身份,不携带Claims/Timeline正文;未知算法/Schema、Set/Scope/成员摘要、Action Count/成员、Revision或Cut错配、Set/成员缺失或非valid全部进入Quarantine。后到撤销只能影响新准入或追加Security Incident/Reconciliation事实,不得重算已提交Run的Evaluation Set。
  • admission.product 是冻结经济身份并必须等于 admission.source.surface:Developer Credential 为 developer_api,Playground Grant 为 developer_playground,Customer Session 还要求 productSurface 相等,Delegated Agent 还要求 originatingSurface 相等。只有 Delegated Agent 允许 agentRevisionId;MeterEvent 与 Operations Snapshot 必须逐项继承 Product/Agent Revision,不能由 Consumer 推断或覆盖。
  • Model 只保存已解析并冻结的 Offering、initial Execution Target 与 Routing Policy Revision;不包含 Provider Credential、物理路由配置或内部模型提示词。
  • Output Contract 只保存内容寻址的 outputContractRef + outputContractSchemaVersion + outputContractDigestAlgorithmVersion + outputContractDigest 四元组,不复制 Contract 正文。四项必须同时存在。Admission Producer 必须在提交事务内验证它与 RunAdmissionManifest 的冻结四元组逐项相等,并拒绝未知 Schema/算法、摘要错配或缺项;Projector 只按严格 Event Schema 校验并投影这组自包含字段,不解引用 Manifest 重新比较。
  • 不包含输入正文、Prompt、输出、参考素材、签名 URL、客户邮箱、IP 原文或原始错误。

run.created@2.0 与 RunAdmissionManifest 的同名字段必须逐项相等,包括完整Authentication Evidence、Product、Authorization Evidence、Authorization Evidence Evaluation Set(Set四元组、统一Archive Cut、Scope Snapshot四元组、Action集合、Count、精确成员、排序与成员四元组/Revision)、Delegated Agent Revision与Output Contract四元组。这项等值是Admission Producer同事务不变量:Producer必须在Event Append前以同一份已冻结Candidate比较,任一Actor/Tenant/Access/Authentication Evidence/Product/Authorization Evidence/Evaluation Set/Scope/Action/Offering/Initial Deployment/Routing Policy/Gateway Pool/Output Contract/Pricing/Billing Policy/Reservation字段缺失、未知或错配,都回滚Run、Manifest、Reservation、Event与Outbox;Producer/Contracts/Repository测试必须覆盖这些拒绝和原子回滚。run.created@2.0本身是Projector的完整投影输入;Projector验证Event严格Schema并以事件自包含的Set/Scope/Action/Cut构造Set Read,再严格读取成员;它不解引用Manifest,也不因无法解引用而声称完成或失败了Event↔Manifest运行时比较。executionManifestRef + executionManifestSchemaVersion只用于受授权追踪。事件中的modelDeploymentId只表示首次准入目标;首次Attempt必须使用它,后续重试只有在冻结Routing Policy允许时才能选择新Deployment并创建独立Attempt Manifest。历史Admission/Eligibility只使用已提交事件及其不可变证据,更新当前授权、Billing Policy或Output Contract不能改变重放结果。

首期 Producer 在同一发布门禁停止产生两个 v1,原子改为产生 run.created@2.0 + wallet.reserved@2.0;不得出现 Run v2 搭配 Wallet v1 的窗口。第一批 Producer Capability 只启用 Organization 下的 developer_credential | playground_execution_grantcustomer_session | delegated_agent 必须等对应产品的 Assertion/Delegation、Actor/Execution Principal、Billing 与端到端门禁完成后单独启用。Consumer 仍能按各自原 Schema 读取历史 v1,并在 limitations[] 标记 partial_legacy_event 和缺失原因。因为平台尚未上线,不为不存在的生产历史写复杂数据迁移或伪造缺失字段。Contracts 负向测试必须拒绝 Run v2 中缺失、空白或格式非法的 operationId / correlationId,Wallet v2 的 operationId / correlationId / causationId,以及任一 Authentication 分支缺项/混合、Claims/Decision 摘要或版本错配、Actor/Execution Principal/Assertion/Delegation 错配、跨 Run Agent Principal、Product/Surface 错配、Authorization Action Count缺失或不等于排序去重成员长度、Evaluation Count/完整四元组/Archive Revision 缺项、排序/去重/分支精确集合错误、Evaluation Purpose/Operation/Time/状态/Evidence 错配、Output Contract 四元组缺项/算法未知/摘要格式非法和后两个分支伪造 Service Account;还必须覆盖后到撤销不改变已冻结 Evaluation 的历史重放。Output Contract 正文摘要与 Ref/Schema 的内容一致性及 Event↔Manifest(含 Evaluation Set)等值由 Producer/Contracts Golden 与 Repository 原子回滚测试保证,Projector 测试不伪造 Manifest 解引用能力。

Legacy wallet.reserved@1.0

wallet.reserved@1.0 继续表达 Billing Domain 已完成的预占。它必须永远按已发布 Envelope 和 Payload 原样消费;operationIdcausationId 等可选字段不能在同版本中改成必填。当前严格 Payload 是 reservation,即既有 BillingReservationRef

reservation.billingReservationId
reservation.billingAccountId
reservation.runId
reservation.value
reservation.status

pricingSnapshotId 不在 wallet.reserved@1.0 Payload 中。不能在不升级 Wallet Event Version 的情况下假称 v1 已携带该字段,也不能要求历史 v1 必须拥有新的因果字段。

Legacy Consumer 遵循以下规则:

  • 严格校验 v1 原本要求的字段、类型、Aggregate 与 Payload 自洽性;缺少原本可选的 operationIdcausationId 仍是合法 v1,不能因此隔离。
  • v1 只能形成带 partial_legacy_event 的 Legacy/Partial 投影,不能参与新的完整 Versioned Admission Snapshot。
  • 若 v1 可选关联字段实际存在,Projector 可以在不猜测的前提下建立低置信度受限链接,但必须保留字段级 Lineage;缺失字段不能从时间、租户、金额、当前领域表或相邻日志补造。
  • 重放不能再次预占;同一 Reservation 的后续结算、释放或调整由新领域事件表达。
  • Wallet/Billing 领域仍是余额和账本的唯一事实源。

wallet.reserved@2.0

新的完整准入投影使用 Tenant-aware wallet.reserved@2.0。其 Envelope 通过事件类型 Refinement 强制非空 operationId + correlationId + causationId,Payload 为:

reservation.billingReservationId
reservation.billingAccountId
reservation.runId
reservation.pricingSnapshotId
reservation.billingPolicyRevisionId
reservation.value =
  { kind=credits; amount }
  | { kind=entitlement; entitlementKey; quantity; unit }
  | { kind=money; money={ amount; currency } }
reservation.status = active

这里是 Billing Reservation 状态,不是 Run 状态;wallet.reserved@2.0 创建时固定为版本化 BillingReservation 枚举中的 active,同一事务里的 Run 仍为 reservedreservation.value 复用 Contracts 的严格 BillingValue 判别联合:Credits 的 amount、Entitlement 的 quantity 与 Money 的 money.amount 都是同精度的规范 Decimal 字符串,禁止浮点转换;分支外字段、空白或非正数值一律拒绝。entitlementKey + unitcurrency 是经济身份的一部分,不能跨 Kind、Bucket、Unit 或 Currency 合并、比较或换算。

它遵循以下不变量:

  • 与 Run、Run Input、RunAdmissionManifest、幂等结果和 run.created@2.0 在同一 Admission 事务提交;causationId 指向本次 Run Event 的 eventId。Admission Producer 在 Event Append 前强制 reservation.value == RunAdmissionManifest.budgetAuthorization.reservedValue,包括 Kind、规范 Decimal 以及 Entitlement Key/Unit 或 Money Currency 的逐项等值;失败时整笔事务回滚,不能提交后留给 Projector 修复或隔离。
  • reservation.runId == run Event aggregateId;Wallet Event aggregateId == reservation.billingReservationId == run Event admission.billing.billingReservationId
  • reservation.billingAccountId == run.billingAccountIdreservation.pricingSnapshotId == run admission.billing.pricingSnapshotIdreservation.billingPolicyRevisionId == run admission.billing.billingPolicyRevisionId;Admission Producer 还必须在 Append 事务内验证三者与 RunAdmissionManifest 的冻结账务字段逐项相等。
  • 两个 Envelope 的 actorPrincipalId + tenantKind + tenantId + workspaceId + projectId? + correlationId + operationId 必须逐项相等;Wallet Actor 不能省略、改用 Billing 操作者或由当前 Membership 回填,可选 projectId 一侧有值而另一侧缺失同样不一致。
  • 首个 Producer 策略只接受 tenantKind=organization。Schema 已保留严格 Personal Space 分支,但在 tenant-aware Manifest、授权、Billing 与端到端门禁完成前不得启用。
  • Projector 独立严格验证 wallet.reserved@2.0 的自包含 BillingValue 分支,并只在已提交的 Run/Wallet 两个 Event 之间校验双方都携带的 ID、Actor、Tenant、Workspace/Project、Correlation/Operation、Billing Account、Reservation、Pricing、Billing Policy 与因果关系;这些跨 Event 字段冲突才进入 Quarantine 和 Snapshot Semantic Check。Projector 不解引用 RunAdmissionManifest,也不声称验证 reservation.value 与 Manifest reservedValue 的运行时等值;该不变量由前述 Producer/Contracts/Repository 测试保证。
  • 重放不能再次预占;后续结算、释放或调整使用新的版本化领域事件。

execution.attempt-eligibility.finalized@1

Execution每次为Attempt追加唯一ExecutionEligibilityFact@1时,必须在同一Execution事务追加Tenant-aware execution.attempt-eligibility.finalized@1,使Metering不依赖同步响应或进程内回调。schemaVersion=1的严格低敏Payload为:

AttemptEligibilityFinalized@1 = {
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId
  runId / runStepId / executionAttemptId
  attemptExecutionManifestRef / attemptExecutionManifestSchemaVersion
  attemptExecutionManifestDigestAlgorithmVersion / attemptExecutionManifestDigest
  executionEligibilityFactRef / executionEligibilityFactSchemaVersion
  executionEligibilityFactDigestAlgorithmVersion / executionEligibilityFactDigest
  terminalState = succeeded | failed | cancelled | timed_out
  dispatchDisposition =
    { state=gateway_bound;
      attemptRouteBindingRef / attemptRouteBindingSchemaVersion;
      attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest;
      gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion;
      gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest }
    | { state=not_dispatched;
        attemptNotDispatchedFactRef / attemptNotDispatchedFactSchemaVersion;
        attemptNotDispatchedFactDigestAlgorithmVersion / attemptNotDispatchedFactDigest;
        gatewayAttemptDispatchSlotId / gatewayPreBindingRequestId / gatewayDeploymentId }
  outputEligibility =
    { state=registered;
      outputFactRef / outputFactSchemaVersion;
      outputFactDigestAlgorithmVersion / outputFactDigest }
    | { state=not_required;
        outputContractRef / outputContractSchemaVersion;
        outputContractDigestAlgorithmVersion / outputContractDigest }
    | { state=unavailable; reasonCode }
    | { state=failed;
        executionFailureFactRef / executionFailureFactSchemaVersion;
        executionFailureFactDigestAlgorithmVersion / executionFailureFactDigest }
}

producer是认证后的Execution Workload;Envelope Actor/Tenant与Run Admission、Attempt Manifest和Fact逐项相等,Payload Tenant字段与Envelope相等。aggregateId=executionAttemptIdaggregateRevision=1,同Attempt终身只允许一个Fact和一个同摘要Event。Payload的Terminal、Dispatch与Output三部分必须与Owner Fact严格同构;Gateway-bound与Not-dispatched互斥,Not-dispatched/Failed分支必须完整绑定对应低敏Fact四元组,禁止原始错误、Prompt、Provider正文、URL或资产内容。Fact、嵌套Fact、Event、Canonical摘要、冻结Definition四元组或metering_input_processor Mandatory Delivery任一失败,Execution事务全部回滚。

Metering Consumer只在本地Inbox事务严格验证Event与Owner四元组,推进MeteringAttemptInputFence的Eligibility Watermark、insert-or-compare可恢复Work并写版本化Consumer Receipt后Ack。Gateway-bound分支可以等待Gateway Usage Availability;Not-dispatched分支不等待不存在的Gateway输入。Event先于Gateway输入、Consumer/Ack响应丢失或Worker崩溃都只能留下可恢复非终态Work,不能把Event Receipt当作Eligibility Decision、MeterEvent或Settlement Input。readExecutionEligibilityFact或后续Gateway Evidence Owner Read的确定性冲突必须分别返回内容寻址的ExecutionEligibilityConflictFact@1 | GatewayEvidenceConflictFact@1完整四元组;Metering同事务写MeteringInputWorkAttemptBlocked@1,把Fence置为coordinationState=blocked_on_owner_conflict,释放Lease但保留相同Work/Operation/Generation及activeWork.state=pending。该路径禁止写Work Finish、Eligibility Decision、Settlement Input、Lane终态CAS或reconciliationCaseRef;Owner修复后按同Work重新Lease,或由合法新Current Event创建后继Generation。首期没有这些Conflict Fact的Canonical Event与core_operations Mandatory Delivery,因此只能形成Owner诊断和明确标注不完整的best-effort告警,不能宣称Operations拥有可靠Admin队列。Contracts/跨进程测试必须覆盖四类Output、两类Dispatch、错Step/Manifest/Fact、半联合/未知字段、同Attempt第二Event、两类Conflict Fact/Blocked四元组错配、阻塞后同Work重试,以及Fact提交后在同步Metering调用或返回响应前崩溃仍最终生成规范Metering输入。

Attempt Binding Owner Read冲突使用独立内容寻址GatewayBindingConflictFact@1,不得拿Gateway Evidence Conflict Fact或泛conflictRef代替。Eligibility Lane选择MeteringInputWorkAttemptBlocked@1.blockingCause.kind=gateway_binding_owner_conflict;Provider Cost Lane必须选择外层provider_cost_processing_conflict,再由ProviderCostProcessingConflictEvidence@1.cause.kind=gateway_binding_owner_conflict绑定同一Fact。两条Lane不能互换外层Cause,任一Fact四元组、Purpose或Expected Attempt/Deployment错绑都拒绝。

Eligibility Basis、Availability Validation Receipt、Eligibility Decision、MeterEvent或Settlement Input构造/Repository的已证明本地确定性冲突使用EligibilityProcessingConflictEvidence@1,其validationStage严格为eligibility_basis | availability_validation_receipt | eligibility_decision | meter_event | settlement_input。Evidence绑定Run/Step/Attempt、Manifest/Execution Fact、Work/Operation/Generation、Lane Trigger与冲突Candidate摘要;它与MeteringInputWorkAttemptBlocked@1.blockingCause.kind=eligibility_processing_conflict原子提交,同样保持Active Work而不写Finished/CAS/Case。Provider Cost本地确定性校验同理由ProviderCostProcessingConflictEvidence@1.cause=metering_deterministic_validation冻结Stage与冲突Candidate带算法摘要,再由Blocked外层provider_cost_processing_conflict绑定。暂态依赖、网络、锁或容量错误不得伪造任何Evidence。

gateway.evidence-availability.current-changed@1

Text/Media Gateway每次为attempt-bound Usage或Cost链CAS推进Current Availability时,必须在Evidence(若有)、Availability Snapshot和Current/Active Head同一Gateway事务追加gateway.evidence-availability.current-changed@1。Pre-binding/no-execution Snapshot严格不得产生该Event。schemaVersion=1的封闭Payload为:

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使用Tenant-aware Envelope;producer是持有该Deployment身份的认证Gateway Workload,Actor/Tenant/Workspace/Project/Correlation必须与事件绑定的不可变Attempt Manifest相等。aggregateId由Contracts按executionAttemptId + gatewayDeploymentId + providerEvidenceKind + evidenceDimensionKey确定性派生,aggregateRevision=currentAvailabilityStateVersion。Payload必须与同事务Current Snapshot、Active Head、Binding/Route及Attempt Manifest四元组逐项相等;Snapshot为available时且仅此时currentEvidence=available并完整等于对应Usage/Cost Evidence四元组,其余状态固定none。Root/后继与Current Availability直接前驱五元组同构,第二Root、跳号、分叉和同Revision异摘要拒绝。

Gateway事务必须同时冻结适用Delivery Set四元组并创建唯一metering_input_processor Mandatory Delivery;任一Event/Digest/Member失败都回滚Evidence/Availability/Pointer。Metering Consumer只在Inbox事务推进相同Attempt/Kind/Dimension的Availability Watermark、insert-or-compare不可变Work和写版本化Consumer Receipt后Ack;旧合法Revision可already_observed,同Revision异摘要或跨Binding/Route/Kind/Dimension重绑隔离。Gateway Source正文只允许用绑定这条已接受Event完整ID/Type/Schema/Envelope摘要、Aggregate/Revision与Payload身份的metering_source_event_bootstrap读取;该Purpose不携带尚未从正文构造的Eligibility Basis、Provider Cost Candidate或Validation Operation,Bootstrap响应也不是Current Receipt。Usage Work与Execution Eligibility Watermark合流,Cost Work不等待客户Eligibility;新Revision必须重新置Pending。Cost Work对Gateway Availability的五种状态形成严格处理:available → available_applied并绑定ProviderCostFact与两份验证Receipt,pending → waiting_for_evidencenot_reported|unavailable → no_cost_evidence且不表示零成本;只有Gateway Owner已经持久化state=conflicting时才允许追加ProviderCostAvailabilityProcessingFact@1.outcome={state=reconciliation_required; availabilityState=conflicting; stateReasonCode}。该Processing Fact、Work Finish与Lane CAS同一Metering事务提交,以Processing Fact完整四元组作为Metering-owned耐久锚点;仅后继Gateway Availability Current-changed Event可创建新Generation恢复。

available路径中的确定性Schema/Identity/Mapping/Normalization/Receipt/Repository冲突不属于上述终态。Metering只追加内容寻址ProviderCostProcessingConflictEvidence@1MeteringInputWorkAttemptBlocked@1,把Fence置为coordinationState=blocked_on_processing_conflict,释放Lease但保留同一Work/Operation/Generation及activeWork.state=pending;严格禁止写Processing Fact、Work Finish、ProviderCostFact或Lane终态CAS。修复Owner/Registry/Repository状态后以同Work重新Lease,合法新Current Event仍可Supersede旧Work。Owner暂不可读、超时、锁冲突或其他可重试错误连Conflict Evidence/Blocked Fact也不写,仅返回retryable。所有分支都不创建或引用第三种Reconciliation Case。当前十三Pair Delivery Set没有Provider Cost Processing/Conflict Event,首期只保证Metering定向诊断和明确标注不完整的best-effort告警,不得声称Operations拥有完整队列;可靠Admin投影必须以后续Canonical Event、core_operations Mandatory Delivery、Owner Read和严格Projection契约为前置。Contracts和跨进程测试覆盖全部Availability状态、Gateway-conflicting终态、确定性冲突Blocked后同Work重试、暂态错误零领域Fact/Finish/CAS、Evidence四元组裁剪/错摘要、A1/E1完成后A2/E2提交但同步响应/Observation丢失且无后续Poll、Event Ack后Worker崩溃、乱序/合并、同Ref异摘要、Pre-binding误发与Event/Current原子回滚。

execution.run-finalization.closed@1

Execution把Run的Attempt Admission不可逆地从accepting_attempts推进为attempts_closed时,必须在同一Execution事务追加RunAttemptSetManifest@1RunExecutionFinalizationFact@1和Tenant-aware execution.run-finalization.closed@1。该Event是Billing Finalization Coordinator的必达触发事实,不是“已完成结算”的状态。其schemaVersion=1 Payload为:

RunFinalizationClosed@1 = {
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId
  closureOperationId
  runAdmissionManifestRef / runAdmissionManifestSchemaVersion
  runAdmissionManifestDigestAlgorithmVersion / runAdmissionManifestDigest
  runExecutionFinalizationRef / runExecutionFinalizationSchemaVersion
  runExecutionFinalizationDigestAlgorithmVersion / runExecutionFinalizationDigest
  runExecutionFinalizationStateVersion
  attemptSetManifestRef / attemptSetManifestSchemaVersion
  attemptSetManifestDigestAlgorithmVersion / attemptSetManifestDigest
  attemptCount
}

producer必须是认证后的Execution Workload;Envelope Actor/Tenant/Workspace/Project与不可变Run Admission/Finalization Fact逐项相等,Payload重复Tenant字段还必须与Envelope相等。Envelope operationId == closureOperationIdaggregateId == runIdaggregateRevision=1;同一Run终身只能有一个Closure Event。Payload中的Finalization Fact与Attempt Set Manifest四元组、State Version、Attempt Count必须和同事务Owner对象双向等值,Run Admission Manifest四元组必须与所有Attempt Manifest冻结值一致。关闭CAS、Owner Fact/Manifest、Event、Canonical Envelope Digest、Delivery Set Definition四元组或billing_finalization_coordinator Mandatory Delivery任一失败,整笔Execution事务回滚;关闭后不得新增Attempt、重开Run或产生第二个Event。

Billing Consumer只能把该Event用于推进BillingFinalizationFence@1的Execution Closure Watermark。它必须验证完整Event与Owner四元组,在单一Billing Inbox事务冻结新的BillingFinalizationTriggerSnapshot@1、递增Fence Revision/Work Generation、insert-or-compare BillingFinalizationWork@1并写版本化Consumer Receipt后才Ack;不能把Event本身当作Finalization Decision、Ledger或Reservation终态。每代Work的billingFinalizationOperationId必须由Contracts固定Namespace按billingReservationId + runId + workGeneration + Trigger Snapshot完整摘要确定性派生并持久化,响应丢失或Worker重启恢复同一Operation。Execution的Precondition/Finalization Owner Read或Current Validation若返回确定性冲突,只能返回内容寻址RunExecutionFinalizationConflictFact@1完整四元组,不得返回或预先创建reconciliationCaseRef;Billing把该Conflict Fact冻结进Finalization输入并由正式Finalization Decision决定是否按下节Run级Identity协议创建Operations Case。Owner暂不可读仍为retryable,不生成Conflict Fact或Case。

Contracts与跨进程测试必须覆盖Attempt集合空/非空、Count/排序、Fact/Manifest/Event任一四元组裁剪或摘要错配、跨Tenant/Account/Reservation/Run重绑、同Run第二Event、关闭CAS后Event/Delivery失败回滚、Event早于Fence异常可见、Consumer/Ack响应丢失,以及Execution关闭后在任何同步Billing调用或排队前崩溃仍由Mandatory Delivery创建可恢复Finalization Work。

billing.finalization-reconciliation.case-requested@1

Finalization Work首次对某一代判定reconciliation_required前,Billing必须先通过Operations的无业务Case副作用预留契约取得稳定Case Ref。预留不创建可见Case;Billing随后才在同一Finalization事务追加reconciliation_required Decision、推进Fence、完成本代Work,并发布Tenant-aware billing.finalization-reconciliation.case-requested@1schemaVersion=1的封闭Payload为:

FinalizationReconciliationCaseIdentityReservation@1 = {
  finalizationCaseIdentityReservationRef / finalizationCaseIdentityReservationSchemaVersion
  finalizationCaseIdentityReservationDigestAlgorithmVersion=jcs-sha256-v1
  finalizationCaseIdentityReservationDigest
  reconciliationCaseRef
  sourceOwner=billing / sourceKind=billing_finalization
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId / billingFinalizationFenceId
  reconciliationGeneration / caseRequestOperationId
  predecessorCase =
    { state=root }
    | { state=supersedes; previousReconciliationGeneration; previousReconciliationCaseRef;
        previousFinalizationCaseIdentityReservationRef / previousFinalizationCaseIdentityReservationSchemaVersion;
        previousFinalizationCaseIdentityReservationDigestAlgorithmVersion / previousFinalizationCaseIdentityReservationDigest }
  reservedAt
}

FinalizationReconciliationCaseRequestedEvent@1 = {
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId / billingFinalizationFenceId
  reconciliationCaseRef / reconciliationGeneration / expectedResolutionRevision=1
  caseRequestOperationId / billingFinalizationOperationId
  finalizationCaseIdentityReservationRef / finalizationCaseIdentityReservationSchemaVersion
  finalizationCaseIdentityReservationDigestAlgorithmVersion / finalizationCaseIdentityReservationDigest
  billingFinalizationDecisionRef / billingFinalizationDecisionSchemaVersion
  billingFinalizationDecisionDigestAlgorithmVersion / billingFinalizationDecisionDigest
  triggeringBillingFinalizationWorkRef / triggeringBillingFinalizationWorkSchemaVersion
  triggeringBillingFinalizationWorkDigestAlgorithmVersion / triggeringBillingFinalizationWorkDigest
  triggeringBillingFinalizationWorkGeneration
  reasonCode
}

readBillingFinalizationDecisionForOperations(
  purpose=operations_finalization_case_projection,
  caseRequestedEvent={ eventId / eventType / eventSchemaVersion;
    eventEnvelopeDigestAlgorithmVersion / eventEnvelopeSha256 },
  expected tenantKind, tenantId, workspaceId, projectId?, billingAccountId,
  billingReservationId, runId, billingFinalizationFenceId,
  reconciliationCaseRef, reconciliationGeneration, expectedResolutionRevision=1,
  caseRequestOperationId, billingFinalizationOperationId,
  finalizationCaseIdentityReservation完整四元组,
  billingFinalizationDecision完整四元组,
  triggeringBillingFinalizationWork完整四元组, triggeringBillingFinalizationWorkGeneration
)
  -> { result=found; decision=BillingFinalizationDecision@1; triggeringWork=BillingFinalizationWork@1 }
   | { result=not_found }
   | { result=conflicting; conflictRef / conflictSchemaVersion;
       conflictDigestAlgorithmVersion / conflictDigest }

PendingFinalizationCaseSuccessor@1 = {
  projectionName / projectionVersion
  sourceOwner=billing / sourceKind=billing_finalization
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId / billingFinalizationFenceId
  successorReconciliationCaseRef / successorReconciliationGeneration
  successorFinalizationCaseIdentityReservation完整四元组
  predecessorCase = { state=supersedes; previousReconciliationGeneration;
    previousReconciliationCaseRef; previousFinalizationCaseIdentityReservation完整四元组 }
  caseRequestOperationId / billingFinalizationOperationId / expectedResolutionRevision=1
  caseRequestedEvent={ eventId / eventType / eventSchemaVersion;
    eventEnvelopeDigestAlgorithmVersion / eventEnvelopeSha256 }
  billingFinalizationDecision完整四元组
  triggeringBillingFinalizationWork完整四元组 / triggeringBillingFinalizationWorkGeneration
  reasonCode
  state = { kind=pending }
    | { kind=consumed; predecessorResolutionEvent完整四元组;
        predecessorResolutionAppliedFact完整四元组;
        successorMaterializedCaseRevision; consumedAt }
  firstSeenAt
}

caseRequestOperationId由Contracts固定Namespace按规范化sourceOwner/sourceKind + tenantKind/tenantId/workspaceId/projectId? + billingReservationId/billingAccountId/runId/billingFinalizationFenceId + reconciliationGeneration确定性派生。reserveFinalizationReconciliationCaseIdentityreadFinalizationReconciliationCaseIdentityBySource只接受精确Billing Finalization Case Identity Workload Audience/Scope;请求/Token绑定Tenant、Account/Reservation/Run/Fence、Generation、Operation与Predecessor,服务端重算Operation和摘要,严格返回reserved|found|not_found|conflicting{conflict Reservation quartet},禁止Admin、列表、latest或裸Ref读取。Reservation摘要覆盖除Repository-owned Ref/Time和摘要自身外的完整稳定Identity;不得包含Triggering Work或billingFinalizationOperationId。同Source/Generation重放采用原Reservation;reserve(G1) → G2 Work supersedes G1 → G1 CAS失败 → G2必须复用同Identity。

producer必须是认证后的Billing Workload;Envelope Actor/Tenant/Workspace/Project和Payload租户字段与Run/Fence/Decision逐项相等,operationId == caseRequestOperationIdaggregateId == reconciliationCaseRefaggregateRevision=1;Case Ref必须来自完整FinalizationReconciliationCaseIdentityReservation@1四元组,不得在Event投影时临时生成。Identity只冻结稳定Tenant/Account/Reservation/Run/Fence/Generation/Case Request Operation/Predecessor,不绑定可被并发后继超越的Work或Finalization Operation;Event中显式billingFinalizationOperationId与最终Winning Work四元组才是投影精确Owner Read的输入。Payload中Tenant、Account/Reservation/Run/Fence、Case/Generation/Expected Resolution Revision/Case Request Operation、Identity Reservation、Billing Finalization Operation、Decision、Triggering Work与Reason必须和同事务Fence/Work Finish/Decision及已预留Identity双向等值。Operations Projector只能以Event完整四元组与全部Expected身份调用readBillingFinalizationDecisionForOperations;Owner和Projector双方重算摘要,not_found保持Delivery non-terminal,conflicting隔离,禁止回查当前Fence或按裸Ref读取。Decision、Fence、Work Finish、Audit、Event、Canonical Envelope Digest、冻结Delivery Set Definition四元组或唯一core_operations → operations_projector Mandatory Delivery任一失败,整笔Billing事务回滚。

Operations Projector只能在验证Event、Identity Reservation、Billing Decision和Triggering Work完整四元组后,按预分配Ref幂等创建sourceKind=billing_finalization的Run级Case;投影不得读取当前Fence猜测创建输入。同Event同摘要返回首次Applied Receipt;同Case/代次异Identity、Decision、Work或Reason进入Quarantine且不产生Case副作用。Identity或Owner Fact暂不可读时不写Receipt,保持Delivery非终态重试。Operations可拥有调查、评论、指派和审批时间线,但只有消费Billing-owned Resolution Applied Event才能使该业务Case进入终态。

若后继Case Requested先于直接前代的Billing Resolution终态到达,Projector必须锁定同Source的前代与Pending集合,将上述严格PendingFinalizationCaseSuccessor@1(state=pending)和本Event的OperationsProjectionAppliedReceipt@1在同一事务insert-or-compare后Ack,不得创建第二个Open Case或丢弃已Ack的后继。前代Resolution到达时,若前代Case已存在,必须在一个Operations事务验证并终结前代、物化后继并把Pending推进为consumed,冻结前代Resolution Event完整Envelope与Applied Fact四元组;若前代Request仍缺失,则先保存既有pending_resolution,待其到达后在同一事务直接物化Resolved前代、消费后继并创建后继。多代乱序按Generation和完整Predecessor Identity消费最大连续已验证链,至多最后一代可Open。C2 Request → C1 Resolution → C1 Request、Resolution/Request并发、同代异Candidate和Shadow Rebuild必须确定性收敛。

Contracts/Repository/跨进程测试覆盖预留响应丢失后按Source/Generation/Operation恢复同一Identity、reserve(G1) → G2 Work supersedes G1 → G1 CAS失败 → G2复用同Identity并以自己Operation/Work成功提交、Event与Identity/Decision/Winning Work/Fence/Finalization Operation任一错配、同Case异摘要、Case Request投影响应丢失不创建第二Case、C2 Request → C1 Resolution → C1 Request的Pending Successor原子消费、Owner Read暂不可用保持Delivery非终态,以及Decision/Fence/Work/Event/Delivery中途失败无半完成状态。

billing.finalization-reconciliation-resolution.applied@1

Billing Finalization进入reconciliation_required后,Operations只能编排受控调查与授权;Billing验证当前Case代次、Resolution Decision、一次性Command Grant与已授权调查引用集合后,必须在同一Billing事务追加FinalizationReconciliationResolutionApplied@1与Tenant-aware billing.finalization-reconciliation-resolution.applied@1。该Event只表示“受控重评授权已应用”的必达触发事实,不声称Owner事实已经修复,也不是Ledger、Reservation终态或忽略冲突的命令。schemaVersion=1的封闭Payload为:

FinalizationReconciliationResolutionCommandRequest@1 = {
  finalizationReconciliationResolutionCommandRequestRef / finalizationReconciliationResolutionCommandRequestSchemaVersion
  finalizationReconciliationResolutionCommandRequestDigestAlgorithmVersion=jcs-sha256-v1
  finalizationReconciliationResolutionCommandRequestDigest
  adminCommandId / domainIdempotencyKey / actorWorkforcePrincipalId
  tenantKind / tenantId / workspaceId / projectId?
  billingAccountId / billingReservationId / runId / billingFinalizationFenceId
  reconciliationCaseRef / reconciliationGeneration / expectedCaseRevision / expectedResolutionRevision=1
  finalizationCaseIdentityReservation完整四元组
  caseRequestEventId / caseRequestEventType / caseRequestEventSchemaVersion
  caseRequestEventEnvelopeDigestAlgorithmVersion / caseRequestEventEnvelopeSha256
  action=reevaluate_current_owner_state
  investigationEvidenceReferenceCount
  investigationEvidenceReferences[]=sorted { ownerDomain=execution|metering|gateway|billing; evidenceKind;
    evidenceRef / evidenceSchemaVersion / evidenceDigestAlgorithmVersion / evidenceDigest }
  reasonCode
}

FinalizationReconciliationResolutionDecision@1 = {
  resolutionDecisionRef / resolutionDecisionSchemaVersion
  resolutionDecisionDigestAlgorithmVersion=jcs-sha256-v1 / resolutionDecisionDigest
  resolutionDecisionInputDigestAlgorithmVersion=jcs-sha256-v1 / resolutionDecisionInputDigest
  resolutionDecisionIdempotencyKey
  finalizationReconciliationResolutionCommandRequest完整四元组
  adminCommandCandidate完整四元组
  actorWorkforcePrincipalId
  tenantKind / tenantId / workspaceId / projectId?
  billingAccountId / billingReservationId / runId / billingFinalizationFenceId
  reconciliationCaseRef / reconciliationGeneration / expectedCaseRevision / expectedResolutionRevision=1
  finalizationCaseIdentityReservation完整四元组
  caseRequestEventId / caseRequestEventType / caseRequestEventSchemaVersion
  caseRequestEventEnvelopeDigestAlgorithmVersion / caseRequestEventEnvelopeSha256
  action=reevaluate_current_owner_state
  investigationEvidenceReferenceCount
  investigationEvidenceReferences[]=FinalizationReconciliationResolutionCommandRequest@1.investigationEvidenceReferences[]
  decision=authorized / decidedAt
}

FinalizationReconciliationResolutionApplied@1 = {
  finalizationReconciliationResolutionAppliedRef / finalizationReconciliationResolutionAppliedSchemaVersion
  finalizationReconciliationResolutionAppliedDigestAlgorithmVersion=jcs-sha256-v1
  finalizationReconciliationResolutionAppliedDigest
  resolutionOperationId
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId / billingFinalizationFenceId
  reconciliationCaseRef / reconciliationGeneration / resolutionRevision=1
  finalizationCaseIdentityReservation完整四元组
  caseRequestEventId / caseRequestEventType / caseRequestEventSchemaVersion
  caseRequestEventEnvelopeDigestAlgorithmVersion / caseRequestEventEnvelopeSha256
  finalizationReconciliationResolutionCommandRequest完整四元组
  adminCommandCandidate完整四元组
  finalizationReconciliationResolutionDecision完整四元组
  commandExecutionGrantRef / commandExecutionGrantSchemaVersion
  commandExecutionGrantDigestAlgorithmVersion / commandExecutionGrantDigest / commandExecutionGrantJti
  action=reevaluate_current_owner_state
  investigationEvidenceReferenceCount
  investigationEvidenceReferences[]=FinalizationReconciliationResolutionCommandRequest@1.investigationEvidenceReferences[]
  actorWorkforcePrincipalId / appliedAt
}

FinalizationReconciliationResolutionAppliedEvent@1 = {
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId / billingFinalizationFenceId
  reconciliationCaseRef / reconciliationGeneration / resolutionRevision=1 / resolutionOperationId
  finalizationCaseIdentityReservationRef / finalizationCaseIdentityReservationSchemaVersion
  finalizationCaseIdentityReservationDigestAlgorithmVersion / finalizationCaseIdentityReservationDigest
  finalizationReconciliationResolutionAppliedRef / finalizationReconciliationResolutionAppliedSchemaVersion
  finalizationReconciliationResolutionAppliedDigestAlgorithmVersion / finalizationReconciliationResolutionAppliedDigest
  action = reevaluate_current_owner_state
}

readFinalizationReconciliationResolutionAppliedForOperations(
  purpose=operations_finalization_case_projection,
  resolutionEvent={ eventId / eventType / eventSchemaVersion;
    eventEnvelopeDigestAlgorithmVersion / eventEnvelopeSha256 },
  expected tenantKind, tenantId, workspaceId, projectId?, billingAccountId,
  billingReservationId, runId, billingFinalizationFenceId,
  reconciliationCaseRef, reconciliationGeneration, resolutionRevision=1,
  resolutionOperationId, actorWorkforcePrincipalId,
  finalizationCaseIdentityReservation完整四元组,
  finalizationReconciliationResolutionApplied完整四元组
)
  -> { result=found; fact=FinalizationReconciliationResolutionApplied@1 }
   | { result=not_found }
   | { result=conflicting; conflictRef / conflictSchemaVersion;
       conflictDigestAlgorithmVersion / conflictDigest }

readFinalizationReconciliationResolutionAppliedByOperation(
  resolutionOperationId,
  expected tenantKind, tenantId, workspaceId, projectId?, billingAccountId, billingReservationId, runId,
  billingFinalizationFenceId, reconciliationCaseRef, reconciliationGeneration,
  resolutionRevision=1, actorWorkforcePrincipalId,
  finalizationCaseIdentityReservation完整四元组,
  finalizationReconciliationResolutionCommandRequest完整四元组,
  adminCommandCandidate完整四元组,
  finalizationReconciliationResolutionDecision完整四元组,
  signedWorkforceCommandExecutionGrant完整四元组 / commandGrantJti
)
  -> { result=found; fact=FinalizationReconciliationResolutionApplied@1 }
   | { result=not_found }
   | { result=conflicting; conflictRef / conflictSchemaVersion;
       conflictDigestAlgorithmVersion / conflictDigest }

Request、Decision与Fact摘要都排除Repository-owned Ref/Time和摘要自身;Request不含Candidate/Decision/Grant/Fact/Operation,Decision不含Grant/Operation。通用AdminCommandCandidate@1使用commandType=finalization_reconciliation_resolution,且其既有commandRequest.payload严格选择本Request分支并保存完整四元组;不得另造第二个Candidate specialization字段。只有SignedWorkforceCommandExecutionGrant@1.commandSpecialization.kind=finalization_reconciliation_resolution逐项回显Request稳定身份,并额外绑定Decision完整四元组和由其确定性派生的resolutionOperationId。依赖顺序固定为:先冻结Request业务Payload,Preview/Approval/JIT基于它完成,最终Candidate聚合全部,Operations在Candidate后形成Decision,Core最后签Grant;因此不存在摘要环。Grant aud=billing_finalization_reconciliation_resolution_commandboundWorkload=Admin Command Gateway Workload Principal且等于实际呈递Domain调用的Caller JWT sub,Grant sub=actorWorkforcePrincipalId;动作唯一为reevaluate_current_owner_state。任何对象都禁止金额、Ledger、Reservation终态、替代Snapshot、忽略冲突或自由Map。调查引用必须非空、按Contracts Registry的封闭Tuple排序去重并与Count等值,只用于授权与审计关联;Billing只验证Request/Candidate/Decision/Grant/Fact之间集合等值及注册Schema,不得解引用它们来证明Owner已经修复。真正安全性由触发后既有Finalization严格Owner Reads与Current Receipts保证;Owner状态仍冲突时重评必须创建新Case代次。当前ADR-030阶段不启用此命令;任何Producer可能进入reconciliation_required前,必须与ADR-031完整命令链同批启用。

Command Grant Exchange本身也必须能从“Core已提交Grant但响应丢失”恢复。commandGrantExchangeOperationId由Contracts固定Namespace仅按actorAssertionIssuer + actorAssertionJti确定性派生;两字段分别逐字节等于已验证Actor Assertion JWT的iss + jti。Candidate不进入Operation ID,而与Bound Workload、Request Digest/Nonce、Actor一起成为首次Result的insert-or-compare正文,使同JTI偷换任何正文稳定命中conflicting。Core持久化内容寻址CommandGrantExchangeResult@1,完整绑定Operation、actorAssertionIssuer + actorAssertionJti、Actor、Bound Workload、Request Digest/Nonce、Candidate quartet、Grant quartet/JTI。readCommandGrantExchangeResultByOperation(operationId, expected actorAssertionIssuer/actorAssertionJti/commandType/actor/boundWorkload/requestDigest+nonce/Candidate quartet)严格返回found{result; grant=SignedWorkforceCommandExecutionGrant@1} | not_found | conflicting{conflict quartet}。Core先认证Caller Workload JWT并要求sub == boundWorkload,随后在检查Assertion当前时间/JTI前执行该Read:found同输入返回首次Grant,即使Assertion已过期或JTI已消费;conflicting停写;仅not_found才校验Assertion、消费JTI,并在一个事务写Grant、Result与签发Audit。Grant/Result摘要或Audit任一失败全部回滚。

Billing命令入口必须在Grant时间窗/JTI或当前Fence检查之前调用readFinalizationReconciliationResolutionAppliedByOperationfound时完整比较Actor、Request/Candidate/Decision/Grant/JTI并返回首次Fact,即使Grant已过期或JTI已消费;conflicting停写;仅not_found进入新执行。producer必须是认证后的Billing Workload;Envelope Tenant/Workspace/Project、Payload租户字段与Owner Fact必须逐项相等,Envelope actorPrincipalId == FinalizationReconciliationResolutionApplied@1.actorWorkforcePrincipalId,且该Actor必须继续等于Resolution Decision Actor、Command Grant sub、Candidate Actor与Audit Actor;operationId == resolutionOperationId。每个Reconciliation Generation只允许一次Resolution Applied:Case Requested/Request/Decision/Grant固定expectedResolutionRevision=1,Applied Fact/Event固定resolutionRevision=1;重评仍冲突必须开启后继Generation。aggregateId由Contracts固定Namespace按billingFinalizationFenceId + reconciliationGeneration确定性派生,aggregateRevision=1,每个Aggregate只有该Event;同Revision异摘要或跨Fence/Case/代次重绑拒绝。Payload中Identity Reservation与Resolution Fact两个完整四元组、Case/Generation/Revision/Operation与Action必须与同事务Owner Fact双向等值;Fact又必须绑定同一Identity、已投影Case Request Event完整Envelope摘要、Request/Candidate/Decision、Command Grant JTI和排序的Investigation Evidence References。Operations Projector只用Event四元组及Expected身份调用readFinalizationReconciliationResolutionAppliedForOperations,双方重算Fact摘要;Owner暂不可读返回retryable且不得写Outcome/Receipt。Fact、Grant消费、Audit、Event、Canonical Envelope Digest、冻结Delivery Set Definition四元组或billing_finalization_coordinator + core_operations两条Mandatory Delivery任一失败,整笔Billing事务回滚。

Coordinator收到事件后先严格验证Event/Identity/Fact与当前Fence。若仍是同一Case/代次和期望Resolution Revision,它必须在单一Billing Inbox事务单调推进reconciliationResolutionWatermark,把该Watermark冻结进新BillingFinalizationTriggerSnapshot@1,产生新Generation的内容寻址BillingFinalizationWork@1,再与BillingFinalizationCoordinatorConsumerReceipt@1同事务Ack。只有同一Resolution Event已经成功应用并创建了它自己的重评Work,或该Work的重评已推进/被该次Resolution吸收时,重投才可返回绑定原Event/Identity/Fact与当时Fence Revision的already_superseded Receipt;普通Closure/Settlement Owner输入在Case持有态只推进Watermark(Settlement返回held Receipt),不能创建后继Work或使Resolution变成superseded。Owner Fact暂不可读、Fence锁不可用或无法判定Current/Stale时返回retryable且不写Receipt/Ack;摘要或身份冲突才是non_retryable。同一Event的core_operations投影只能在验证Billing Fact、Identity与Case Request身份后将对应Operations Case进入Billing-authoritative终态,不得因Coordinator先行接收就本地关闭Case。

Contracts Golden与跨进程测试必须覆盖Current Resolution创建唯一后继Work、同一Resolution已应用/重评推进后的重投返回already_superseded、Closure/Settlement先到只推进Watermark且不得令Resolution superseded、同Event/Ack响应丢失幂等、Fact或Case/Generation/Revision/Operation/Fence错绑、Envelope/Decision/Grant/Candidate/Audit跨Actor重绑、同Revision异摘要、旧Grant跨代重放、二次评估仍冲突则创建新Case代次,以及Fact/Event/Delivery中途失败不留半完成状态。

metering.settlement-input.current-changed@1

Metering 每次原子追加 SettlementInputSnapshot@1 并推进该维度 Current Pointer 时,都必须在同一 Metering 事务追加 Tenant-aware metering.settlement-input.current-changed@1。这不是可以丢失的遥测通知,而是终局后结算更正的必达唤醒事实。其 Event Type 与 schemaVersion=1 是精确字面量,Payload 为未知字段拒绝的封闭 DTO:

SettlementInputCurrentChanged@1 = {
  tenantKind / tenantId / workspaceId / projectId?
  billingReservationId / billingAccountId / runId / runStepId
  executionAttemptId / chargeDimensionKey
  settlementEconomicIdentity = SettlementEconomicIdentity@1
  currentSettlementInputSnapshotRef / currentSettlementInputSnapshotSchemaVersion
  currentSettlementInputSnapshotDigestAlgorithmVersion / currentSettlementInputSnapshotDigest
  currentSettlementInputStateVersion
  supersedesSettlementInputSnapshot =
    { state=root }
    | { state=supersedes; ref; schemaVersion; digestAlgorithmVersion; digest; stateVersion }
}

该事件使用 Tenant-aware Canonical Envelope;producer 必须是认证后的 Metering Workload,Envelope 的 actorPrincipalId + tenantKind + tenantId + workspaceId + projectId? 必须与 Owner Snapshot 逐项相等,Payload 中重复的 Tenant 字段还必须与 Envelope 严格等值。correlationId 必填;operationId / causationId / traceId沿用Canonical Envelope的可选性,存在时也只追踪原Metering操作/因果/遥测,任何Consumer都不得用它们替代Snapshot五元组、直接前驱或Billing操作身份。

aggregateId 是 Contracts 固定 Namespace 按 (billingReservationId, runStepId, executionAttemptId, chargeDimensionKey) 确定性派生的 Settlement Dimension ID;aggregateRevision == currentSettlementInputStateVersion。Revision 1 只允许 state=root;后续 Revision 只允许 state=supersedes,且其中 Ref/Schema Version/Digest Algorithm Version/Digest/State Version 五元组必须完整指向同一维度、同一经济身份的 Current 直接前驱,predecessor.stateVersion + 1 == aggregateRevision。Payload、同事务 Snapshot 正文和提交后的 Current Pointer必须逐项等值;同一 Snapshot 事务恰好产生一个同 eventId + eventEnvelopeDigestAlgorithmVersion + eventEnvelopeSha256 的 Event,并冻结适用 Delivery Set完整四元组及 billing_settlement_catch_up Mandatory Delivery。Snapshot、Pointer、Event、Digest、Definition或Delivery Row任一失败,整笔 Metering事务回滚。

Billing Consumer只能把该Event解释为“一个完整Settlement Input版本需要被追平”:它不能据此写Ledger、构造Transition或宣称已结算。Consumer按Event自带身份和完整Snapshot五元组单调推进SettlementInputWakeupWatermark。Reservation尚未成功Finalization且Fence不在Case中时,它必须在同一Inbox事务推进Admission时已创建的BillingFinalizationFence、冻结新的Trigger Snapshot并产生/合并Finalization Work;Fence处于reconciliation_required时只单调推进Watermark并返回绑定Finalization Fence Revision、Case/Generation/Expected Resolution Revision的held_for_resolution Receipt,严格不创建Work、不退出Case,只由后续同代Current Resolution Applied新Trigger一次性吸收这些Watermark。成功Finalization后则重新打开对应BillingSettlementCatchUpFence并insert-or-compare内容寻址的BillingSettlementCatchUpWork@1。Catch-up Receipt必须冻结Fence Revision、Work完整四元组/Generation与确定性billingCatchUpValidationOperationId,并与同事务Fence Active Work逐项相等。若Catch-up Worker从readSettlementInput或Current Validation得到确定性冲突,它必须持久化内容寻址SettlementInputConflictFact@1BillingSettlementCatchUpWorkAttemptBlocked@1完整四元组,把Fence置为coordinationState=blocked_on_owner_conflict,保留同一Work/Operation/Generation及activeWork.state=pending并释放Lease;不得写Finished、把Fence推进终态、创建/引用Operations Case或伪造held_for_resolution。修复后同Work重试;本地CAS竞争本身只重基线或retryable,不伪造Owner Conflict Fact。若极端乱序令Finalization Fence尚不可绑定,只能先耐久保存Inbox Watermark并返回retryable,不得写成功Receipt或Ack后永久停在awaiting_finalization。Ack只证明Watermark与所选Fence/Work/持有结果、版本化Consumer Receipt已经原子提交,不证明Snapshot已被Billing消费。真正的Current线性化仍必须使用readSettlementInputvalidateSettlementInputCurrent(purpose=billing_catch_up_fence),其中billingCatchUpValidationOperationIdpurpose + BillingCatchUp Basis带算法摘要 + 待验证Snapshot五元组确定性派生;该Receipt不能替代post_finalization_transition Receipt或驱动Ledger。上述Owner-local Conflict Fact首期没有Canonical Event与core_operations Mandatory Delivery,只能用于Owner诊断和不完整best-effort告警。

Contracts Golden、Producer/Repository、Dispatcher/Billing Inbox与跨进程测试必须拒绝缺失/裁剪五元组、未知Schema/算法、同Revision异Digest、第二Root、跳号/分叉/错前驱、跨Tenant/Account/Reservation/Run/Step/Attempt/Dimension/经济身份重绑、弱changed=true Payload和同Snapshot重复Event。恢复测试至少覆盖Event先于/晚于Finalization、Ack后Consumer或Dispatcher崩溃、较旧合法Revision的already_observed、Receipt与新Snapshot竞态、S2→S3合并追平,以及S1 Receipt → S2 Event先到且已Ack → Finalization按S1提交 → 此后没有S3仍由早到Watermark与Finalization自建Work最终追平S2。

结算与对账经济边界事件

Operations 不能从 Wallet 当前状态、Ledger 表、Case 文案或 Observation 反推经济边界。Contracts 固定下列五个 Tenant-aware Canonical Event,Payload 都是严格、低敏、未知字段拒绝的 DTO:

Event TypePayload Contract唯一 Producer
billing.finalization.committed@1BillingFinalizationCommitted@1Billing
billing.settlement-transition.committed@1BillingSettlementTransitionCommitted@1Billing
billing.late-settlement-exposure.case-requested@1LateSettlementExposureCaseRequested@1Billing
billing.case-resolution.applied@1BillingCaseResolutionApplied@1Billing
billing.late-settlement-command-result.committed@1LateSettlementCommandResultCommitted@1Billing

五类事件都强制非空 correlationId + operationId + causationId,Tenant/Workspace/Project 与原 Run/Reservation 一致。它们不共用 Dimension State Revision 冒充 Event Aggregate Revision:aggregateId 固定为当次不可变 Owner Fact/Result Ref,aggregateRevision=1;领域先后关系由 Payload 内 State/Exposure Revision 与 Envelope causationId 表达。这避免同一 Billing 事务中 Transition、Exposure/Case Request、Command Result 与 Applied Fact 争用同一 Aggregate Revision。自动 Finalization/Transition/Case Request 的 actorPrincipalId 继承 Run 不可变 Actor,不用 Billing Workload 冒充业务主体;Late Command Result 使用已授权 Workforce Actor,Applied 事件按其 Source 继承 Run 或 Workforce Actor。producer 始终是已认证 Billing Workload。

经济价值种类复用下列严格联合:

SettlementEconomicIdentity@1 =
  { kind=credits }
  | { kind=entitlement; entitlementKey; unit }
  | { kind=money; currency }

billing.finalization.committed@1

Billing 成功终局使用新的 Billing-owned 内容寻址提交事实,而不是把“Decision 已允许”当成 Ledger 已提交:

BillingFinalizationCommitted@1 = {
  billingFinalizationCommittedRef / billingFinalizationCommittedSchemaVersion
  billingFinalizationCommittedDigestAlgorithmVersion = jcs-sha256-v1
  billingFinalizationCommittedDigest
  billingFinalizationOperationId
  billingFinalizationDecisionRef / billingFinalizationDecisionSchemaVersion
  billingFinalizationDecisionDigestAlgorithmVersion / billingFinalizationDecisionDigest
  billingFinalizationDecisionInputDigestAlgorithmVersion / billingFinalizationDecisionInputDigest
  finalizationInputManifestRef / finalizationInputManifestSchemaVersion
  finalizationInputManifestDigestAlgorithmVersion / finalizationInputManifestDigest
  finalizationValidationBundleRef / finalizationValidationBundleSchemaVersion
  finalizationValidationBundleDigestAlgorithmVersion / finalizationValidationBundleDigest
  billingReservationId / billingAccountId / runId
  billingFinalizationFenceId / billingFinalizationFenceRevision
  closureSourceEventId / closureSourceEventType / closureSourceEventSchemaVersion
  closureSourceEventEnvelopeDigestAlgorithmVersion / closureSourceEventEnvelopeDigest
  closureConsumerReceiptRef / closureConsumerReceiptSchemaVersion
  closureConsumerReceiptDigestAlgorithmVersion / closureConsumerReceiptDigest
  billingPolicyRevisionId / evidenceFinalizationRuleVersion
  settlementEconomicIdentity = SettlementEconomicIdentity@1
  status = settle_and_release_remainder | release_all
  dimensionCommitmentCount
  dimensionCommitments[] = sorted {
    runStepId / executionAttemptId / chargeDimensionKey
    settlementInputConsumptionRef / settlementInputConsumptionSchemaVersion
    settlementInputConsumptionDigestAlgorithmVersion / settlementInputConsumptionDigest
    resultingDimensionStateRevision
  }
  ledgerEffectCount
  ledgerEffects[] = sorted {
    runStepId / executionAttemptId / chargeDimensionKey
    ledgerEffectRef / ledgerEffectSchemaVersion
    ledgerEffectDigestAlgorithmVersion / ledgerEffectDigest
  }
  releaseEffect =
    { state=none }
    | { state=applied; releaseEffectRef / releaseEffectSchemaVersion;
        releaseEffectDigestAlgorithmVersion / releaseEffectDigest }
  resultingReservationStatus = settled | released
  resultingReservationRevision
  committedAt
}

Committed Digest 覆盖除 Repository-owned Ref/Time 和摘要自身外的完整 Candidate;Envelope operationId必须等于Payload billingFinalizationOperationId。Count 与数组长度相等,Dimension 按 (runStepId, executionAttemptId, chargeDimensionKey)、Ledger Effect 再加 Ref 排序且不重复。Decision 的 Ref/Schema Version/Digest Algorithm Version/Digest 完整四元组以及 inputDigestAlgorithmVersion + inputDigest 都必须逐项映射 Owner Decision。成功Fact/Event还必须冻结提交时BillingFinalizationFence Revision、已由Billing Consumer耐久应用的Closure Source Event ID/Type/Schema/Envelope摘要及BillingFinalizationCoordinatorConsumerReceipt@1完整四元组,并与Fence Closure Watermark、Trigger、Execution Owner Read、Input Manifest和Execution Validation Receipt逐项相等;Admission首代Work在该Closure Receipt应用前只能产生closure_event_not_applied阻塞结果,禁止Owner Read、Input Manifest、Decision或Ledger成功路径。dimensionCommitments[] 必须与 Finalization Input Manifest 的全部 (runStepId, executionAttemptId, chargeDimensionKey) 一一等值,每项 Consumption 是该 Finalization 原子提交的对应输入消费且 State Revision 与 Billing Repository提交后值一致;ledgerEffects[]同样按完整Step/Attempt/Dimension与实际Ledger精确对应。两组runStepId必须与Owner Fact、Input Manifest、Consumption、Dimension State及Ledger/Event逐项相等,禁止通过Attempt反查Step。Ledger/Release集合必须与同事务实际 Effect精确等值,不能漏项、夹带或只让 Count自洽。status=release_all 当且仅当 Decision 为 release_all、所有目标净额为零、无 Ledger Effect、Reservation变为 released且余量 Release符合 Decision;status=settle_and_release_remainder 当且仅当 Decision同值、Reservation变为 settled、Ledger Effect精确实现 Manifest目标净额并按剩余额产生 none/applied Release。任一双向 Refinement或集合等值失败都拒绝 Event并回滚账务事务。Committed Fact 自身四元组才是“Closure Mandatory Event已应用,且Decision、Ledger、Release、Reservation终态与全Dimension State已在同一Billing事务提交”的 Owner 证明。causationId 指向原 wallet.reserved@2.0 Event ID。blocked | reconciliation_required 不得伪造 Committed Event。Contracts/Repository负测必须拒绝Closure Event/Receipt或Fence Revision缺项/错摘要/未应用、任一数组缺Step、错Step、旧排序键或跨Step重绑。

billing.settlement-transition.committed@1

BillingSettlementTransitionCommitted@1 = {
  billingSettlementTransitionRef / billingSettlementTransitionSchemaVersion
  billingSettlementTransitionDigestAlgorithmVersion / billingSettlementTransitionDigest
  billingTransitionOperationId
  billingTransitionValidationOperationId
  billingReservationId / billingAccountId / runId / runStepId / executionAttemptId / chargeDimensionKey
  settlementEconomicIdentity = SettlementEconomicIdentity@1
  fromStateRevision / toStateRevision
  currentSettlementInputSnapshotRef / currentSettlementInputSnapshotSchemaVersion
  currentSettlementInputSnapshotDigestAlgorithmVersion / currentSettlementInputSnapshotDigest
  currentSettlementInputStateVersion
  settlementInputLineage[] = ordered non-empty {
    settlementInputSnapshotRef / settlementInputSnapshotSchemaVersion
    settlementInputSnapshotDigestAlgorithmVersion / settlementInputSnapshotDigest
    settlementInputStateVersion
  }
  settlementInputConsumptionRef / settlementInputConsumptionSchemaVersion
  settlementInputConsumptionDigestAlgorithmVersion / settlementInputConsumptionDigest
  ledgerEffect =
    { state=none }
    | { state=applied; ledgerEffectRef / ledgerEffectSchemaVersion;
        ledgerEffectDigestAlgorithmVersion / ledgerEffectDigest }
  caseAction =
    { kind=none }
    | { kind=request_open; caseGeneration; caseRequestOperationId; reconciliationCaseRef;
        reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion;
        reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest;
        lateSettlementExposureRef / lateSettlementExposureSchemaVersion;
        lateSettlementExposureDigestAlgorithmVersion / lateSettlementExposureDigest / exposureRevision }
    | { kind=resolve; caseGeneration; caseRequestOperationId; resolutionOperationId; reconciliationCaseRef;
        reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion;
        reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest;
        resolvedExposureRef / resolvedExposureSchemaVersion;
        resolvedExposureDigestAlgorithmVersion / resolvedExposureDigest / resolvedExposureRevision }
}

Lineage Owner Read固定使用readPurpose=operations_transition_audit和独立Operations Projector Audience;请求Expected Identity与Scope必须同时绑定Tenant/Workspace/Project、Billing Account/Reservation、Run/Step/Attempt/Dimension、Event ID/Type/Schema/Envelope摘要、Transition四元组和目标Snapshot五元组,服务端与调用方逐项比较;禁止Admin使用、跨Event复用或枚举同Run其他Snapshot。

Envelope operationId必须等于Payload的逻辑billingTransitionOperationId。Payload只是已提交BillingSettlementTransition@1的低敏不变量投影,所有四元组、经济身份、State Revision、Input Consumption、Ledger与Case Action必须与Owner Fact逐项相等。runStepId是该Dimension的自包含经济身份,必须与Transition、Consumption、每个Settlement Input、Exposure、Applied Fact和Owner Read Expected Identity逐项相等;禁止从Attempt或相邻Event反查Step。settlementInputLineage[]必须与Owner Fact同构、非空并按State Version严格递增:第一项的前驱五元组等于Owner Fact的fromLastEvaluatedInput,每个后项直接指向数组前项,末项完整五元组等于Payload的Current Settlement Input;Consumer用每项完整身份调用readSettlementInput读取精确历史或Current正文并重算,不能要求中间项仍是Current、跳项或从相邻Event补值。Owner Read的conflicting分支只返回内容寻址SettlementInputConflictFact@1完整四元组,不返回Case Ref;Transition/Catch-up Worker据此阻塞当前Work,禁止把读冲突直接伪装成Late-settlement或Finalization Case。只有完成全部Owner验证后形成的正式Billing Transition/Finalization Decision,才可分别按已定义Dimension/Run级Identity协议请求Operations Case。billingTransitionValidationOperationId必须等于 Contracts 固定 Namespace 对 (billingTransitionOperationId, billingReservationId, runStepId, executionAttemptId, chargeDimensionKey, fromStateRevision, Owner Fact内Basis完整摘要) 的确定性派生值,并与Owner Fact、Consumption和Metering Receipt回显值相等;它不是Envelope Operation,也不能替换逻辑Operation。caseAction=resolve 时,resolutionOperationId 必须由 Contracts 固定 Namespace 按 (billingTransitionOperationId, caseGeneration, predecessor Exposure完整四元组/Revision) 确定性派生,并与Resolved Exposure、同事务Applied Fact逐项相等;调用方随机值或错误前驱派生值都拒绝。首个Dimension Transition的causationId指向该Reservation的billing.finalization.committed@1。后续Transition必须指向同Dimension直接前一个推进State Revision的边界Eventbilling.settlement-transition.committed@1billing.late-settlement-command-result.committed@1严格二选一,并要求前驱Payload toStateRevision == 当前 fromStateRevision;不能因Late Command插入而继续回指更早Transition,也不能按到达顺序或时间猜前驱。并发前驱使旧Receipt对应的CAS失败时,Writer必须按新From State/Basis派生新的Validation Operation,旧Receipt不得进入Event;already_evaluated是零副作用响应,不得发出新Event。

billing.late-settlement-exposure.case-requested@1

LateSettlementExposureCaseRequested@1 = {
  caseGeneration / caseRequestOperationId / reconciliationCaseRef
  reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion
  reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest
  billingSettlementTransitionRef / billingSettlementTransitionSchemaVersion
  billingSettlementTransitionDigestAlgorithmVersion / billingSettlementTransitionDigest
  billingTransitionOperationId / fromStateRevision / toStateRevision
  lateSettlementExposureRef / lateSettlementExposureSchemaVersion
  lateSettlementExposureDigestAlgorithmVersion / lateSettlementExposureDigest / exposureRevision
  billingReservationId / billingAccountId / runId / runStepId / executionAttemptId / chargeDimensionKey
  pricingSnapshotId / billingPolicyRevisionId
  settlementEconomicIdentity = SettlementEconomicIdentity@1
  exposureState = open
}

aggregateId=lateSettlementExposureRefaggregateRevision=1operationId=caseRequestOperationIdcausationId 精确指向同一 Billing 事务预分配的 billing.settlement-transition.committed@1 Event ID。Event 必须同时携带预分配 Case Ref、Case Identity Reservation 完整四元组、Originating Transition完整四元组及其 billingTransitionOperationId + fromStateRevision + toStateRevision、完整Account/Run/Step/Attempt/Dimension身份,以及 Current Open Exposure 四元组/Revision,不能只发裸 Case/Exposure Ref。Consumer必须只凭这些自包含字段构造 readBillingSettlementTransition,即使被因果引用的Transition Event尚未到达也能验证Owner Fact;Case Request自己的Envelope operationId=caseRequestOperationId不能冒充Transition Operation,也不得从Attempt或相邻Event补Step/其他参数。Exposure 后续替换仍使用同一 Case Ref,但以新 Exposure Ref/Revision 和新事件表达单调 Source 更新。

billing.case-resolution.applied@1

BillingCaseResolutionApplied@1 = {
  billingCaseResolutionAppliedRef / billingCaseResolutionAppliedSchemaVersion
  billingCaseResolutionAppliedDigestAlgorithmVersion / billingCaseResolutionAppliedDigest
  billingCaseResolutionAppliedIdempotencyKey
  resolutionOperationId / reconciliationCaseRef / caseGeneration
  reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion
  reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest
  billingReservationId / billingAccountId / runId / runStepId / executionAttemptId / chargeDimensionKey
  settlementEconomicIdentity = SettlementEconomicIdentity@1
  resolvedExposureRef / resolvedExposureSchemaVersion
  resolvedExposureDigestAlgorithmVersion / resolvedExposureDigest / resolvedExposureRevision
  resolutionSource =
    { kind=settlement_transition;
      billingSettlementTransitionRef / billingSettlementTransitionSchemaVersion;
      billingSettlementTransitionDigestAlgorithmVersion / billingSettlementTransitionDigest }
    | { kind=late_settlement_command;
        lateSettlementCommandResultRef / lateSettlementCommandResultSchemaVersion;
        lateSettlementCommandResultDigestAlgorithmVersion / lateSettlementCommandResultDigest }
  ledgerEffect =
    { state=none }
    | { state=applied; ledgerEffectRef / ledgerEffectSchemaVersion;
        ledgerEffectDigestAlgorithmVersion / ledgerEffectDigest;
        settlementEconomicIdentity=SettlementEconomicIdentity@1; amountDecimal }
  resultingSettlementState = {
    toStateRevision
    settledInput = BillingSettlementInputPointer@1
  }
  recordedAt
}

aggregateId=billingCaseResolutionAppliedRefaggregateRevision=1operationId=resolutionOperationIdcausationId 必须指向与 resolutionSource 同一 Owner Fact 的 billing.settlement-transition.committed@1billing.late-settlement-command-result.committed@1 Event ID。Payload 的 Case Identity Reservation、Resolved Exposure、Source、Ledger、经济身份与 State Revision 必须与 BillingCaseResolutionApplied@1 Owner Fact 精确相等。Owner Read还必须验证Source专属Exposure前驱与Operation:settlement_transition首次解决只允许同代Current Open→Resolved,连续零/负更正允许同Generation、同Reservation的Current Resolved→Resolved直接后继,且resolutionOperationId必须等于由Transition Operation、Generation和直接前驱Exposure确定性派生的值;late_settlement_command只允许其授权Current Open→Resolved,并固定resolutionOperationId=lateSettlementOperationId。任何跳过直接前驱、反复回指旧Open、跨Generation/Reservation、随机Operation或以Late Command解决已Resolved Exposure都拒绝。

billing.late-settlement-command-result.committed@1

LateSettlementCommandResultCommitted@1 = {
  lateSettlementCommandResultRef / lateSettlementCommandResultSchemaVersion
  lateSettlementCommandResultDigestAlgorithmVersion / lateSettlementCommandResultDigest
  lateSettlementOperationId / status=applied
  reconciliationCaseRef / caseGeneration
  reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion
  reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest
  billingReservationId / billingAccountId / runId / runStepId / executionAttemptId / chargeDimensionKey
  pricingSnapshotId / billingPolicyRevisionId / fundingPolicyRevisionId
  settlementEconomicIdentity = SettlementEconomicIdentity@1
  authorizedOpenExposureRef / authorizedOpenExposureSchemaVersion
  authorizedOpenExposureDigestAlgorithmVersion / authorizedOpenExposureDigest / authorizedExposureRevision
  resolvedExposureRef / resolvedExposureSchemaVersion
  resolvedExposureDigestAlgorithmVersion / resolvedExposureDigest / resolvedExposureRevision
  ledgerEffectRef / ledgerEffectSchemaVersion
  ledgerEffectDigestAlgorithmVersion / ledgerEffectDigest
  billingCaseResolutionAppliedRef / billingCaseResolutionAppliedSchemaVersion
  billingCaseResolutionAppliedDigestAlgorithmVersion / billingCaseResolutionAppliedDigest
  fromStateRevision / toStateRevision
}

aggregateId=lateSettlementCommandResultRefaggregateRevision=1operationId=lateSettlementOperationIdactorPrincipalId 必须等于 Result 中已授权 Workforce Actor。causationId 指向授权 Open Exposure Revision 最新的 billing.late-settlement-exposure.case-requested@1 Event。Payload 必须与 Result 的 Case Identity Reservation逐项相等,并携带同事务产生的 BillingCaseResolutionApplied@1 完整四元组;Consumer 使用 Result 四元组、Case/Identity Reservation 与 Resolved Exposure 构造受限 readLateSettlementCommandResult,再使用 Applied Fact四元组读取解决事实,不能依赖相邻 Event 补字段。Event 不复制 Grant Token、JTI、Approval/JIT 正文或金额。

Transition、Case Requested、Applied与Late Result四个Payload都强制携带并逐项继承同一billingAccountId + billingReservationId + runId + runStepId + executionAttemptId + chargeDimensionKey;对应Owner Fact、Exposure、Case Identity Reservation、Consumption、Settlement Input和定向Read Expected Identity必须相等。任何缺Step、跨Step重绑或尝试用Attempt→Step映射补值都按严格Schema/身份冲突拒绝。

原子 Append、因果与 Case 乱序收敛

Billing 必须在领域事务开始前生成所需 Event ID,以便将精确 causationId 冻结到后续事件。每个成功边界在同一 Billing PostgreSQL 事务原子提交 Owner Fact/Result、Ledger/Release/Reservation 或 Dimension State、必要的 Exposure/Applied Fact、Audit、Canonical Event、完整 Event Digest、冻结 Delivery Set 四元组与精确 Mandatory Delivery Rows。Finalization 提交必须包含 Finalization Committed Event;每个已应用 Transition 必须包含 Transition Event,request_open 同事务再包含 Case Requested Event,resolve 同事务再包含 Case Resolution Applied Event;Late Command 成功事务同时包含 Result Committed 与 Case Resolution Applied Event。任一 Event、Outbox、Delivery Row 或 Audit 失败使整个账务事务回滚,不得先改 Ledger 再补事件。

Operations 是 ReconciliationCaseIdentityReservation@1 与 Case 的唯一 Owner。身份预留只分配稳定 reconciliationCaseRef,严格 Reservation还包含 caseGenerationpredecessorCase = root | supersedes{previousCaseGeneration, previousReconciliationCaseRef, previous Identity Reservation完整四元组};摘要覆盖除Repository-owned Reservation Ref/Time和摘要自身外的全部字段。唯一 Source/Generation键与caseRequestOperationId确定性派生输入统一固定为 (sourceOwner=billing, sourceKind=late_settlement, billingReservationId, billingAccountId, runId, runStepId, executionAttemptId, chargeDimensionKey, caseGeneration);调用方不能覆盖,Operations必须用相同Contracts Namespace重算。第一代必须为1/root,后继必须恰好前代+1且完整引用直接前代。同Generation/Operation重放返回原Reservation/Case Ref,同Generation异候选冲突。预留不创建可见Case、告警或审批。受限 readReconciliationCaseIdentityReservationBySource 只接受精确 Billing Case Identity Workload Audience/Scope,并要求完整Source Key、确定性 Operation、Generation、Predecessor 和返回Reservation完整四元组逐项相等;它不提供列表、模糊查询或裸Ref读取。若预留已提交而Billing在保存响应或Transition前崩溃,新Worker必须先以同一Source/Generation/Predecessor调用该Read或重放reserve,严格验证并采用既有Reservation,禁止生成第二个Case Ref或让孤儿预留永久封锁Generation。Case Requested Consumer先按四元组验证本地不可变Reservation、Generation与Predecessor,再按 (caseGeneration, reconciliationCaseRef, exposureRevision) 单调幂等创建/更新;旧代Event/Ack不能覆盖新代或迁移旧Approval/JIT/Grant。

Case Create/Ack 的恢复只允许使用 Operations Owner 的版本化定向读取,不能从Case列表、Timeline或当前告警猜测:

readReconciliationCaseByReservedIdentity(
  reconciliationCaseIdentityReservationRef / reconciliationCaseIdentityReservationSchemaVersion,
  reconciliationCaseIdentityReservationDigestAlgorithmVersion / reconciliationCaseIdentityReservationDigest,
  expected reconciliationCaseRef, billingReservationId, billingAccountId, runId, runStepId, executionAttemptId,
  chargeDimensionKey, caseGeneration, caseRequestOperationId
)
  -> { result=not_created }
   | { result=found; reconciliationCaseRef; caseRevision;
       sourceExposureRef / sourceExposureSchemaVersion;
       sourceExposureDigestAlgorithmVersion / sourceExposureDigest / sourceExposureRevision;
       caseState }
   | { result=conflicting; conflictRef }

该Read只向精确Billing Case Recovery Workload Audience/Scope开放。服务端先按Reservation完整四元组读取不可变Owner记录并重算摘要,再逐项验证Case Ref、Source/Generation/Operation、Billing Reservation、Attempt/Dimension与Repository绑定;found中的Exposure完整四元组/Revision必须等于Case当前冻结Source,调用方也必须严格解码和复验。not_created只表示该预留尚未形成业务Case,不表示预留不存在或可重新分配;不存在/错摘要/跨身份不得伪装成not_created。若Create已提交而Ack丢失,Billing以原Reservation和期望身份读取并采用found,不得另建同代Case。

一个或多个 Resolution Applied 先于可见 Case 创建到达时,Operations 必须先验证 Case Identity Reservation、Generation/Predecessor、每个Exposure的直接前驱链和 readBillingCaseResolutionApplied,再把每个 (caseGeneration, reconciliationCaseRef, resolvedExposureRevision, Applied Fact完整四元组) 以唯一约束耐久写入 pending_resolution。后到同代Case Requested不得短暂或最终创建Open,而是在同一Operations事务选择最高连续、已验证的Resolved Revision,直接建立绑定对应Applied Fact的Resolved Case。Case已存在时只在同Generation内按Exposure Source Revision处理 applied | superseded_noop | already_applied | conflict;已Resolved Case收到同Generation/Reservation、更高且无缺口的Resolved直接后继时必须追加Timeline并原子推进Source Binding,状态保持Resolved。中间Owner Fact暂不可读或链暂不完整时必须返回retryable,不写Outcome、不写Applied/Event Receipt、不提交任何投影副作用,让原Event Delivery保持non-terminal并按Lease重试;不得把该瞬态保存为deferred或把合法Resolved→Resolved当作冲突。更高Generation使用新Reservation/Case Ref,旧代本地评论、指派、审批与授权都不得迁移。晚到旧代/旧Revision Create/Ack只能返回 already_resolved | superseded_noop,绝不能覆盖新代或把Resolved恢复为Open。只有完整验证后的pending_resolution | applied | superseded_noop | already_applied | conflict投影结果才与Applied/Event Receipt在同一Operations事务提交;失败只重试事件消费,不回滚已提交Billing账务。

Contracts 必须为五个 Payload、所有 Owner Fact/Result 四元组、Settlement Economic Identity、Case Generation/Predecessor/Exposure联合、排序 Count 与 Causation Refinement 发布 Golden JSON/Canonical Bytes/Digest。负向测试覆盖 Owner Ref/Schema正确但Digest错误、摘要算法未知、Envelope Operation与Finalization/Transition Payload Operation不等、逻辑/Validation Operation混用或Validation Operation派生错误、Lineage为空/漏项/乱序/分叉/前驱五元组或末项Current错配、Case Requested缺失/篡改Transition Operation或from/to Revision、跨Reservation/Account/Run/Case/Generation/Exposure/Dimension/经济身份重绑、第一代非1/root、后继跳代或错Predecessor、错Aggregate/Revision/Actor/Causation、Count/排序/分支错误、同Owner Fact两个Event、事务提交后缺Outbox/Delivery、Case Requested先于Transition Event仍可独立读取Owner、F→T(open)→Late Result→T(correction)乱序仍按State Revision直接前驱收敛、缺失/错误前驱Event或前驱toRevision不等当前fromRevision、Billing停在S1而Metering已追加S2→S3时按完整[S2,S3]一次catch-up且中间S2只做精确历史Owner Read、resolve-before-create、多条Resolution先于Create后选择最高连续Revision、Open O1→Resolved R2→Resolved R3合法直接链及R3回指旧Open分叉、Transition随机/错误前驱派生Resolution Operation、Late Command的Resolution Operation不等于Command Operation、Create/Applied Ack丢失、Case Owner Read的not_created/found/conflicting三分支、旧代Create晚到、更高Exposure Revision或Generation超越与投影崩溃重放;恢复测试还必须覆盖reserve提交后Billing保存响应或预提交Transition前崩溃,由新Worker在相同或更新Snapshot下按Source/Generation/Predecessor读回并采用同一Reservation,证明只有一个Case Ref且该Generation仍可继续,Create提交后Ack丢失由Billing凭Reservation完整四元组读回同一Case,Metering Receipt提交后Billing预提交前崩溃时新Worker重建同一Resolution Operation/Basis/Validation Operation,以及F→旧Basis/Receipt→并发前驱提交→CAS失败→重读新From State/Basis→新Validation Operation→成功Event且旧Receipt不被采用。

Operational Observation Submission 与 Accepted Envelope

准入前拒绝、每次 HTTP 接收和幂等重放无法由 Run Domain Event 表达。API Edge 使用独立的内部 OperationalObservationSubmission@1.0 向 Core Operations Intake 提交低敏记录。Submission Body 只包含生产者能够声明的内容:

observationId
schemaVersion
sourceClaimedObservedAt?
requestId
errorId?
traceId?
correlationId?
operationId?
runId?
surface
apiVersion?
operation?
claimedTenantKind? / claimedTenantId?
claimedWorkspaceId?
claimedServiceAccountId?
claimedDeveloperCredentialId?

payload =
  RequestAttempt@1 {
    requestKind / outcome / submissionState / normalizedCode?
    httpStatusClass? / idempotencyDisposition?
    attributes  # 固定白名单子 Schema
  }
  | ErrorOccurrence@1 {
    layer / phase / normalizedCode / errorNormalizationPolicyVersion / severity
    certainty / retryDisposition / compensationDisposition
    messageTemplateKey / sanitizedParameters
    causeErrorId? / technicalDetailRef?
    runStepId? / executionAttemptId?
    gatewayExecution? {
      gatewayPool / gatewayDeploymentId
      attemptRouteBindingRef / attemptRouteBindingSchemaVersion
      attemptRouteBindingDigestAlgorithmVersion / attemptRouteBindingDigest
      gatewayRouteSnapshotRef / gatewayRouteSnapshotSchemaVersion
      gatewayRouteSnapshotDigestAlgorithmVersion / gatewayRouteSnapshotDigest
      executionAnchor =
        { kind=text_invocation; gatewayInvocationId }
        | { kind=media_task; gatewayTaskId }
    }
  }
  | GatewayDiagnostic@1 {
    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 =
      { availabilityRef / availabilitySchemaVersion
        availabilityDigestAlgorithmVersion / availabilityDigest / stateVersion
        providerEvidenceKind=provider_usage / 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 }
        stateReasonCode
        state = available { providerUsageEvidenceRef; providerUsageEvidenceSchemaVersion;
                            providerUsageEvidenceDigestAlgorithmVersion; providerUsageEvidenceDigest }
              | not_reported | pending | unavailable | conflicting }
    costEvidenceAvailability =
      { availabilityRef / availabilitySchemaVersion
        availabilityDigestAlgorithmVersion / availabilityDigest / stateVersion
        providerEvidenceKind=provider_cost / 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 }
        stateReasonCode
        state = available { providerCostEvidenceRef; providerCostEvidenceSchemaVersion;
                            providerCostEvidenceDigestAlgorithmVersion; providerCostEvidenceDigest }
              | not_reported | pending | unavailable | conflicting }
    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) }

payload.type 是严格判别字段;每个分支拒绝其他分支字段和未知字段。ErrorOccurrence@1 必须有 errorId,其他分支若没有错误不得伪造它;normalizedCode 是三份契约统一的规范字段名,不再并存 normalizedErrorCode 或裸 code。Request、Error 与 Gateway 的 Attributes/Parameters 都由 Contracts 逐字段规定类型、长度、编码和数据分类,不能退化成任意 Map。Producer 必须提交实际 Adapter 使用、已由 Contracts 注册的 errorNormalizationPolicyVersion;Intake 依据受信 Workload/Deployment 支持矩阵校验该版本,并校验 normalizedCode 属于该 Policy 的注册值,未知或退役组合必须拒绝。Producer 不提交 serviceerrorFingerprinterrorFingerprintVersion;可信 Service 只能由 Core 根据已认证 Workload Registry 注入的 source.service 推导,不能接受同名 Claim。出现派生指纹或可信来源字段都按未知字段拒绝。

ErrorOccurrence@1.gatewayExecution 是严格嵌套 Refinement,不能把这些字段散落到外层或从相邻 GatewayDiagnostic 补齐。非 Gateway 错误必须省略它;Gateway 在 Binding 创建前且证明未发生 Provider Side Effect 的拒绝可以省略它,并只保留实际已知的 Run/Step/Attempt。Binding 已创建或可能发生外部 Side Effect 时,外层 runId 与 Error Payload 的 runStepId + executionAttemptId + gatewayExecution 全部必填;Binding 与 Route 的 Ref/Schema Version/Digest Algorithm Version/Digest 必须各自完整成组,executionAnchor 严格二选一,不能同时/缺失 Invocation 与 Task。Core Intake以Binding完整四元组、期望Attempt/Deployment和Audience调用readAttemptRouteBinding,从响应取得并验证Manifest/Slot/Route/Anchor后,再把同一Error Observation自包含的Run/Step/Attempt、Gateway Deployment、Binding、Route Snapshot和Anchor逐项交叉验证;Bootstrap Read不得反过来要求调用方预知Slot/Manifest/Anchor。不能查询“当前版本”、从相邻记录补字段或只比较裸Ref。错配进入Quarantine,不建立Attempt关联。Contracts/Intake测试必须覆盖同一Run多Attempt、错Binding/Route、任一四元组字段缺项、合法Ref/Schema搭配错误Digest、未知算法、两种Anchor同时或均未给、三件套缺项以及未知字段,并验证JSON/数据库round-trip不丢失任一四元组字段。

普通 GatewayDiagnostic@1 只携带低敏 OceanWay Deployment、受控执行身份与两个当前 GatewayEvidenceAvailabilitySnapshot@1 摘要,不携带 Gateway 私有 backendModelId、Supply/Channel、Provider Model 或 Provider Credential Version;Pool 字段唯一规范名是 gatewayPool=text|media,旧 gatewayPoolId 必须按未知字段拒绝。resultSummary必填并使用上述封闭低敏联合:reported要求正数且不超过Contracts上限的Count和至少一个按注册顺序排序去重、与Capability相容的规范模态,no_output固定零Count/空集合,not_available禁止全部输出字段;Pre-binding固定not_available。它禁止文本、Prompt、URL、文件名、MIME、尺寸、Hash、Asset ID、Provider原始状态和自由Map,不能驱动Run/Output成功。Usage/Cost 两类 Availability 均必填,且所有状态都必须携带 Snapshot Ref/Schema Version/Digest Algorithm Version/Digest/State Version/Kind/固定 Dimension/严格 availabilityIdentity/前驱联合/Reason;supersedesAvailability.state=supersedes 必须携带直接前驱 Snapshot 的 Ref/Schema Version/Digest Algorithm Version/Digest/State Version 五元组并逐项相等,root 分支禁止全部前驱字段。attempt_bound 的 Binding 和 Route 以及 available 的 Evidence Head 都必须携带完整 Ref/Schema Version/Digest Algorithm Version/Digest;当后续 Owner Read 展开 Evidence 时,其 supersedesEvidence 也只能是 root 或直接前驱 Evidence 完整四元组,不能接受裸 Ref/Schema。其他 Availability 状态禁止全部 Evidence 四元字段。缺任一 Snapshot 或前驱字段、半联合、声明版本/摘要/State Version 与 Read Contract 不等、第二 Dimension、错类 Ref、非法状态和未知字段都拒绝。

身份只能二选一,且两者都要求外层非空 gatewayAttemptDispatchSlotIdattempt_bound 另外要求外层 executionAttemptId + Binding完整四元组 + Route Snapshot完整四元组 + executionAnchor 全部存在并与两类 Snapshot 和 readAttemptRouteBinding 返回值相等,禁止只给子集;其 Slot 必须等于已验证 AttemptRouteBinding 冻结的 Slot,不能靠相同 Attempt 猜测。pre_binding_no_execution 仅用于 Binding 创建前且可证明未发生 Provider Side Effect 的拒绝,外层 gatewayAttemptDispatchSlotId + gatewayPreBindingRequestId 必须与两类 Snapshot 逐项相等,必须省略 Attempt/Binding/Route/Anchor,两类 Snapshot 只能是 stateVersion=1 + root + not_reported|unavailable 且禁止 Evidence 四元组,resultSummary固定not_available。Pre-binding Snapshot 不能进入 Metering、Eligibility 或 Finalization;不能证明无 Side Effect 时必须使用 Attempt-bound。Anchor 严格二选一并匹配 Pool:Text 只能是 text_invocation,Media 只能是 media_task;both/neither/wrong-pool/错 ID 都是非法输入。Contracts/Intake/Projector 负向测试必须覆盖 Slot 缺失、外层与任一 Pre-binding Snapshot Slot/Request ID 不等、Attempt-bound Slot 与 Binding 不等、同 Attempt 换 Slot、Binding/Route/Evidence 任一四元字段裁剪或摘要错配、Result Summary缺失/分支混合/零负超限Count/重复未知错Capability模态/内容或URL注入,以及 JSON/数据库 round-trip 丢失 Slot/摘要/Result Summary。需要展开私有路由时,必须使用 Case/JIT 授权的 Gateway Read Contract,结果只作为受限 technicalDetailRef,不得复制进普通 Accepted Observation、Operations Projection 或 Query DTO。

Observation对readAttemptRouteBinding的Bootstrap验证使用两个互斥Audience:Intake在Accepted Envelope形成前必须用operations_observation_intake并把Token Scope绑定Observation ID/Schema、Canonical Submission完整摘要、Tenant/Run(若有)、Attempt/Deployment、Binding四元组及可选Operation;Projector只能用operations_observation_projection并改为绑定Accepted Envelope完整摘要。两者只返回低敏不可变Binding正文,禁止摘要类型互换、跨Observation复用、读取Availability/Evidence/Receipt或Route私有正文;错误Audience/Scope不得泄露Binding存在性。

Error Fingerprint 规范

Error Fingerprint 的唯一规范 Owner 是 oceanway-contracts,唯一 Writer 是 Core Operations Projector。Projector 只从通过 Schema 和关联校验的字段计算,不信任 Producer、日志或 Gateway 上报的现成指纹。每条投影结果必须同时保存:

errorNormalizationPolicyVersion
errorFingerprintVersion
errorFingerprint

errorNormalizationPolicyVersion 固定 Producer Adapter 在发生时实际使用的 Raw/Provider Error 到 normalizedCode 映射,并由 Intake 按 Workload/Deployment 支持矩阵验证;Projector 不使用“当前最新版本”回填历史记录。errorFingerprintVersion="1" 固定以下七项输入,全部来自同一条 Accepted Error Observation。所有字符串先按 Contracts 字段规则校验并转为 UTF-8 NFC,枚举使用注册表中的 canonical 小写值:

{
  "errorFingerprintVersion": "1",
  "errorNormalizationPolicyVersion": "...",
  "layer": "...",
  "normalizedCode": "...",
  "phase": "...",
  "service": "...",
  "surface": "..."
}

service 取 Core 注入的 source.servicesurface 取外层必填字段,其余取已校验 Error Payload。Projector 不通过相邻 Gateway Diagnostic、Telemetry 或当前 Deployment 状态补字段。对象使用 RFC 8785 JSON Canonicalization Scheme 生成 UTF-8 字节,计算 SHA-256,小写十六进制并加 efp1_ 前缀。Request/Trace/Operation/Run/User/Tenant ID、Deployment/Config、Capability、位置/行号、时间戳、Prompt、自由文本、动态 URL、Provider Task ID 和 Secret 永不进入 v1 输入;未来增加维度必须升级 Fingerprint Version。

固定测试向量:

{"errorFingerprintVersion":"1","errorNormalizationPolicyVersion":"2026-09-01","layer":"gateway_protocol","normalizedCode":"provider.timeout","phase":"submit","service":"media-gateway","surface":"api"}

结果必须是 efp1_2443900e8feff84eb23160caf67f5b6c68e941678519db6fb9db40a231c7309b。Contracts 必须同时测试 Key 顺序变化结果不变、Unicode 非 NFC 输入先规范化、未知 Policy/Code 被拒绝、Workload/Deployment 与 Policy 不匹配被 Intake 拒绝,以及 Producer 携带任何 Fingerprint 派生字段被拒绝。每个 Producer Adapter 还必须对该 Policy 的固定 Raw Classification 测试集通过一致性测试;原始 Provider 正文仍不进入 Observation。算法或输入字段变化必须发布新的 errorFingerprintVersion;Normalization 映射变化升级 errorNormalizationPolicyVersion;旧分组保留原版本,不能后台静默重算后混入同一 Group。

Core 验证 Workload、Schema 与资源限制后,生成并不可变保存 AcceptedOperationalObservationEnvelope@1.0。它完整包含原 Submission,并只由 Core 增加:

acceptedAt
source.workloadPrincipalId
source.service
source.environment
source.region?
source.deploymentId?
source.instanceId?
observationDigestAlgorithmVersion = jcs-sha256-v1
submissionPayloadSha256

Operations低敏投影使用下列封闭摘要,不把attributessanitizedParameters正文变成新的自由Map:

AcceptedObservationSummary@1 = {
  observationId / schemaVersion / requestId
  errorId? / traceId? / correlationId? / operationId? / runId?
  surface / apiVersion? / operation?
  claimedTenantKind? / claimedTenantId? / claimedWorkspaceId?
  claimedServiceAccountId? / claimedDeveloperCredentialId?
  sourceClaimedObservedAt? / acceptedAt
  source = { workloadPrincipalId; service; environment; region?; deploymentId?; instanceId? }
  observationDigestAlgorithmVersion
  submissionPayloadSha256 / acceptedEnvelopeSha256
  payloadSummary =
    { kind=request_attempt;
      requestKind; outcome; submissionState; normalizedCode?;
      httpStatusClass?; idempotencyDisposition?;
      attributesSchemaVersion; attributesDigestAlgorithmVersion; attributesDigest }
    | { kind=error_occurrence;
        layer; phase; normalizedCode; errorNormalizationPolicyVersion; severity;
        certainty; retryDisposition; compensationDisposition;
        messageTemplateKey;
        sanitizedParametersSchemaVersion;
        sanitizedParametersDigestAlgorithmVersion; sanitizedParametersDigest;
        causeErrorId?; technicalDetailRef?; runStepId?; executionAttemptId?;
        errorFingerprintVersion; errorFingerprint }
    | { kind=gateway_diagnostic;
        gatewayPool; gatewayDeploymentId; providerAttemptId?;
        capability; configRevision; normalizedStatus; gatewayStateVersion;
        submissionCertainty; resultSummary=GatewayDiagnosticResultSummary@1 }
}

Projector只从同一Accepted Envelope和Registry/Receipt中的acceptedEnvelopeSha256逐字段形成该摘要。Request Attributes与Error Sanitized Parameters按各自已注册子Schema计算Schema Version + jcs-sha256-v1 Digest,正文不进入普通Search;Gateway分支完整保留强制Result Summary。三个Payload分支严格互斥,未知字段、Common或分支字段错映射、子摘要篡改、Result Summary缺失以及JSON/数据库round-trip丢字段均拒绝。需要返回Observation详情时,Summary、关联证据、Error Gateway Execution或Gateway Dispatch/Availability使用Operations Read Contract定义的整体available|redacted权限单元,不能只裁一个Sibling泄漏Payload Kind或对象存在性。

Core 另维护 append-only 的低敏 observation_id_registry,其最小记录为:

observationId
firstSourceWorkloadPrincipalId
observationDigestAlgorithmVersion
submissionPayloadSha256
originalAcceptedAt
acceptedEnvelopeSha256

Payload 清理状态使用另一份 append-only、每个 observationId 最多一条的 observation_payload_purge_markers(observationId, purgedAt, retentionAuditRef),不更新 Registry。

Registry 是 Observation ID 命名空间与幂等绑定的完整性事实,不是可查询 Observation 正文。它在环境的 Observation ID 命名空间生命周期内保留,或迁入 Intake 每次接受前都必须检查的不可变完整性归档;普通 Retention 不得删除、更新或绕过它。

Submission 与 Accepted Envelope 是两个不同 Schema;生产者不能提交或覆盖 acceptedAtsource.*observationDigestAlgorithmVersionsubmissionPayloadSha256,Intake 对这些保留字段一律拒绝,不能采用“忽略后继续”的歧义行为。Producer 提供的可选 sourceClaimedObservedAt 必须原样作为 Claim 保存,不能被 Intake 重写成 occurredAt 或 Core 时间。

Intake 对 Canonical Submission 计算 submissionPayloadSha256。只有当前 Workload JWT Subject 与首次保存的 source.workloadPrincipalId 相同、且 Digest Algorithm Version、observationId + submissionPayloadSha256 均相同时,才是幂等重放;首次接受时生成唯一的 acceptedAt/source.* 并对最终信封计算存储侧 acceptedEnvelopeSha256。Source Payload 尚存时,同一 ID、同一受信 Source、同一算法版本与同一 Submission 摘要返回 accepted_existing、原 Accepted Envelope 与原 acceptedAt;已有 Purge Marker 时返回 accepted_existing_purged,只包含 observationId + originalAcceptedAt + observationDigestAlgorithmVersion,不能重构信封、重新投影或复活 Source。两者都不能重新生成信封。同一 ID 来自不同 Workload、算法版本错配,或同一 Source 下摘要不同,都必须作为完整性冲突拒绝、追加低敏 Audit/告警,且不能返回首次 Source 的内容。Projector Receipt 比较同一算法版本下的 acceptedEnvelopeSha256,不能把两个摘要字段或不同算法版本混用。

Observation Digest 规范

两个 Observation 摘要统一由 oceanway-contractsjcs-sha256-v1 实现生成,不能由 Producer、数据库 JSON 序列化器或各 Consumer 自行选择算法:

  1. 原始 JSON 必须按 UTF-8 严格解码,并在构造普通对象前拒绝重复 Member Name;所有 Member Name 与字符串值转为 Unicode NFC,规范化后产生重名也拒绝。
  2. 规范化对象再通过对应的严格版本 Schema;未知字段拒绝。v1 的可选字段缺失时保持缺失,不注入默认值;除 Schema 明确声明 Nullable 的分支外,显式 null 一律拒绝,因此“缺失”与 null 不能获得同一摘要。数组顺序保持不变,数值必须先符合 Contracts 的有限、范围与整数/十进制规则。
  3. 对验证后的精确 DTO 使用 RFC 8785 JSON Canonicalization Scheme,取得 UTF-8 Canonical Bytes,再计算 SHA-256,输出 64 位小写十六进制。
  4. submissionPayloadSha256 覆盖完整 Canonical Submission,不包含由 Core 注入的算法版本。acceptedEnvelopeSha256 覆盖完整 Canonical Accepted Envelope,包含 observationDigestAlgorithmVersionsubmissionPayloadSha256;它自身只存在于 Registry/Receipt,不进入被摘要的 Envelope,避免递归。

共享 Canonicalization 固定向量以 NFD e\u0301 作为输入,NFC 与 RFC 8785 后的字节必须精确为 {"a":"é","z":[3,2,1]},SHA-256 必须为 35ca92c06e5e44b0729f57937d5aaf7476ccbc3b6202e41ac669ed3780815988。Contracts Release 还必须随包发布一份完整 Submission 与对应 Accepted Envelope 的 Golden JSON/Canonical Bytes/两个摘要;Node、Web、Core、Projector、Archive Replay 和 Rebuild 全部读取同一制品验证,不能复制测试常量后各自实现。Key 顺序变化摘要不变,缺失与非法 null、未知字段、规范化重名、Envelope 字段或算法版本篡改必须失败;算法或字段覆盖范围变化必须发布新的 Digest Algorithm Version 和 Observation Schema Version,旧记录始终按原版本重放,禁止后台静默重算。

RequestAttempt 种类

RequestAttempt@1.requestKind 首期至少区分:

  • request_received:Edge 接收到一次合法 Host 上的请求;不表示认证或准入成功。
  • request_rejected:在提交 Core 前被拒绝,携带规范化低敏原因。
  • admission_submitted:Edge 已向 Core 发起 Admission;不能单凭它推断事务提交。
  • admission_accepted:Core 返回已存在或新建的 reserved Run。
  • idempotency_replayed:本次 Request ID 返回既有 Run。
  • admission_outcome_unknown:Edge 无法确定 Core 是否提交,需要依赖稳定 Key 重试与后续事实查询。

错误另用 ErrorOccurrence@1,不把 Layer/Phase/Certainty/Fingerprint 等塞进 Request Attributes;Gateway 诊断使用 GatewayDiagnostic@1。三个分支共享外层稳定关联 ID,但各自严格 round-trip,任何分支错置字段、normalizedErrorCode/裸 code 旧名或未知参数都必须拒绝。

Observation 安全边界

  • 未完成认证时,Claimed Tenant、Workspace、Service Account 和 Credential ID 可以为空;它们必须来自 Edge 已验证的请求上下文,不得从客户 Body 接受。即使如此,它们仍只是 Producer Claim,不是 Core 领域事实。

  • 不发送 Raw Secret、Key Digest、Authorization、Cookie、Session、请求/响应 Body、Prompt、输入摘要、完整 IP、User-Agent 原文或堆栈。

  • RequestAttempt.attributesErrorOccurrence.sanitizedParametersGatewayDiagnostic 都只能使用 Contracts 明确的判别子 Schema、白名单和长度/分类约束;不能作为逃逸的任意 JSON 日志袋。

  • Intake 使用面向 oceanway-core 的短期 Workload JWT 与 operations-observation:write Scope;Core 从 JWT 确认来源 Workload,不能信任 Body 自报 Producer。

  • Intake 数据库 Role 不直接读取或写入 Source/Registry/Purge Marker,只能执行受控 accept_operational_observation Primitive;Primitive 在唯一约束下原子 insert-or-compare,只有当前受信 Workload 与首次 Source、Digest Algorithm Version 和 Submission 摘要全部一致时才返回 accepted_new | accepted_existing | accepted_existing_purged 之一及允许字段,跨 Workload 或跨算法版本冲突不得返回旧内容。

  • Producer、Environment、Region、Deployment/Instance 由 Core 根据受信 Workload Registry 注入;Submission Body 出现 acceptedAtsource.*observationDigestAlgorithmVersionsubmissionPayloadSha256 必须拒绝。acceptedAt 是 Core 权威接收时间,sourceClaimedObservedAt 只是来源声明;Observation 固定按 (acceptedAt, observationId) 排序,Summary 的 first_accepted_observation_at/latest_accepted_observation_at、accepted health window、Retention/Archive 和 Freshness 只能使用 acceptedAt,claimed time 只在 Timeline 展示。

  • claimedTenantKindclaimedTenantIdclaimedWorkspaceIdclaimedServiceAccountIdclaimedDeveloperCredentialIdoperationIdrunId 不能直接用于 Tenant 授权或 operation_linked。Operations Projector 只有通过同一 Operation/Run 的 Canonical Domain Event,或 Core 签发且可验证的不可变 Admission Context 交叉验证后,才能把关联提升为 domain_verified。关联证据使用严格联合:

    association =
      { trust=producer_claimed; associationEvidence={ state=none } }
      | { trust=domain_verified;
          associationEvidence =
            { kind=domain_event;
              eventId; eventType; eventSchemaVersion;
              eventEnvelopeDigestAlgorithmVersion; eventEnvelopeSha256 }
            | { kind=admission_context;
                admissionContextRef; admissionContextSchemaVersion;
                admissionContextDigestAlgorithmVersion; admissionContextDigest } }

    Domain Event 分支必须逐项复制已应用 Canonical Event 的 ID、Type、Schema Version 与覆盖完整 Envelope+Payload 的摘要四元身份;Admission Context 分支必须引用 Core append-only Registry 中内容寻址、Ref 永不复用的严格 Context 四元组,其摘要覆盖用于关联的 Actor/Tenant/Workspace/Developer Access/Operation/Run Claims。Projector 必须验证所选证据与 Observation Claims、目标领域事实及 Tenant 分区逐项相等,并把完整联合原子写入投影;不能只存裸 Ref、只比 ID/Schema、从当前 Run/Session 补值或混合两分支。producer_claimed 必须且只能携带 state=nonedomain_verified 必须且只能携带一个完整证据分支;未知 Schema/算法、摘要错配、缺项、两分支混合、同 Ref 异正文或错标 Tenant/Run 都隔离关联且不能污染领域时间线。Contracts/Repository/Query round-trip 与跨租户负向测试必须覆盖所有互斥、篡改和裁剪场景。

  • Contracts 与部署配置共同限制单条 Payload、批次数量、字段长度和白名单;Intake 按 Workload 执行配置化配额、背压和异常告警。资源保护不能靠在代码中散落固定次数或固定延时。

  • Telemetry/Intake 失败不阻塞客户请求,也不改变公共响应。首期没有 Edge 持久队列,因此 Observation 是 best-effort。

  • 后续 Gateway Observation 对 Usage/Cost 只允许携带两类严格 Evidence Availability,并只在 available 分支携带对应 Evidence Ref/Schema Version/Digest Algorithm Version/Digest完整四元组;不得嵌入或冒充规范 MeterEvent / ProviderCostFact,也不得作为 Billing 结算命令。Gateway 只拥有不可变 Evidence,规范 Fact 由 Metering 唯一追加。

  • Core 接受后将 Envelope 以 source.workloadPrincipalId + observationDigestAlgorithmVersion + observationId + submissionPayloadSha256 验证幂等,并以全局唯一 observationId 原子写入 append-only Source 与 ID Registry;跨 Workload 的同 ID 或算法版本错配在该命名空间内始终是冲突。数据库 Trigger 与 Column Grant 禁止修改已接受的 Source、Registry、Purge Marker、Envelope、算法版本、两个摘要和接受时间。Intake 不直接修改当前投影。

  • Projector 以 (consumerName, projectionName, projectionVersion, observationId) 建立 Receipt,Receipt 保存 observationDigestAlgorithmVersion + acceptedEnvelopeSha256,并与 Observation Projection Mutation 放在同一事务;其他 Consumer/Projection 的 Receipt 不能满足当前投影,相同 Accepted Envelope 重投不重复应用,算法版本或摘要冲突拒绝并告警。

  • Edge 没有 Durable Spool,也不发送可证明连续性的 Sequence。Core 只能报告已经接受的记录集合、接受时间范围和 Intake/Source 已知健康窗口;不能声称请求覆盖完整、计算丢失数量或检测 Observation Gap。

  • 缺少 Observation 不能反证请求没有到达 Edge;已知健康窗口也只表示组件健康信号可用,不表示该窗口内每个请求都已有 Observation。

  • 契约与 PostgreSQL 负向测试必须覆盖 Producer 错标 Tenant/Run、Claim 与 Domain Event 不一致、未验证 Claim 被 Tenant-scoped Grant 查询,以及验证证据撤销/缺失;未验证 Claim 只能由显式跨租户 Observation 调查 Scope 读取。时间负测还必须覆盖 claimed time 与接受顺序反转、claimed time 位于未来/Retention 边界两侧、相同 acceptedAt 的稳定排序,以及 operational_observation 缺少 acceptedAt、伪造 occurredAt 或把 claimed time 写入 Summary;这些输入均不得改变基于 acceptedAt 的结果。

Schema Registry 与兼容门禁

事件和 Observation 的运行时 Schema、TypeScript 类型与 JSON Schema 都由固定版本 oceanway-contracts 发布。消费仓只依赖精确 Release:

  1. Contracts 新版本先发布并通过 Package/Release 制品一致性验证。
  2. Core Producer、Dispatcher、Consumer 和 Query 使用同一受支持版本矩阵。
  3. API Edge 升级后才能发送新 Observation 版本。
  4. 未知事件类型、未知版本、严格 Schema 失败或完整性摘要冲突进入隔离,不得跳过后继续声称投影完整。
  5. 删除旧 Consumer 版本前,必须证明保留事件已全部可由当前 Projector 重建,或已按治理策略归档相应 Schema 与重放运行时。

任何版本门禁失败都不能通过“从日志补字段”“直接查询生产表”或“修改历史 Event Payload”绕过。

On this page