Skip to content

ExecutionOutcome — Append-Only Corrections Model

Generated from specification/state-machines/execution-outcome.md. Edit the canonical source file, not this page.

RFC 2119 normative language applies throughout.

ExecutionOutcome follows an append-only corrections model. A submitted outcome is never mutated in place. Corrections are expressed as new records that supersede prior ones. This document describes the submission chain, correction types, preconditions, postconditions, and invariants.

An ExecutionOutcome records whether and how an accepted exchange was executed, without copying participants’ complete operational records. The record is logically associated with one ExecutionReference.

The outcome history forms an ordered chain:

Outcome-1 (initial submission)
└─ Outcome-2 (correction, supersedes Outcome-1)
└─ Outcome-3 (further correction, supersedes Outcome-2)

At any moment, the head of the chain (the record with no supersededByOutcomeId) is the current authoritative outcome.

Although there is no single lifecycle automaton, each ExecutionOutcome record carries a status reflecting the execution reality it reports:

status Value Meaning
planned Execution accepted but not yet started.
inProgress Execution underway; partial confirmation available.
completed Execution concluded successfully.
cancelled Execution was called off after ExecutionReference was created.
disputed One or more parties dispute the reported outcome; arbitration pending.

These values describe the execution event being reported, not the record’s own lifecycle. A completed outcome record can still be superseded by a correction if the reported data was erroneous.

3.1 Initial Submission (POST /execution-outcomes)

Section titled “3.1 Initial Submission (POST /execution-outcomes)”

Creates the first ExecutionOutcome for a given ExecutionReference.

Preconditions:

  • Authorization: Actor belongs to one of the participatingOrganizationIds of the linked ExecutionReference.
  • Scope required: outcomes:write
  • Reference state: The linked ExecutionReference MUST be in linked or created state (not yet completed or cancelled).
  • Version check: executionReferenceId and its current resourceVersion MUST be included.
  • Deduplication key: deduplicationKey (a stable caller-supplied key) MUST be provided. A duplicate submission with the same deduplicationKey returns the original record (200 OK).
  • Policy check: status, planned and actual time ranges (where available), and participant confirmations MUST be present. Sensitive fields (exact addresses, customer identity, price) MUST NOT be included.

Postconditions:

  • New ExecutionOutcome record created; submittedAt recorded; resourceVersion = 1; supersedes = null.
  • ExecutionReference status transitions to linked if it was created, or remains linked.
  • If status is completed or cancelled, ExecutionReference MAY transition to completed or cancelled respectively (broker policy determines exact trigger).
  • Event pcx.execution-outcome.recorded.v1 emitted.

3.2 Correction (POST /execution-outcomes/{id}/corrections)

Section titled “3.2 Correction (POST /execution-outcomes/{id}/corrections)”

Creates a new ExecutionOutcome that supersedes the identified prior record.

Preconditions:

  • Authorization: Actor belongs to one of the participatingOrganizationIds of the linked ExecutionReference.
  • Scope required: outcomes:write
  • Prior record state: The {id} in the path MUST identify the current head of the correction chain (i.e. the record with no supersededByOutcomeId). Correcting a non-head record MUST return 409 Conflict with idempotency-conflict.
  • Version check: observedOutcomeVersion MUST match the resourceVersion of the record being superseded. A mismatch MUST return 409 Conflict with stale-resource-version.
  • Correction reason: correctionReason MUST be provided. correctionReasonCode SHOULD be provided from the correction vocabulary.
  • Deduplication key: A new deduplicationKey MUST be supplied for this correction record.

Postconditions:

  • New ExecutionOutcome record created; submittedAt recorded; supersedes = {id}; resourceVersion = 1 on the new record.
  • Prior record’s supersededByOutcomeId set to the new record’s id (immutable pointer added); prior record is otherwise unchanged.
  • If status of the new record is completed or cancelled, appropriate ExecutionReference transitions may be triggered.
  • Event pcx.execution-outcome.corrected.v1 emitted, referencing both the old and new record IDs.
Field Type Required Description
id string (UUID) yes Stable immutable identifier for this outcome record.
executionReferenceId string yes Reference to the parent ExecutionReference.
status enum (see §2) yes Execution status being reported.
submittedAt RFC 3339 timestamp yes When this record was recorded (server-assigned).
submittedBy actor reference yes The actor submitting this record.
deduplicationKey string yes Caller-supplied stable key for idempotent submission.
plannedTimeRange time range no Planned start and end times.
actualTimeRange time range no Actual start and end times; required if status is completed.
participantConfirmations array no Per-organization confirmation records.
externalExecutionRefs array no External system references (namespaced).
operationalDeviations array no Documented deviations or exceptions.
capacityUtilizationObservations object no Optional observed utilization data.
routeObservations object no Optional route deviation or mileage data.
schemaVersion string yes Protocol schema version used for this record.
supersedes string (UUID) no ID of the prior record this one corrects; null for initial submissions.
supersededByOutcomeId string (UUID) no ID of the next record in the chain; null if this is the head. Set by the server; never provided by the client.
correctionReason string conditional Required when supersedes is set.
correctionReasonCode string conditional Structured reason code; SHOULD be provided when supersedes is set.
observedOutcomeVersion integer conditional Required when supersedes is set; MUST match resourceVersion of superseded record.
  • Concurrent corrections on the same head: Two concurrent POST /execution-outcomes/{id}/corrections against the same head record MUST be serialized. The first writer creates a new head and sets supersededByOutcomeId on the old head. The second writer’s observedOutcomeVersion will no longer match; it MUST return 409 Conflict with stale-resource-version. The caller MUST re-read the current head and retry if the correction is still needed.
  • Concurrent initial submissions with the same deduplicationKey: Only one record is created; subsequent requests with the same key return the original (200 OK).
  • Concurrent initial submissions with different deduplicationKey values: Both are accepted; however, a (executionReferenceId, status=completed) record SHOULD be treated as idempotent by the broker — only the first completed outcome triggers ExecutionReference completion.
  • Dispute and correction racing: A disputed outcome may be corrected; the correction supersedes the disputed record and MUST include a correctionReason explaining the resolution.
  1. Append-only chain: No ExecutionOutcome record MUST be mutated or deleted after recording. The supersededByOutcomeId pointer MAY be set by the server when a correction arrives, but all other fields are immutable.
  2. Single head invariant: At most one record per executionReferenceId MUST have supersededByOutcomeId = null at any time. Two concurrent corrections to the same head violate this invariant and MUST be prevented by the stale-resource-version check.
  3. Correction chain integrity: The chain formed by supersedes pointers MUST be acyclic and MUST eventually terminate at a record with supersedes = null (the initial submission).
  4. Deduplication key uniqueness: deduplicationKey MUST be unique per executionReferenceId. The server MUST reject a new record whose deduplicationKey matches an existing record unless the request is an exact replay (same payload, returns 200 OK).
  5. Schema version recording: schemaVersion MUST be stored on every record so historical records remain interpretable after protocol version advances.
  6. Data minimisation: ExecutionOutcome records MUST NOT contain customer identity, exact addresses, price, or complete goods details unless policy explicitly permits disclosure. Adapter-specific fields MUST be in the extensions namespace.
  7. Audit retention: All records in the correction chain MUST be retained for the period defined in the retentionPolicyRef of the linked PartnerRelationship.
  8. Outcome-reference consistency: A completed ExecutionReference MUST have a head ExecutionOutcome with status of completed or cancelled. The broker MUST NOT mark the reference completed based on a superseded outcome record.