<!-- Generated by landing-page/scripts/generate-scenario-docs.mjs. Do not edit directly. -->
# Scenario authoring reference

## Start with one real conversation: an X12 850 order and its 810 invoice

Suppose a retailer sends your company an X12 850 purchase order and your company later returns an X12 810 invoice. A scenario turns that familiar exchange into a repeatable proof that the right documents, maps, partner route, acknowledgments, timing, and business values all agree.

1. **Definition** — Describe the reusable business conversation: the retailer sends one 850, the supplier returns one matching 810 within 30 days, both carry the same purchase-order number, the selected maps succeed, and required AS2 receipts plus accepted 997 or 999 acknowledgments exist. No tenant-specific partner or map ID appears here.
2. **Binding** — Connect that recipe to this tenant's real platform resources: the retailer partner, the supplier workspace, the inbound 850 map, the outbound 810 map, the fact expressions that read each purchase-order number, and any explicitly pinned X12 syntax-tree version (the exact parsing structure used for that document). Applying the binding freezes those exact dependencies for repeatable runs.
3. **Run** — Start one evaluation of the applied binding and attach the persisted 850 and 810 transactions. ModernEDI checks that the documents followed the allowed path, matched by purchase-order number, arrived in time, used the frozen dependencies, and satisfied every required check.
4. **Evidence** — Inspect the durable proof: persisted transaction and map identities, transport-receipt and 997 or 999 assurance outcomes, redacted fact subjects, matching-rule and business-check results, evidence references, timestamps, and the immutable evidence report for the terminal run. Raw X12 payloads and extracted fact values remain in authorized platform and transaction views; the run and downloadable report do not copy them.

## Mental model

`Definition → Binding → Run → Evidence`

- **Definition** — The reusable recipe for an X12 business conversation: roles, document steps, allowed order and repetition, matching rules, evidence requirements, and business checks.
- **Binding** — The tenant-specific wiring that selects the partners, workspace, maps, fact expressions, server-side execution implementation, and optional X12 syntax-tree versions used by that recipe.
- **Run** — One timestamped evaluation of an applied binding against persisted transactions and platform evidence.
- **Evidence** — The durable, hash-identified record of what happened and why the run passed, failed, was cancelled, or remained inconclusive.

### Terms used below

- **Conversation graph** — The actors, document steps, and directed relationship rules in a definition. It is a model of the business conversation, not a separate customer API.
- **Actor** — A business role that sends or receives documents, such as retailer, supplier, warehouse, or carrier. A binding later connects each role to a tenant partner or the tenant workspace.
- **Step** — One kind and direction of X12 business document in the conversation, such as an inbound 850 order or outbound 810 invoice.
- **Occurrence** — One actual persisted document assigned to a step during a run. Two 856 shipment notices are two occurrences of the same step.
- **Transition** — A rule connecting two steps. follows requires a matched later document; supersedes records a replacement such as a later 860 order change; cancels records a removal such as an ocean 303 cancelling a 301 booking confirmation.
- **Fact** — A typed business value extracted from one document occurrence by an X12 Mapper expression, such as purchaseOrderNumber, invoiceTotal, or statusTimestamp.
- **Correlation** — A matching rule that decides which concrete documents belong together, such as equal purchase-order numbers on an 850 and 810.
- **Assertion** — A business fact rule that must pass, such as shipped quantity equaling invoiced quantity or successive 315 status timestamps increasing.
- **Parameter** — A typed value supplied when a run starts rather than extracted from a document, such as expectedShipmentCount or cancelRequested.
- **Matching strategy** — The rule for pairing repeated documents: by declared correlations, by observation position, or by the immediately previous occurrence in a same-step revision chain.
- **Quantifier** — The scope of a repeated check, such as every pair must match, any pair may match, or exactly a declared number must match.
- **Closure** — The objective signal that no more documents are expected for one repeated step: a fixed count, the authored maximum, or a required/defaulted expected count.
- **Checkpoint** — A named completion event emitted after a declared processing stage. It can trigger a branch; for example, bookingDisposition after processing a 301 can choose the 303 or 304 path.
- **Branch** — An explicit choice between mutually exclusive next-document paths after a checkpoint, such as choosing a 303 cancellation instead of 304 shipping instructions.
- **Revision effect** — The rule for when a superseding or cancelling document begins to apply and whether later checks keep the original document or reevaluate with the replacement or removal.
- **Pipeline stage** — One ordered processing action for a document occurrence: prepare, map, exchange, extract facts, check evidence, or emit a checkpoint.
- **Runtime target** — The server-side implementation selected by a binding to prepare, map, exchange, and evaluate the scenario's document steps.
- **Runtime capacity** — The bounded amount of durable run state a definition may require. Validate and Apply reject a definition whose worst-case structure would exceed that budget.
- **Publish** — Create an immutable, content-hashed definition revision after validation succeeds.
- **Apply** — Create an immutable binding revision after ModernEDI resolves and validates its tenant-owned dependencies.

The signed-in Workspace API is the customer HTTP API for definitions, bindings, runs, context, operations, and evidence reports. A conversation graph is only the definition's model of actors, document steps, and directed rules; the scenario runtime is the server-side evaluator that executes supported applied bindings. Some generated OpenAPI component names begin with ScenarioGraph because they represent conversation-graph state inside a run; they remain part of the Workspace API, not a separate Graph API.

## Why scenarios exist

Maps define how documents are processed; scenarios define and prove the business conversation those maps implement. A ScenarioDefinition is the portable recipe for that conversation: who exchanges each X12 business document, which documents belong together, what order and repetition are allowed, and what evidence must pass. Tenant partners, syntax trees, mappings, and executable targets belong in a ScenarioBinding.

Scenario definitions and bindings are ordinary JSON files with strict JSON Schema Draft 2020-12 contracts. Those schemas are the structured documentation source used to validate examples, generate this reference, and generate the editor schema module. Checks involving multiple files, tenant ownership, conversation rules, extracted fact types, and executable support remain server-authoritative and are called out explicitly below.

The optional top-level `$schema` property gives VS Code, JetBrains IDEs, and other JSON-aware tools completion, hover text, and structural diagnostics. ModernEDI Mapper associates the same schemas automatically for `*.scenario.json` and `*.binding.json` files.

## ModernEDI ScenarioDefinition v1

- File pattern: `*.scenario.json`
- JSON Schema: [scenario-definition-v1.schema.json](https://www.modernedi.com/docs/scenarios/schemas/scenario-definition-v1.schema.json)
- Example: [order-invoice.scenario.json](./examples/order-invoice.scenario.json)

### Authoring workflow

1. Create a *.scenario.json draft in Mapper Explorer. JSON Schema supplies completion, hover help, and immediate structural diagnostics.
2. Run Validate to check references, X12 catalog values, closure and branch rules, typed operands, and whether the current scenario runtime can execute the definition.
3. Publish only after validation succeeds. Publish creates an immutable definition identity and content hash for bindings.
4. Create and Apply a matching *.binding.json to resolve tenant partners, mappings, adapters, and optional syntax-tree choices.
5. Start a scenario run with the applied binding, then inspect each occurrence, evidence item, correlation, and assertion in Implementation Verification.

### Server semantic checks

- Actor, step, transition, parameter, checkpoint, branch, predicate, fact, and pipeline-stage IDs are unique in their documented scopes.
- Every referenced actor, step, fact, checkpoint, transition, and parameter exists, and every document step goes from one actor to a different actor. A correlation may read facts only from its two connected steps. A branch condition may read facts only from the common source step and cannot use a destination document to select itself.
- An occurrence minimum cannot exceed its maximum; every repeated step has an objective closure rule; repeated-document pairing and every/any/count behavior are explicit; durations are positive and no longer than P365D. A min-zero step uses expected_count because zero observations cannot satisfy max_reached, unless every incoming follows path is branch-controlled so an unselected path supplies the no-document outcome. expected_count uses an exact integer parameter that is required at run start or has a default within the step bounds; steps sharing that parameter must have overlapping bounds.
- Transaction sets exist in the X12 catalog, while 997 and 999 are represented as assurance evidence.
- Ordinary next-document paths cannot loop, and every step belongs to the same connected conversation. Only supersedes with previous matching may form a same-step revision chain, and that repeated step must allow at least two occurrences; cancels identifies a distinct cancellation-document step.
- Each operator receives compatible typed values from facts, run parameters, or literals; list and set elements must use one exact scalar type.
- Each composed processing pipeline contains one exchange stage in valid order and at most one map and assure stage. map must be directly beside exchange; Apply requires it before exchange for an outgoing runtime mapping and after exchange for an incoming one. Every parameter named by prepare is required at run start or has a default. Every declared fact appears in exactly one extract stage. Every declared checkpoint has exactly one emitting stage, a step that emits a checkpoint can occur only once, and a branch fact is extracted before its decision checkpoint.
- supersedes and cancels require a revision effect; follows forbids one. previous matching is supersedes-only, requires a step occurrence max of at least 2, and requires record for both matching and effect because the first occurrence is the initial revision. Revisions always match the unchanged observation history, cannot be branch alternatives, and cannot open or schedule a next-document path. Each branch checkpoint must be emitted by the alternatives' shared source step and must necessarily observe at least one document, so expected_count closure with occurrence min 0 is rejected. Each branch-decision round uses only steps already allowed at its start; a selected path becomes available in the next round. After branch selection, a revision affects checks only when both endpoint steps remain on the selected path. retain keeps the original document for branch conditions, follows transitions, and assertions; reevaluate uses the replacement or removal instead. A later effective time wins, and equal latest times fail with REVISION_EFFECT_CONFLICT.
- The definition's combined worst-case occurrence summaries, transition pairs, checks, and compact evidence references must fit the v1 durable run-state budget. Per-step JSON Schema maxima for fact declarations and occurrences are structural ceilings, not separately available runtime quotas.

### Runtime capacity

Validate and Apply conservatively estimate deterministic durable run-state growth rather than accepting each step independently. The estimate includes occurrence summaries, compact evidence references, checks, and quadratic transition-pair and revision-check growth. It does not reserve the maximum runtime value size for every declared fact; actual Mapper-derived values and evidence are checked against separate per-observation limits before persistence. A definition is rejected with runtime_capacity_exceeded when its combined structural projection exceeds the v1 durable run-state budget.

- Durable run-state projection budget: `480,000 bytes`.
- Fact declarations per step in JSON Schema: `100` (a structural ceiling, not preallocated runtime value capacity).
- Per-step occurrence maximum in JSON Schema: `1000` (a structural ceiling, not an independently available quota).
- Stable compiler diagnostic: `runtime_capacity_exceeded`.

### Field reference

<a id="schema-definition-token"></a>

#### token

A stable identifier beginning with a letter and containing at most 128 letters, digits, underscores, or hyphens.

Type or allowed values: string; pattern `^[A-Za-z][A-Za-z0-9_-]{0,127}$`.

<a id="schema-definition-namespace"></a>

#### namespace

A lowercase, DNS-like ownership namespace.

Type or allowed values: string; max length 253; pattern `^[a-z0-9]+(?:[.-][a-z0-9]+)*$`.

<a id="schema-definition-artifactversion"></a>

#### artifactVersion

A trim-exact artifact version with no control characters. This versions a published definition; it is separate from apiVersion.

Type or allowed values: string; min length 1; max length 64; pattern `^(?!\s)(?!.*\s$)[^\u0000-\u001F\u007F]+$`.

<a id="schema-definition-positiveduration"></a>

#### positiveDuration

A positive ISO 8601 duration accepted by java.time.Duration, no longer than P365D. Examples: PT30M, PT4H, P2D. The server enforces the upper bound.

Type or allowed values: string; pattern `^P(?=.+)(?!0+(?:D\|T(?:0+H)?(?:0+M)?(?:0+(?:\.0+)?S)?$))(?:[0-9]+D)?(?:T(?=[0-9])(?:[0-9]+H)?(?:[0-9]+M)?(?:[0-9]+(?:\.[0-9]+)?S)?)?$`.

<a id="schema-definition-metadata"></a>

#### Definition metadata

Immutable identity of a published definition. The identity tuple is namespace, key, and version; contentSha256 is computed when the definition is published.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `namespace` | yes | [namespace](#schema-definition-namespace) |  |
| `key` | yes | [token](#schema-definition-token) | Stable definition key within the namespace. |
| `version` | yes | [artifactVersion](#schema-definition-artifactversion) |  |

<a id="schema-definition-spec"></a>

#### Scenario specification

The business-conversation recipe. Actors name the business roles, steps name their X12 document exchanges, and transitions state how those exchanges relate. ModernEDI also verifies unique IDs, references, a connected conversation, and the absence of ordinary transition cycles during Validate and Publish. Omitted transitions, assertions, parameters, checkpoints, or branches mean empty arrays; published JSON materializes every collection.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `actors` | yes | array of [actor](#schema-definition-actor) | Business roles participating in the conversation. Every actor ID must be unique. |
| `steps` | yes | array of [step](#schema-definition-step) | Business-document exchanges. Every step ID must be unique and must reference two different declared actors. |
| `transitions` | no | array of [transition](#schema-definition-transition) | Rules connecting document steps. For example, an 810 invoice can follow its matching 850 purchase order, a later 860 can supersede an earlier order change, and an ocean 303 can cancel a matching 301 booking confirmation. Transition IDs must be unique. Except for a same-step supersedes revision chain, ordinary next-document paths cannot loop and every step must belong to one connected conversation. |
| `assertions` | no | array of [assertion](#schema-definition-assertion) | Run-level facts that must hold across one or more observed step occurrences. Assertion IDs must be unique. |
| `parameters` | no | array of [parameter](#schema-definition-parameter) | Prepared values supplied when a run starts. Parameters declare only their semantic type, required flag, and optional default; bindings and runtime APIs supply values. |
| `checkpoints` | no | array of [checkpoint](#schema-definition-checkpoint) | Named completion events emitted after a step finishes a declared processing stage. A checkpoint can trigger a choice between allowed next steps. For example, a bookingDisposition checkpoint emitted after an X12 301 booking confirmation can choose between an X12 303 cancellation and X12 304 shipping instructions. |
| `branches` | no | array of [branch](#schema-definition-branch) | Explicit choices between allowed next-document transitions, evaluated only after a named checkpoint is emitted. For example, after an X12 301 booking confirmation emits bookingDisposition, cancelRequested=true can select the X12 303 cancellation path and otherwise can select X12 304 shipping instructions. Choices are evaluated in deterministic rounds from the steps already available at the start of that round; a destination document cannot provide the fact that selects its own path. |

<a id="schema-definition-actor"></a>

#### Actor

A business role. Bindings later connect each role to this workspace or a trading partner.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |

<a id="schema-definition-step"></a>

#### Step

One directed X12 business-document exchange. Functional acknowledgments (997/999) are evidence requirements, not business steps.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) | Stable ID used by transitions, assertions, and bindings. |
| `fromActor` | yes | [token](#schema-definition-token) | ID of the actor sending this business document. |
| `toActor` | yes | [token](#schema-definition-token) | ID of the actor receiving this business document; it must differ from fromActor. |
| `transaction` | yes | [transaction](#schema-definition-transaction) |  |
| `occurrence` | yes | [occurrence](#schema-definition-occurrence) |  |
| `assurance` | no | [assurance](#schema-definition-assurance) |  |
| `facts` | yes | array of [factDeclaration](#schema-definition-factdeclaration) | Typed semantic facts exposed by this step. Use an empty array when the step exposes none. Declarations name the stable ABI only; extraction provenance belongs to runtime capability and binding layers. |
| `pipeline` | yes | array of [pipelineStage](#schema-definition-pipelinestage) | Ordered abstract processing stages for each step occurrence. Stages describe behavior without naming mapper or transport artifacts. |

<a id="schema-definition-transaction"></a>

#### Transaction

The business document carried by a step. The server verifies the transaction-set code against ModernEDI's X12 catalog.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `standard` | yes | exactly `X12` | Transaction standard. v1 supports X12. |
| `transactionSet` | yes | string; pattern `^(?!(?:997\|999)$)[0-9]{3}$` | Known three-digit X12 business transaction set, such as 850, 855, 856, 810, 875, 880, 940, 945, 204, 214, 300, 301, or 315. Use assurance for 997/999 acknowledgments. |
| `businessUsage` | yes | [token](#schema-definition-token) | Scenario-specific semantic role, such as purchase_order, shipment_notice, or ocean_status. It is intentionally more precise than the transaction-set code. |

<a id="schema-definition-occurrence"></a>

#### Occurrence bounds

How many documents this step may contribute to one run and the rule that says when no more are expected. One observed document is one occurrence. For example, an 850 order can be exactly once while 856 shipment notices can repeat. The server also enforces min <= max.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `min` | yes | integer; minimum 0; maximum 1000 | Minimum accepted count once a reachable step closes. Zero is a no-document outcome only when expected_count resolves to 0 or branch selection makes the step unreachable; zero alone does not close a stream. |
| `max` | yes | integer; minimum 1; maximum 1000 | Structural per-step ceiling for authored occurrences. Validate and Apply also enforce one conservative run-state capacity budget across all steps, paired documents, checks, and durable evidence. |
| `closure` | no | [occurrenceClosure](#schema-definition-occurrenceclosure) | The closure rule: the objective signal that no more documents are expected for this step. It may be omitted while authoring; Publish writes fixed when min equals max and max_reached otherwise. Because max_reached waits for the maximum, a min-zero unbranched step must instead use expected_count so a zero-document outcome is explicit. |

<a id="schema-definition-assurance"></a>

#### Evidence requirements

Operational evidence required for each occurrence of this step. Duplicate requirement types are rejected by the server.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `requirements` | yes | array of [assuranceRequirement](#schema-definition-assurancerequirement) |  |

<a id="schema-definition-assurancerequirement"></a>

#### Evidence requirement

One observable proof required for a step. For example, mapping_succeeded proves that the selected map ran, while functional_or_implementation_acknowledgment_accepted proves accepted 997 or 999 evidence. Outgoing mapping proof may predate the document occurrence because mapping runs immediately before exchange; receipts and acknowledgments may not. A deadline is measured from the document occurrence to the terminal evidence time, and requires that evidence's own timestamp. Terminal evidence timestamped after the run's evaluation time is invalid.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `type` | yes | `mapping_succeeded`, `transport_receipt_accepted`, `interchange_acknowledgment_accepted`, `functional_or_implementation_acknowledgment_accepted` | mapping_succeeded proves mapper execution; transport_receipt_accepted proves the AS2 receipt; interchange_acknowledgment_accepted proves TA1 acceptance; functional_or_implementation_acknowledgment_accepted proves accepted 997 or 999 evidence. |
| `within` | no | [positiveDuration](#schema-definition-positiveduration) | Optional deadline from the business document occurrence to terminal evidence. An outgoing mapping completed before exchange satisfies the lower timing boundary, but its own source timestamp is still required; missing terminal source time cannot prove a deadline. |

<a id="schema-definition-transition"></a>

#### Transition

A rule from one document step to another. Correlations identify which actual documents belong together. follows models ordinary order, such as a matching 810 invoice after an 850 order. supersedes records a replacement, such as a later 860 order change replacing the prior 850 or 860. cancels records a removal, such as an ocean 303 cancellation for a 301 booking confirmation. Supersedes and cancels inspect every stored observation before any replacement or cancellation is applied; they do not make an otherwise unavailable next-document path available and cannot themselves be branch alternatives.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |
| `fromStep` | yes | [token](#schema-definition-token) | Predecessor step ID. |
| `toStep` | yes | [token](#schema-definition-token) | Successor step ID. It may equal fromStep only for a supersedes transition that uses previous matching; cancellation is represented by a distinct cancellation-document step. |
| `relationship` | yes | `follows`, `supersedes`, `cancels` | Choose follows when a matched later document must occur at or after the earlier one, such as an 810 invoice after its 850 order. Choose supersedes when the later document replaces the matched earlier occurrence, such as an 860 order change replacing an 850 or prior 860. Choose cancels when the later document cancels the matched earlier occurrence, such as an ocean 303 cancelling a 301 booking confirmation. supersedes and cancels require effect to say when the change begins and whether later checks keep using the original document or reevaluate with the replacement/removal. Business labels such as acknowledges, reports status, or settles belong in the transition ID and prose unless an assertion or evidence requirement actually verifies them. |
| `within` | no | [positiveDuration](#schema-definition-positiveduration) | Optional maximum elapsed time from the correlated fromStep occurrence to the toStep occurrence. |
| `correlations` | no | array of [correlation](#schema-definition-correlation) | Conditions the scenario evaluator uses to pair actual source and target documents. For example, compare the purchase-order number extracted from an 850 with the purchase-order number extracted from an 810. Correlation IDs must be unique within this transition. |
| `matching` | yes | [occurrenceMatching](#schema-definition-occurrencematching) | Required quantification and pairing semantics for concrete occurrences; the server does not infer them from correlations. |
| `effect` | conditional | [revisionEffect](#schema-definition-revisioneffect) | Required effective-time and downstream behavior for supersedes and cancels. Forbidden for follows. |

<a id="schema-definition-correlation"></a>

#### Correlation

A condition that decides whether two actual documents belong to the same transition pair. equal can match the purchase-order number on an 850 and 810; same_set can compare their item sets; reply_link uses ModernEDI's stored reply relationship and accepts no fact operands.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |
| `operator` | yes | `equal`, `same_set`, `reply_link` |  |
| `left` | conditional | [factOperand](#schema-definition-factoperand) | For fact operators, must reference the transition's fromStep. |
| `right` | conditional | [factOperand](#schema-definition-factoperand) | For fact operators, must reference the transition's toStep. |

<a id="schema-definition-assertion"></a>

#### Assertion

A fact rule that must hold for the run to pass. For example, exists can require every 810 invoice to expose invoiceTotal, sum_equal can compare shipped and invoiced totals, and monotonic can require successive 315 status timestamps to move forward. Binary operators require right; unary operators reject it.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |
| `operator` | yes | `equal`, `not_equal`, `exists`, `unique`, `same_set`, `subset`, `sum_equal`, `less_than_or_equal`, `greater_than_or_equal`, `monotonic` |  |
| `left` | yes | [valueOperand](#schema-definition-valueoperand) |  |
| `right` | conditional | [valueOperand](#schema-definition-valueoperand) |  |

<a id="schema-definition-valuetype"></a>

#### valueType

Closed evaluator value type. list and set contain scalar values only and require elementType.

Type or allowed values: `string`, `decimal`, `date`, `time`, `timestamp`, `boolean`, `list`, `set`.

<a id="schema-definition-scalartype"></a>

#### scalarType

Closed scalar type used directly or as the element type of list and set values.

Type or allowed values: `string`, `decimal`, `date`, `time`, `timestamp`, `boolean`.

<a id="schema-definition-factprojection"></a>

#### factProjection

Select one declared per-occurrence fact value, aggregate values across occurrences as a list or set, or select the first/latest observed occurrence. Correlations require value.

Type or allowed values: `value`, `list`, `set`, `first`, `latest`.

<a id="schema-definition-decimaljson"></a>

#### decimalJson

A finite JSON number or exact base-10 string. The scenario evaluator normalizes scale without precision loss.

Type or allowed values: number or string; pattern `^-?(?:0\|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?$`.

<a id="schema-definition-parameter"></a>

#### Prepared run parameter

A typed value supplied when a run starts through the Workspace UI or API, or resolved from its declared default when optional.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) | Stable name used by prepare stages, expected-count closure, and parameter operands. |
| `type` | yes | [valueType](#schema-definition-valuetype) |  |
| `elementType` | conditional | [scalarType](#schema-definition-scalartype) | Required exactly when type is list or set. |
| `required` | yes | boolean | Whether the run must explicitly provide this value. A required parameter cannot also have a default. |
| `default` | no | JSON value | Optional JSON value used when the run omits a non-required parameter. |

<a id="schema-definition-checkpoint"></a>

#### Checkpoint declaration

A named completion event emitted by exactly one checkpoint pipeline stage after its preceding stages finish. For example, an X12 301 booking-confirmation step can emit bookingDisposition after exchange and fact extraction, allowing the run to choose the cancellation or shipping-instructions path.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |

<a id="schema-definition-factdeclaration"></a>

#### Typed fact declaration

Stable semantic ABI for one fact exposed by a step occurrence. The binding/runtime capability separately defines extraction provenance.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `name` | yes | [token](#schema-definition-token) | Stable fact name used by discriminated fact operands and binding-side fact sources. |
| `type` | yes | [valueType](#schema-definition-valuetype) |  |
| `elementType` | conditional | [scalarType](#schema-definition-scalartype) | Required exactly when type is list or set; nested collections are not supported. |
| `cardinality` | yes | `one`, `optional` | Presence of the typed value on each occurrence. Collection multiplicity is expressed by type list/set, never by a separate many cardinality. |
| `normalization` | yes | array of `trim`, `collapse_whitespace`, `uppercase`, `lowercase`, `decimal_canonical` | Ordered, deterministic normalization applied before typed evaluation. |
| `sensitivity` | yes | `business`, `personal`, `financial`, `health`, `restricted` | Data-handling classification carried with evidence and diagnostics. |

<a id="schema-definition-pipelinestage"></a>

#### Composed step pipeline stage

One named action in the ordered processing of an observed document. A definition says prepare, map, exchange, extract facts, check evidence, or emit a checkpoint; the binding later selects the concrete map, partner, or adapter. Keeping those artifact IDs out of the definition lets the same conversation recipe be reused by another tenant.

Variants: Prepare stage or Map stage or Exchange stage or Extract stage or Assure stage or Checkpoint stage.

<a id="schema-definition-occurrenceclosure"></a>

#### Occurrence closure

The objective rule that tells a run no more documents are expected for one repeated step. fixed closes at the required fixed count; max_reached closes only at the authored maximum; expected_count closes at a required or defaulted run parameter, including an explicit zero. Branch selection supplies the no-document outcome for an unselected destination. There is no manual-close operation in v1.

Variants: Fixed closure or Maximum-reached closure or Expected-count closure.

<a id="schema-definition-matchquantifier"></a>

#### Occurrence match quantifier

An explicit requirement over source occurrences, target occurrences, matched pairs, or matches per endpoint occurrence.

Variants: Any quantifier or Every quantifier or Exact-count quantifier.

<a id="schema-definition-occurrencematching"></a>

#### Occurrence matching

How actual repeated documents are paired across a transition, plus what happens to documents with no match. correlate pairs documents whose declared fact or reply-link conditions pass; position pairs by observation order; previous pairs each revision with the immediately preceding occurrence of the same step, such as the second 860 order change with the first.

Variants: Correlation matching or Positional matching or Previous-occurrence matching.

<a id="schema-definition-factoperand"></a>

#### Fact operand

A declared semantic fact from a concrete step occurrence.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `kind` | yes | exactly `fact` |  |
| `stepId` | yes | [token](#schema-definition-token) |  |
| `fact` | yes | [token](#schema-definition-token) | Name from the referenced step's facts declaration. |
| `projection` | yes | [factProjection](#schema-definition-factprojection) | How values are selected or aggregated across this step's occurrences. list/set require occurrence max greater than 1 and a scalar declared fact. |

<a id="schema-definition-parameteroperand"></a>

#### Parameter operand

A prepared run parameter usable in assertions, branch predicates, and effective-time expressions.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `kind` | yes | exactly `parameter` |  |
| `parameter` | yes | [token](#schema-definition-token) |  |

<a id="schema-definition-literaloperand"></a>

#### Typed literal operand

A closed typed JSON literal. list and set literals require scalar elementType and use a JSON array value.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `kind` | yes | exactly `literal` |  |
| `type` | yes | [valueType](#schema-definition-valuetype) |  |
| `elementType` | conditional | [scalarType](#schema-definition-scalartype) |  |
| `value` | yes | JSON value | JSON value matching type and elementType. The server performs format and exact type validation. |

<a id="schema-definition-valueoperand"></a>

#### Value operand

Closed discriminated union used by assertions, branch predicates, and effective-time expressions.

Variants: Fact operand or Parameter operand or Typed literal operand.

<a id="schema-definition-effectiveat"></a>

#### Revision effective time

When a replacement or cancellation begins to govern the conversation. observed_at uses the time ModernEDI observed the later document. value uses an explicit timestamp, such as effectiveTimestamp extracted from an X12 860 order change. The value must be a timestamp, not only a date or clock time. A fact value belongs to the matched revision pair and must come from its source or later document; for a previous-matched same-step revision, it is read from the later revision occurrence.

Variants: Time ModernEDI observed the revision or Business effective timestamp.

<a id="schema-definition-revisioneffect"></a>

#### Revision or cancellation effect

What a matched replacement or cancellation changes. Raw immutable observation history means every received document remains stored unchanged; the revision rule changes only the run's interpreted business view. A revision transition does not open a next-document path by itself. Each branch-decision round first snapshots the steps already allowed; its conditions see only active reevaluate effects whose original and later-document steps are both in that snapshot, and a chosen path becomes available only in the next round. After branch selection, a revision affects checks only when both endpoint steps remain on the selected conversation path. If several active reevaluate effects target the same original document, the later effectiveAt wins; equal latest times fail with REVISION_EFFECT_CONFLICT instead of choosing arbitrarily.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `effectiveAt` | yes | [effectiveAt](#schema-definition-effectiveat) | When this replacement or cancellation begins to govern checks. Later active reevaluate effects take precedence for the same original document. |
| `downstream` | yes | `retain`, `reevaluate` | retain records the change and effective time but keeps using the original document for branch conditions, ordinary follows transitions, and assertions; for example, record an advisory 860 while later shipment checks still use the original 850. reevaluate recomputes those same consumers with the replacement or removal; for example, use the revised 860 values for later 856/810 checks, or remove a 301 booking confirmation after its 303 cancellation. |
| `unmatched` | yes | `fail`, `record` | Behavior when no prior effective occurrence can be revised or cancelled. previous matching requires record because the first occurrence is the initial revision and necessarily has no prior occurrence. |

<a id="schema-definition-predicate"></a>

#### Branch predicate

A yes/no condition evaluated after the branch's named checkpoint is emitted. For example, after an X12 301 emits bookingDisposition, compare the cancelRequested run parameter with true to select the X12 303 path. A fact condition must read the common source step of every alternative and that fact's extract stage must precede the checkpoint; it cannot read a destination document or later pipeline evidence to make that destination eligible. Every condition sees the conversation view from the start of the decision round, so one branch cannot use evidence made available by itself or a sibling branch in that round.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |
| `operator` | yes | `equal`, `not_equal`, `exists`, `unique`, `same_set`, `subset`, `sum_equal`, `less_than_or_equal`, `greater_than_or_equal`, `monotonic` |  |
| `left` | yes | [valueOperand](#schema-definition-valueoperand) |  |
| `right` | conditional | [valueOperand](#schema-definition-valueoperand) |  |

<a id="schema-definition-branchalternative"></a>

#### Branch alternative

One ordinary follows transition that a branch may select, either when its conditions pass or as the explicit otherwise fallback. For example, cancelRequested=true selects the 301-to-303 follows transition; otherwise selects 301-to-304. supersedes and cancels transitions are revision records, not branch alternatives.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |
| `kind` | yes | `when`, `otherwise` |  |
| `transitionId` | yes | [token](#schema-definition-token) | ID of a follows transition selected by this branch; supersedes and cancels transitions are not allowed. |
| `conditions` | yes | array of [predicate](#schema-definition-predicate) | Conditions may use parameters, literals, or facts from the alternatives' shared fromStep. They cannot read a destination step to select that destination. |

<a id="schema-definition-branch"></a>

#### Explicit branch

A choice between mutually exclusive next-document paths after a named checkpoint. The checkpoint must be emitted by the alternatives' shared source step, so the decision precedes every controlled destination. The emitter must also necessarily observe at least one document; expected_count closure with occurrence min 0 cannot emit a branch checkpoint. All alternatives leave the same source step. Example: after a 301 booking confirmation emits bookingDisposition, choose the 303 cancellation path when cancelRequested=true; otherwise choose 304 shipping instructions. exactly_one must choose one path and therefore requires an otherwise fallback. at_most_one may choose no path. A round evaluates only evidence already available when that round began; its selection can make later steps available in the next round.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-definition-token) |  |
| `mode` | yes | `exactly_one`, `at_most_one` |  |
| `checkpoint` | yes | [token](#schema-definition-token) |  |
| `alternatives` | yes | array of [branchAlternative](#schema-definition-branchalternative) | at_most_one accepts one or more when alternatives; exactly_one requires at least two alternatives and exactly one otherwise. |

## ModernEDI ScenarioBinding v1

A tenant-scoped authoring binding that connects every actor and step in one immutable ScenarioDefinition to current workspace partners and executable targets. It references tenant artifacts by identity and contains no copied runtime configuration, credentials, private keys, or other secrets.

- File pattern: `*.binding.json`
- JSON Schema: [scenario-binding-v1.schema.json](https://www.modernedi.com/docs/scenarios/schemas/scenario-binding-v1.schema.json)
- Example: [order-invoice.binding.json](./examples/order-invoice.binding.json)
- Mapper language tutorial: [https://app.modernedi.com/mapper/tutorial](https://app.modernedi.com/mapper/tutorial)
- Mapper function reference: [https://app.modernedi.com/mapper?reference=functions](https://app.modernedi.com/mapper?reference=functions)
- Mapper expression diagnostics API: [https://www.modernedi.com/docs/scenarios/reference#workspace-api-post-x12mapper-workspace-expression-diagnostics](https://www.modernedi.com/docs/scenarios/reference#workspace-api-post-x12mapper-workspace-expression-diagnostics)

### Authoring workflow

1. Publish or select the exact ScenarioDefinition first; copy its namespace, key, version, and contentSha256 into spec.definition.
2. Bind every actor exactly once. Use one workspace endpoint and one or more current partner endpoints.
3. Bind every step exactly once to an evidence-constrained runtime mapping, active executable adapter, or observation-only target. Runtime-mapping and observation-only targets do not initiate exchanges.
4. For every semantic fact declared by a tenant-authored definition step, add one factSources entry. Its expression uses the same X12 Mapper language and functions as an incoming map's primaryKeyExtractor.
5. Omit syntaxTree for the easiest authoring experience when the chosen target can resolve it. Specify it only when you deliberately need an implementation-guide pin.
6. Run Validate, then Apply. Apply resolves current artifacts, fails closed on drift or ambiguity, and stores an immutable runtime revision.

### Editor and API tooling

- factSources[].source.expression is an ordinary value-returning X12 Mapper expression. It is parsed and executed by the same language engine as a mapping's primaryKeyExtractor, not by a scenario-only selector dialect.
- The binding editor opens each fact source in a focused Mapper expression editor. It provides syntax-tree-aware completion, hover information, live diagnostics, and the existing searchable function reference using an explicit draft pin, a selected current runtime mapping, or the Mapper catalog's current default as an authoring preview. Apply independently resolves and freezes the exact authoritative tree.
- POST /x12mapper/workspace/expression/diagnostics is the public stateless diagnostics operation for external authoring tools. It accepts one expression plus optional X12 release and transaction-set context; it never reads tenant data.
- Draft diagnostics are fast authoring feedback. Scenario Validate and Apply remain authoritative for the exact tree, definition fact typing and cardinality, tenant artifacts, target authority, and bounded runtime evaluation.

### Server semantic checks

- The definition identity and content hash resolve to exactly one published or managed definition available to this tenant.
- Actor and step IDs are unique and cover the referenced definition exactly.
- Exactly one actor endpoint is the workspace and at least one is a current tenant partner.
- Every runnable step must cross the tenant workspace boundary: exactly one endpoint is the workspace and the other is a bound partner. Apply rejects partner-to-partner and workspace-to-workspace steps because ModernEDI can neither operate nor authoritatively observe them.
- Runtime mappings match the step direction, partner, transaction set, and resolved syntax tree. They constrain authoritative evidence from the ordinary transaction pipeline; they do not dispatch scenario documents.
- Tenant-authored steps bind every declared fact exactly once. Mapper expressions are parsed and semantically validated against the resolved syntax tree before Apply, must be capable of an X12 segment or element read, and must produce concrete read provenance at runtime; value type, collection behavior, normalization, and sensitivity are taken from the definition.
- Adapters are registered and cover the referenced definition and step. An adapter target may additionally pin a runtime mapping when the adapter executes the step but attached evidence must prove that exact mapping.
- Apply records an immutable, fully resolved execution binding; an optional authoring syntaxTree never makes the runtime artifact ambiguous.

### Runtime observation durability

X12 Mapper expressions retain their ordinary language semantics, while the typed fact values and evidence persisted for one observation are deliberately bounded. Collections may contain at most 1,000 scalar values, each string value may contain at most 4,096 UTF-8 bytes, each encoded typed value may contain at most 32,768 bytes, and the combined durable fact projection may contain at most 262,144 bytes. Fact provenance receipts, individual evidence documents, non-fact evidence count, and aggregate evidence JSON have their own documented limits. Every bound is checked before SQL persistence and returns a stable fact or observation capacity diagnostic.

- Collection maximum: `1,000 scalar values`.
- UTF-8 text maximum per scalar value: `4,096 bytes`.
- Encoded typed-value maximum: `32,768 bytes`.
- Combined durable fact projection maximum per observation: `262,144 bytes`.
- Fact provenance receipt maximum: `4,096 bytes`.
- Evidence document maximum: `8,192 bytes`; at most `8` non-fact evidence documents per observation.
- Combined durable evidence maximum per observation: `524,288 bytes`.
- Stable diagnostics: `fact_value_limit_exceeded`, `transaction_observation_capacity_exceeded`, `transaction_fact_evidence_capacity_exceeded`, and `transaction_evidence_capacity_exceeded`.

### Field reference

<a id="schema-binding-token"></a>

#### token

A stable identifier beginning with a letter and containing at most 128 letters, digits, underscores, or hyphens.

Type or allowed values: string; pattern `^[A-Za-z][A-Za-z0-9_-]{0,127}$`.

<a id="schema-binding-namespace"></a>

#### namespace

Lowercase namespace of the published ScenarioDefinition.

Type or allowed values: string; max length 253; pattern `^[a-z0-9]+(?:[.-][a-z0-9]+)*$`.

<a id="schema-binding-artifactversion"></a>

#### artifactVersion

Exact published definition version.

Type or allowed values: string; min length 1; max length 64; pattern `^(?!\s)(?!.*\s$)[^\u0000-\u001F\u007F]+$`.

<a id="schema-binding-metadata"></a>

#### Binding metadata

Editable identity and display name for this binding draft. Apply creates an immutable binding revision.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `id` | yes | [token](#schema-binding-token) | Stable binding ID within the workspace. |
| `name` | yes | string; min length 1; max length 160; pattern `\S` | Human-readable binding name. The server trims leading and trailing whitespace when canonicalizing. |

<a id="schema-binding-spec"></a>

#### Binding specification

References one exact published definition and binds all of its actors and steps. Apply resolves and freezes authoritative artifacts for runtime use.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `definition` | yes | [definitionReference](#schema-binding-definitionreference) |  |
| `environment` | yes | exactly `production` | ModernEDI's tenant runtime environment selector. v1 runs only against the tenant production runtime; ordinary product access, workspace permissions, and applied-binding readiness govern use. |
| `actors` | yes | array of [actorBinding](#schema-binding-actorbinding) | Exactly one binding for every definition actor. IDs must be unique; exactly one endpoint must be this workspace and at least one must be a current external partner. |
| `steps` | yes | array of [stepBinding](#schema-binding-stepbinding) | Exactly one binding for every definition step. IDs must be unique. |

<a id="schema-binding-definitionreference"></a>

#### Published definition reference

Exact identity and canonical content hash returned by Publish or the scenario catalog. Apply fails closed if any part differs.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `namespace` | yes | [namespace](#schema-binding-namespace) |  |
| `key` | yes | [token](#schema-binding-token) |  |
| `version` | yes | [artifactVersion](#schema-binding-artifactversion) |  |
| `contentSha256` | yes | string; pattern `^[0-9a-f]{64}$` | Lowercase SHA-256 digest of the canonical published definition. |

<a id="schema-binding-actorbinding"></a>

#### Actor binding

Connects one definition actor to this workspace or a current trading partner.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `actorId` | yes | [token](#schema-binding-token) | Actor ID from the referenced ScenarioDefinition. |
| `endpoint` | yes | [endpoint](#schema-binding-endpoint) |  |

<a id="schema-binding-endpoint"></a>

#### Actor endpoint

OneOf discriminator: workspace accepts only kind; partner also requires a positive tenant partner ID.

Variants: Workspace endpoint or Partner endpoint.

<a id="schema-binding-stepbinding"></a>

#### Step binding

Connects one definition step to an executable or observation target and binds every declared semantic fact to an implementation-guide source. syntaxTree is optional while authoring; Apply resolves an exact authoritative syntax-tree artifact before runtime execution.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `stepId` | yes | [token](#schema-binding-token) | Step ID from the referenced ScenarioDefinition. |
| `syntaxTree` | no | [syntaxTreeReference](#schema-binding-syntaxtreereference) | Optional explicit implementation-guide identity. Omit it to let Apply select the exact current syntax tree from the authoritative mapping or adapter; an applied runtime binding is always resolved and immutable. |
| `target` | yes | [target](#schema-binding-target) |  |
| `factSources` | no | array of [factSourceBinding](#schema-binding-factsourcebinding) | One source for every fact declared by this ScenarioDefinition step. Omission is a deliberate authoring shorthand only when the step declares no facts; canonical Apply materializes an empty array. Server validation otherwise requires exact fact-name coverage. Collection shape, element type, cardinality, normalization, and sensitivity come only from the declaration and are intentionally not duplicated here. |

<a id="schema-binding-factsourcebinding"></a>

#### Fact source binding

Binds one named fact declaration to one validated X12 Mapper expression. Fact names must be unique within a step.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `fact` | yes | [token](#schema-binding-token) | Fact name declared by this exact ScenarioDefinition step. |
| `source` | yes | [factSource](#schema-binding-factsource) |  |

<a id="schema-binding-factsource"></a>

#### Fact source

One ordinary X12 Mapper expression fact source. It uses the same language and execution engine as an incoming map's primaryKeyExtractor; v1 does not define a second scenario-specific selector language. The expression must read the bound X12 document so its value has concrete provenance.

Variants: X12 Mapper expression fact source.

<a id="schema-binding-x12mapperexpressionsource"></a>

#### X12 Mapper expression fact source

Evaluates one ordinary X12 Mapper expression against the step transaction. Validate and Apply use the same parser, semantic validator, function registry, budget mechanism, and syntax-tree-aware engine as runtime mappings and primaryKeyExtractor, with scenario-specific bounded limits. Validate and Apply reject an expression that is statically incapable of reading an X12 segment or element, and runtime fails closed when the executed path produces no concrete X12 read. Scenario evidence uses that engine's element-read tracing facility; this does not imply that existing primary-key persistence emits the same trace. The ScenarioDefinition remains authoritative for value type, cardinality, normalization, and sensitivity.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `kind` | yes | exactly `x12-mapper-expression` | Uses ModernEDI's existing X12 Mapper expression language and engine, shared with primaryKeyExtractor. |
| `expression` | yes | string; min length 1; max length 16384; pattern `\S` | One value-returning X12 Mapper expression that reads at least one X12 segment or element. A constant-only expression cannot provide authoritative document evidence. Scalars, lists, and sets are interpreted according to the matching fact declaration; secrets and credentials must never appear here. |

<a id="schema-binding-syntaxtreereference"></a>

#### Syntax-tree reference

Optional authoring-time pin to an exact X12 release and transaction set. Both fields are required when this object is present.

| Field | Required | Type or allowed values | Meaning |
| --- | --- | --- | --- |
| `x12Version` | yes | string; pattern `^[Vv]?(?:00)?[1-9][0-9]{3}$` | X12 release token. Apply canonicalizes accepted forms to a six-digit release such as 004010. |
| `transactionSet` | yes | string; pattern `^[0-9]{3}$` | Known three-digit X12 transaction set. The code must match the referenced definition step. |

<a id="schema-binding-target"></a>

#### Step target

OneOf discriminator selecting an evidence-constrained runtime mapping, a registered active executor adapter, or observation-only evidence.

Variants: Runtime mapping target or Adapter target or Observation-only target.

## Executable design examples

These customer-readable examples preserve the business semantics of definitions that the backend compiles, checks against the same durable runtime-capacity budget used for tenant definitions, and evaluates through the scenario interpreter. They demonstrate the public v1 language; they do not claim that a trading-partner implementation is certified.

The published examples use the reserved `modernedi.examples` namespace. Before validating or publishing a copy, change `metadata.namespace` to a namespace owned by your tenant; the remaining business semantics can stay unchanged.

| Business cycle | Definition | Behaviors exercised |
| --- | --- | --- |
| grocery-order-to-invoice | [`grocery-order-to-invoice.scenario.json`](./examples/business-cycles/grocery-order-to-invoice.scenario.json) | X12 875, 856, 880; relationships follows; correlations equal; assertions subset, equal; closure fixed; matching correlate, position; quantifiers every:from, every:to, every:pairs; unmatched fail; pipeline exchange, extract; fact types string, set<string>, decimal |
| grocery-product-activity | [`grocery-product-activity.scenario.json`](./examples/business-cycles/grocery-product-activity.scenario.json) | X12 852; assertions exists, unique; closure fixed; pipeline exchange, extract; fact types date, list<string>, list<decimal> |
| ocean-booking-to-invoice | [`ocean-booking-to-invoice.scenario.json`](./examples/business-cycles/ocean-booking-to-invoice.scenario.json) | X12 300, 301, 303, 304, 315, 313, 312, 310; relationships supersedes, follows, cancels; correlations equal; assertions monotonic, greater_than_or_equal; closure expected_count, fixed, max_reached; matching previous, correlate, position; quantifiers every:to, every:from, exactly:pairs, any:pairs, every:pairs; unmatched record, fail; revision effects observed_at:reevaluate, observed_at:retain; pipeline exchange, extract, checkpoint; fact types string, decimal, timestamp; branches exactly_one, at_most_one; 2 checkpoints |
| retail-order-lifecycle | [`retail-order-lifecycle.scenario.json`](./examples/business-cycles/retail-order-lifecycle.scenario.json) | X12 850, 855, 860, 865, 856, 810; relationships follows, supersedes; correlations same_set, equal; assertions monotonic, unique, sum_equal; closure fixed, expected_count; matching correlate, previous, position; quantifiers every:to, exactly:pairs, every:from; unmatched record, fail; revision effects observed_at:retain, value:reevaluate; pipeline exchange, extract; fact types string, set<string>, decimal, timestamp |
| warehouse-outbound | [`warehouse-outbound.scenario.json`](./examples/business-cycles/warehouse-outbound.scenario.json) | X12 940, 945; relationships follows; correlations equal; assertions unique, sum_equal; closure fixed, expected_count; matching correlate; quantifiers every:from, every:to, exactly:pairs; unmatched fail; pipeline exchange, extract; fact types string, decimal; 1 time window |

Grocery product activity (852) is intentionally a separate scenario from the 875 → 856 → 880 order lifecycle because public v1 does not yet model composition between independently running scenarios. Runtime targets prepare, map, or exchange transactions; the scenario evaluator consumes timestamped evidence that those actions completed.

## Signed-in Workspace API

This contract serves signed-in ModernEDI workspace users and browser/BFF automation acting with the same tenant session. It is intentionally separate from the public API-key Integration API. An Integration API key does not authenticate tenant routes. The one stateless Mapper expression-diagnostics operation is explicitly public and never reads or changes tenant data.

Authentication: The signed-in workspace session used by app.modernedi.com. Tenant product access and READ or OPERATE permission are enforced in addition to authentication. This is not an Integration API key.

[Download the generated OpenAPI 3.1 contract](./workspace-api.openapi.json). Route method, path, path parameters, and header names are read from the real JAX-RS resources; request field sets are checked against the Java JSON parsers.

| Method | Exact route | Permission boundary | Request | Success response | Purpose |
| --- | --- | --- | --- | --- | --- |
| `GET` | <a id="workspace-api-get-tenant-scenarios-catalog"></a>`/tenant/scenarios/catalog` | READ | none | 200 ScenarioCatalogResponse | List scenario definitions available to the tenant |
| `POST` | <a id="workspace-api-post-x12mapper-workspaces-workspaceid-scenario-authoring-validate"></a>`/x12mapper/workspaces/{workspaceId}/scenario-authoring/validate` | OPERATE | ScenarioValidationRequest | 200 ScenarioValidationResponse | Validate scenario definition and binding drafts |
| `GET` | <a id="workspace-api-get-x12mapper-workspaces-workspaceid-scenario-authoring-definitions"></a>`/x12mapper/workspaces/{workspaceId}/scenario-authoring/definitions` | READ | none | 200 PublishedDefinitionListResponse | List immutable tenant-published definitions |
| `POST` | <a id="workspace-api-post-x12mapper-workspaces-workspaceid-scenario-authoring-definitions-publish"></a>`/x12mapper/workspaces/{workspaceId}/scenario-authoring/definitions/publish` | OPERATE | PublishScenarioDefinitionRequest | 200 PublishedDefinitionMutationResponse; 201 PublishedDefinitionMutationResponse | Publish a validated definition immutably |
| `GET` | <a id="workspace-api-get-x12mapper-workspaces-workspaceid-scenario-authoring-bindings"></a>`/x12mapper/workspaces/{workspaceId}/scenario-authoring/bindings` | READ | none | 200 AppliedBindingListResponse | List applied binding revisions |
| `GET` | <a id="workspace-api-get-x12mapper-workspaces-workspaceid-scenario-authoring-bindings-bindingid"></a>`/x12mapper/workspaces/{workspaceId}/scenario-authoring/bindings/{bindingId}` | READ | none | 200 AppliedBindingResponse | Read one applied binding revision |
| `PUT` | <a id="workspace-api-put-x12mapper-workspaces-workspaceid-scenario-authoring-bindings-bindingid"></a>`/x12mapper/workspaces/{workspaceId}/scenario-authoring/bindings/{bindingId}` | OPERATE | ApplyScenarioBindingRequest | 200 AppliedBindingMutationResponse; 201 AppliedBindingMutationResponse | Apply an immutable binding revision |
| `POST` | <a id="workspace-api-post-x12mapper-workspace-expression-diagnostics"></a>`/x12mapper/workspace/expression/diagnostics` | Public and stateless; no tenant data | MapperExpressionDiagnosticsRequest | 200 MapperExpressionDiagnosticsResponse | Validate one X12 Mapper fact-source expression |
| `GET` | <a id="workspace-api-get-tenant-scenario-runs"></a>`/tenant/scenario-runs` | READ | none | 200 ScenarioRunCollection | List recent scenario conversations |
| `POST` | <a id="workspace-api-post-tenant-scenario-runs"></a>`/tenant/scenario-runs` | OPERATE | StartScenarioRunRequest | 201 ScenarioRunCommandResponse | Start a run from an exact applied binding |
| `POST` | <a id="workspace-api-post-tenant-implementation-verifications-test-partner-order-invoice-runs"></a>`/tenant/implementation-verifications/test-partner-order-invoice/runs` | OPERATE | ManagedScenarioRunStartRequest | 201 ScenarioRunCommandResponse | Start the managed test-partner 850 to 810 verification |
| `POST` | <a id="workspace-api-post-tenant-test-as2-partner-warehouse-outbound-setup"></a>`/tenant/test-as2-partner/warehouse-outbound/setup` | OPERATE | WarehouseOutboundSetupRequest | 200 WarehouseOutboundSetupResponse | Prepare the managed warehouse outbound test profile |
| `GET` | <a id="workspace-api-get-tenant-scenario-runs-runid"></a>`/tenant/scenario-runs/{runId}` | READ | none | 200 ScenarioRunViewResponse | Read current scenario run state and evidence |
| `GET` | <a id="workspace-api-get-tenant-scenario-runs-runid-timeline"></a>`/tenant/scenario-runs/{runId}/timeline` | READ | none | 200 ScenarioRunTimelineResponse | Read the actor-attributed operation timeline for a run |
| `GET` | <a id="workspace-api-get-tenant-scenario-runs-runid-evidence-report"></a>`/tenant/scenario-runs/{runId}/evidence-report` | READ | none | 200 ScenarioEvidenceReport | Download the immutable evidence report for a terminal run |
| `POST` | <a id="workspace-api-post-tenant-scenario-runs-runid-cancel"></a>`/tenant/scenario-runs/{runId}/cancel` | OPERATE | CancelScenarioRunRequest | 200 ScenarioRunCommandResponse | Cancel an active scenario run |
| `POST` | <a id="workspace-api-post-tenant-scenario-runs-runid-advance"></a>`/tenant/scenario-runs/{runId}/advance` | OPERATE | AdvanceScenarioRunRequest | 200 ScenarioRunCommandResponse | Advance adapter work or reevaluate graph deadlines |
| `POST` | <a id="workspace-api-post-tenant-scenario-runs-runid-observations"></a>`/tenant/scenario-runs/{runId}/observations` | OPERATE | ScenarioRunObservationRequest | 200 ScenarioRunCommandResponse | Attach or refresh a persisted transaction observation |
| `GET` | <a id="workspace-api-get-tenant-scenario-context-transactions-messageid-transactionkey"></a>`/tenant/scenario-context/transactions/{messageId}/{transactionKey}` | READ | none | 200 ScenarioTransactionContext | Read scenario membership and eligible occurrences for one transaction |
| `GET` | <a id="workspace-api-get-tenant-scenario-context-partners-partnerid"></a>`/tenant/scenario-context/partners/{partnerId}` | READ | none | 200 ScenarioPartnerContext | Read scenario dependencies and expected documents for one partner |
| `GET` | <a id="workspace-api-get-tenant-scenario-context-mappings-mappingid"></a>`/tenant/scenario-context/mappings/{mappingId}` | READ | none | 200 ScenarioMappingContext | Read scenario dependencies and expected documents for one mapping |

Every mutation documents its idempotency and optimistic-concurrency headers in OpenAPI. Lifecycle and run-operation JSON errors use a closed envelope with a stable machine-readable `code`, a safe `error` message, and `retryable` guidance. Authentication and workspace-permission denials may intentionally have no body. Each operation publishes its closed set of stable application error codes in `x-modernedi-error-codes`.

Lifecycle resources return quoted SHA-256 ETags such as `"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"`. Runs return opaque revision ETags such as `"scenario-run:v1:42:cnVuLTUwMDdkYmYzLWYxMTUtNGNhYy04NTMwLTE4OGZiNDMyNmM0NQ:1"`. Never construct or edit either form: send the latest value returned in the resource body or `ETag` response header unchanged as the next operation's `If-Match` value.

### `POST /x12mapper/workspaces/{workspaceId}/scenario-authoring/validate`

Runs strict JSON parsing, JSON Schema validation, cross-file resolution, tenant-authority checks, graph checks, fact typing, and current runtime-capability checks without publishing or applying anything.

Headers: none.

Stable error codes: `invalid_request`.

```json
{
  "files": [
    {
      "id": "order-invoice.scenario.json",
      "fileType": "SCENARIO_DEFINITION",
      "source": "{\n  \"$schema\": \"https://www.modernedi.com/docs/scenarios/schemas/scenario-definition-v1.schema.json\",\n  \"apiVersion\": \"modernedi.com/scenario/v1\",\n  \"kind\": \"ScenarioDefinition\",\n  \"metadata\": {\n    \"namespace\": \"acme\",\n    \"key\": \"retail-order-invoice\",\n    \"version\": \"1.0.0\"\n  },\n  \"spec\": {\n    \"actors\": [\n      {\n        \"id\": \"retailer\"\n      },\n      {\n        \"id\": \"supplier\"\n      }\n    ],\n    \"steps\": [\n      {\n        \"id\": \"purchaseOrder\",\n        \"fromActor\": \"retailer\",\n        \"toActor\": \"supplier\",\n        \"transaction\": {\n          \"standard\": \"X12\",\n          \"transactionSet\": \"850\",\n          \"businessUsage\": \"purchase_order\"\n        },\n        \"occurrence\": {\n          \"min\": 1,\n          \"max\": 1,\n          \"closure\": {\n            \"kind\": \"fixed\"\n          }\n        },\n        \"assurance\": {\n          \"requirements\": [\n            {\n              \"type\": \"mapping_succeeded\"\n            }\n          ]\n        },\n        \"facts\": [\n          {\n            \"name\": \"purchaseOrderNumber\",\n            \"type\": \"string\",\n            \"cardinality\": \"one\",\n            \"normalization\": [\n              \"trim\"\n            ],\n            \"sensitivity\": \"business\"\n          }\n        ],\n        \"pipeline\": [\n          {\n            \"id\": \"exchange\",\n            \"kind\": \"exchange\"\n          },\n          {\n            \"id\": \"extract\",\n            \"kind\": \"extract\",\n            \"facts\": [\n              \"purchaseOrderNumber\"\n            ]\n          },\n          {\n            \"id\": \"assure\",\n            \"kind\": \"assure\"\n          }\n        ]\n      },\n      {\n        \"id\": \"invoice\",\n        \"fromActor\": \"supplier\",\n        \"toActor\": \"retailer\",\n        \"transaction\": {\n          \"standard\": \"X12\",\n          \"transactionSet\": \"810\",\n          \"businessUsage\": \"invoice\"\n        },\n        \"occurrence\": {\n          \"min\": 1,\n          \"max\": 1,\n          \"closure\": {\n            \"kind\": \"fixed\"\n          }\n        },\n        \"assurance\": {\n          \"requirements\": [\n            {\n              \"type\": \"transport_receipt_accepted\",\n              \"within\": \"PT4H\"\n            },\n            {\n              \"type\": \"functional_or_implementation_acknowledgment_accepted\"\n            }\n          ]\n        },\n        \"facts\": [\n          {\n            \"name\": \"purchaseOrderNumber\",\n            \"type\": \"string\",\n            \"cardinality\": \"one\",\n            \"normalization\": [\n              \"trim\"\n            ],\n            \"sensitivity\": \"business\"\n          },\n          {\n            \"name\": \"invoiceTotal\",\n            \"type\": \"decimal\",\n            \"cardinality\": \"optional\",\n            \"normalization\": [\n              \"decimal_canonical\"\n            ],\n            \"sensitivity\": \"financial\"\n          }\n        ],\n        \"pipeline\": [\n          {\n            \"id\": \"exchange\",\n            \"kind\": \"exchange\"\n          },\n          {\n            \"id\": \"extract\",\n            \"kind\": \"extract\",\n            \"facts\": [\n              \"purchaseOrderNumber\",\n              \"invoiceTotal\"\n            ]\n          },\n          {\n            \"id\": \"assure\",\n            \"kind\": \"assure\"\n          }\n        ]\n      }\n    ],\n    \"transitions\": [\n      {\n        \"id\": \"invoiceSettlesOrder\",\n        \"fromStep\": \"purchaseOrder\",\n        \"toStep\": \"invoice\",\n        \"relationship\": \"follows\",\n        \"within\": \"P30D\",\n        \"correlations\": [\n          {\n            \"id\": \"samePurchaseOrder\",\n            \"operator\": \"equal\",\n            \"left\": {\n              \"kind\": \"fact\",\n              \"stepId\": \"purchaseOrder\",\n              \"fact\": \"purchaseOrderNumber\",\n              \"projection\": \"value\"\n            },\n            \"right\": {\n              \"kind\": \"fact\",\n              \"stepId\": \"invoice\",\n              \"fact\": \"purchaseOrderNumber\",\n              \"projection\": \"value\"\n            }\n          }\n        ],\n        \"matching\": {\n          \"strategy\": \"correlate\",\n          \"quantifiers\": [\n            {\n              \"kind\": \"every\",\n              \"scope\": \"from\"\n            },\n            {\n              \"kind\": \"every\",\n              \"scope\": \"to\"\n            }\n          ],\n          \"unmatched\": \"fail\"\n        }\n      }\n    ],\n    \"assertions\": [\n      {\n        \"id\": \"invoiceTotalExists\",\n        \"operator\": \"exists\",\n        \"left\": {\n          \"kind\": \"fact\",\n          \"stepId\": \"invoice\",\n          \"fact\": \"invoiceTotal\",\n          \"projection\": \"value\"\n        }\n      }\n    ],\n    \"parameters\": [],\n    \"checkpoints\": [],\n    \"branches\": []\n  }\n}\n"
    },
    {
      "id": "order-invoice.binding.json",
      "fileType": "SCENARIO_BINDING",
      "source": "{\n  \"$schema\": \"https://www.modernedi.com/docs/scenarios/schemas/scenario-binding-v1.schema.json\",\n  \"apiVersion\": \"modernedi.com/scenario-binding-authoring/v1\",\n  \"kind\": \"ScenarioBinding\",\n  \"metadata\": {\n    \"id\": \"retailOrderInvoice\",\n    \"name\": \"Retail order to invoice\"\n  },\n  \"spec\": {\n    \"definition\": {\n      \"namespace\": \"acme\",\n      \"key\": \"retail-order-invoice\",\n      \"version\": \"1.0.0\",\n      \"contentSha256\": \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n    },\n    \"environment\": \"production\",\n    \"actors\": [\n      {\n        \"actorId\": \"retailer\",\n        \"endpoint\": {\n          \"kind\": \"partner\",\n          \"partnerId\": 42\n        }\n      },\n      {\n        \"actorId\": \"supplier\",\n        \"endpoint\": {\n          \"kind\": \"workspace\"\n        }\n      }\n    ],\n    \"steps\": [\n      {\n        \"stepId\": \"purchaseOrder\",\n        \"target\": {\n          \"kind\": \"runtime-mapping\",\n          \"runtimeMappingId\": 101\n        },\n        \"factSources\": [\n          {\n            \"fact\": \"purchaseOrderNumber\",\n            \"source\": {\n              \"kind\": \"x12-mapper-expression\",\n              \"expression\": \"ST->BEG(03)\"\n            }\n          }\n        ]\n      },\n      {\n        \"stepId\": \"invoice\",\n        \"syntaxTree\": {\n          \"x12Version\": \"004010\",\n          \"transactionSet\": \"810\"\n        },\n        \"target\": {\n          \"kind\": \"runtime-mapping\",\n          \"runtimeMappingId\": 102\n        },\n        \"factSources\": [\n          {\n            \"fact\": \"purchaseOrderNumber\",\n            \"source\": {\n              \"kind\": \"x12-mapper-expression\",\n              \"expression\": \"ST->BIG(04)\"\n            }\n          },\n          {\n            \"fact\": \"invoiceTotal\",\n            \"source\": {\n              \"kind\": \"x12-mapper-expression\",\n              \"expression\": \"ST->TDS(01)\"\n            }\n          }\n        ]\n      }\n    ]\n  }\n}\n"
    }
  ]
}
```

### `POST /x12mapper/workspaces/{workspaceId}/scenario-authoring/definitions/publish`

Publishes the exact definition source only when its canonical hash matches expectedContentSha256. Reusing an Idempotency-Key with the identical request replays the original result; reusing it for different content is a conflict.

Headers: `Idempotency-Key (required)`, `If-None-Match (required)`.

Stable error codes: `invalid_request`, `precondition_required`, `precondition_failed`, `definition_identity_conflict`, `scenario_revision_conflict`, `idempotency_key_conflict`, `content_hash_mismatch`, `scenario_authoring_quota_exceeded`.

```json
{
  "file": {
    "id": "order-invoice.scenario.json",
    "fileType": "SCENARIO_DEFINITION",
    "source": "{\n  \"$schema\": \"https://www.modernedi.com/docs/scenarios/schemas/scenario-definition-v1.schema.json\",\n  \"apiVersion\": \"modernedi.com/scenario/v1\",\n  \"kind\": \"ScenarioDefinition\",\n  \"metadata\": {\n    \"namespace\": \"acme\",\n    \"key\": \"retail-order-invoice\",\n    \"version\": \"1.0.0\"\n  },\n  \"spec\": {\n    \"actors\": [\n      {\n        \"id\": \"retailer\"\n      },\n      {\n        \"id\": \"supplier\"\n      }\n    ],\n    \"steps\": [\n      {\n        \"id\": \"purchaseOrder\",\n        \"fromActor\": \"retailer\",\n        \"toActor\": \"supplier\",\n        \"transaction\": {\n          \"standard\": \"X12\",\n          \"transactionSet\": \"850\",\n          \"businessUsage\": \"purchase_order\"\n        },\n        \"occurrence\": {\n          \"min\": 1,\n          \"max\": 1,\n          \"closure\": {\n            \"kind\": \"fixed\"\n          }\n        },\n        \"assurance\": {\n          \"requirements\": [\n            {\n              \"type\": \"mapping_succeeded\"\n            }\n          ]\n        },\n        \"facts\": [\n          {\n            \"name\": \"purchaseOrderNumber\",\n            \"type\": \"string\",\n            \"cardinality\": \"one\",\n            \"normalization\": [\n              \"trim\"\n            ],\n            \"sensitivity\": \"business\"\n          }\n        ],\n        \"pipeline\": [\n          {\n            \"id\": \"exchange\",\n            \"kind\": \"exchange\"\n          },\n          {\n            \"id\": \"extract\",\n            \"kind\": \"extract\",\n            \"facts\": [\n              \"purchaseOrderNumber\"\n            ]\n          },\n          {\n            \"id\": \"assure\",\n            \"kind\": \"assure\"\n          }\n        ]\n      },\n      {\n        \"id\": \"invoice\",\n        \"fromActor\": \"supplier\",\n        \"toActor\": \"retailer\",\n        \"transaction\": {\n          \"standard\": \"X12\",\n          \"transactionSet\": \"810\",\n          \"businessUsage\": \"invoice\"\n        },\n        \"occurrence\": {\n          \"min\": 1,\n          \"max\": 1,\n          \"closure\": {\n            \"kind\": \"fixed\"\n          }\n        },\n        \"assurance\": {\n          \"requirements\": [\n            {\n              \"type\": \"transport_receipt_accepted\",\n              \"within\": \"PT4H\"\n            },\n            {\n              \"type\": \"functional_or_implementation_acknowledgment_accepted\"\n            }\n          ]\n        },\n        \"facts\": [\n          {\n            \"name\": \"purchaseOrderNumber\",\n            \"type\": \"string\",\n            \"cardinality\": \"one\",\n            \"normalization\": [\n              \"trim\"\n            ],\n            \"sensitivity\": \"business\"\n          },\n          {\n            \"name\": \"invoiceTotal\",\n            \"type\": \"decimal\",\n            \"cardinality\": \"optional\",\n            \"normalization\": [\n              \"decimal_canonical\"\n            ],\n            \"sensitivity\": \"financial\"\n          }\n        ],\n        \"pipeline\": [\n          {\n            \"id\": \"exchange\",\n            \"kind\": \"exchange\"\n          },\n          {\n            \"id\": \"extract\",\n            \"kind\": \"extract\",\n            \"facts\": [\n              \"purchaseOrderNumber\",\n              \"invoiceTotal\"\n            ]\n          },\n          {\n            \"id\": \"assure\",\n            \"kind\": \"assure\"\n          }\n        ]\n      }\n    ],\n    \"transitions\": [\n      {\n        \"id\": \"invoiceSettlesOrder\",\n        \"fromStep\": \"purchaseOrder\",\n        \"toStep\": \"invoice\",\n        \"relationship\": \"follows\",\n        \"within\": \"P30D\",\n        \"correlations\": [\n          {\n            \"id\": \"samePurchaseOrder\",\n            \"operator\": \"equal\",\n            \"left\": {\n              \"kind\": \"fact\",\n              \"stepId\": \"purchaseOrder\",\n              \"fact\": \"purchaseOrderNumber\",\n              \"projection\": \"value\"\n            },\n            \"right\": {\n              \"kind\": \"fact\",\n              \"stepId\": \"invoice\",\n              \"fact\": \"purchaseOrderNumber\",\n              \"projection\": \"value\"\n            }\n          }\n        ],\n        \"matching\": {\n          \"strategy\": \"correlate\",\n          \"quantifiers\": [\n            {\n              \"kind\": \"every\",\n              \"scope\": \"from\"\n            },\n            {\n              \"kind\": \"every\",\n              \"scope\": \"to\"\n            }\n          ],\n          \"unmatched\": \"fail\"\n        }\n      }\n    ],\n    \"assertions\": [\n      {\n        \"id\": \"invoiceTotalExists\",\n        \"operator\": \"exists\",\n        \"left\": {\n          \"kind\": \"fact\",\n          \"stepId\": \"invoice\",\n          \"fact\": \"invoiceTotal\",\n          \"projection\": \"value\"\n        }\n      }\n    ],\n    \"parameters\": [],\n    \"checkpoints\": [],\n    \"branches\": []\n  }\n}\n"
  },
  "expectedContentSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

### `PUT /x12mapper/workspaces/{workspaceId}/scenario-authoring/bindings/{bindingId}`

Resolves the authoring document against current tenant authority, freezes exact runtime artifacts, and creates a reproducible applied revision. Use If-None-Match: * to create revision zero; use the current strong If-Match ETag for later revisions.

Headers: `Idempotency-Key (required)`, `If-Match`, `If-None-Match`.

Stable error codes: `invalid_request`, `precondition_required`, `precondition_failed`, `etag_mismatch`, `authority_etag_mismatch`, `scenario_revision_conflict`, `idempotency_key_conflict`, `content_hash_mismatch`, `scenario_authoring_quota_exceeded`, `scenario_binding_no_change`, `scenario_binding_not_executable`.

```json
{
  "file": {
    "id": "order-invoice.binding.json",
    "fileType": "SCENARIO_BINDING",
    "source": "{\n  \"$schema\": \"https://www.modernedi.com/docs/scenarios/schemas/scenario-binding-v1.schema.json\",\n  \"apiVersion\": \"modernedi.com/scenario-binding-authoring/v1\",\n  \"kind\": \"ScenarioBinding\",\n  \"metadata\": {\n    \"id\": \"retailOrderInvoice\",\n    \"name\": \"Retail order to invoice\"\n  },\n  \"spec\": {\n    \"definition\": {\n      \"namespace\": \"acme\",\n      \"key\": \"retail-order-invoice\",\n      \"version\": \"1.0.0\",\n      \"contentSha256\": \"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\"\n    },\n    \"environment\": \"production\",\n    \"actors\": [\n      {\n        \"actorId\": \"retailer\",\n        \"endpoint\": {\n          \"kind\": \"partner\",\n          \"partnerId\": 42\n        }\n      },\n      {\n        \"actorId\": \"supplier\",\n        \"endpoint\": {\n          \"kind\": \"workspace\"\n        }\n      }\n    ],\n    \"steps\": [\n      {\n        \"stepId\": \"purchaseOrder\",\n        \"target\": {\n          \"kind\": \"runtime-mapping\",\n          \"runtimeMappingId\": 101\n        },\n        \"factSources\": [\n          {\n            \"fact\": \"purchaseOrderNumber\",\n            \"source\": {\n              \"kind\": \"x12-mapper-expression\",\n              \"expression\": \"ST->BEG(03)\"\n            }\n          }\n        ]\n      },\n      {\n        \"stepId\": \"invoice\",\n        \"syntaxTree\": {\n          \"x12Version\": \"004010\",\n          \"transactionSet\": \"810\"\n        },\n        \"target\": {\n          \"kind\": \"runtime-mapping\",\n          \"runtimeMappingId\": 102\n        },\n        \"factSources\": [\n          {\n            \"fact\": \"purchaseOrderNumber\",\n            \"source\": {\n              \"kind\": \"x12-mapper-expression\",\n              \"expression\": \"ST->BIG(04)\"\n            }\n          },\n          {\n            \"fact\": \"invoiceTotal\",\n            \"source\": {\n              \"kind\": \"x12-mapper-expression\",\n              \"expression\": \"ST->TDS(01)\"\n            }\n          }\n        ]\n      }\n    ]\n  }\n}\n"
  },
  "expectedContentSha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  "expectedAuthorityEtag": "\"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\""
}
```

### `POST /x12mapper/workspace/expression/diagnostics`

Returns tree-aware X12 Mapper diagnostics for exactly one value-returning expression. This is the fast editor/tooling check used while authoring a binding; scenario Validate remains authoritative for definition fact types, exact fact coverage, tenant artifacts, and Apply eligibility.

Headers: none.

Stable error codes: none.

```json
{
  "source": "ST->BEG(03)",
  "x12Version": "004010",
  "transactionSetId": "850"
}
```

### `POST /tenant/scenario-runs`

Starts a durable run from exact definition and binding hashes. Optional typed parameters are checked against the definition before any operation is accepted. Registered adapter targets prepare their current runtime dependencies before the run is inserted; temporary preparation failures are retryable and return Retry-After.

Headers: `Idempotency-Key (required)`.

Stable error codes: `invalid_request`, `scenario_environment_not_executable`, `scenario_definition_changed`, `scenario_preparation_unavailable`, `scenario_binding_incomplete`, `scenario_target_executor_unavailable`, `idempotency_key_conflict`, `scenario_binding_changed`, `scenario_active_run_quota_exceeded`, `scenario_start_rate_limited`, `server_error`.

Explicit retryable conflicts: `scenario_start_rate_limited` (HTTP 429), `scenario_preparation_unavailable` (HTTP 503).

```json
{
  "definition": {
    "namespace": "acme",
    "key": "retail-order-invoice",
    "version": "1.0.0",
    "contentSha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  },
  "environment": "production",
  "binding": {
    "id": "retailOrderInvoice",
    "revision": 0,
    "contentSha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
  },
  "parameters": {}
}
```

### `POST /tenant/implementation-verifications/test-partner-order-invoice/runs`

Starts the named ModernEDI-managed test-partner order/invoice flow without asking the caller to create or select a binding. This is a deliberate guided shortcut for the exact bundled 850 to 810 conversation; every resulting run still uses the same scenario evaluator as a custom run and can be inspected through the general run routes.

Headers: `Idempotency-Key (required)`.

Stable error codes: `invalid_request`, `scenario_definition_not_executable`, `scenario_environment_not_executable`, `scenario_preparation_unavailable`, `scenario_binding_incomplete`, `idempotency_key_conflict`, `scenario_binding_changed`, `scenario_active_run_quota_exceeded`, `scenario_start_rate_limited`, `server_error`.

Explicit retryable conflicts: `scenario_start_rate_limited` (HTTP 429), `scenario_preparation_unavailable` (HTTP 503).

```json
{}
```

### `POST /tenant/test-as2-partner/warehouse-outbound/setup`

Idempotently creates or refreshes the ModernEDI-owned test partner and managed X12 940 runtime mapping used by the warehouse outbound example. This prepares tenant-owned dependencies but does not publish a definition, apply a binding, or start a run. Validate and Apply an exact warehouse binding in Mapper, then start it through POST /tenant/scenario-runs.

Headers: none.

Stable error codes: none.

```json
{}
```

### `POST /tenant/scenario-runs/{runId}/cancel`

Records an actor-attributed operator cancellation as an inconclusive terminal result while preserving all evidence already gathered. Cancellation is optimistic-concurrency controlled and idempotent, and it does not interrupt a command that still owns the run. If a command stops without saving a result and its temporary ownership period expires, ModernEDI records that attempt as failed and claims cancellation as one durable change. If the abandoned command may already have affected an external system, its failed timeline entry remains available for manual reconciliation. Each run can store at most 256 command records. The initial start and all later ordinary commands share 253 records; the remaining three are held for one retry record, cancellation, and a retry of cancellation. Result documents for ordinary commands share a 32 MiB budget, with additional space held for those same three reserved records.

Headers: `Idempotency-Key (required)`, `If-Match (required)`.

Stable error codes: `invalid_request`, `precondition_required`, `etag_mismatch`, `scenario_run_not_found`, `scenario_run_terminal`, `idempotency_key_conflict`, `scenario_operation_in_progress`, `scenario_run_operation_limit_exceeded`, `scenario_run_result_bytes_limit_exceeded`, `scenario_operation_ownership_lost`, `server_error`.

Explicit retryable conflicts: `scenario_operation_in_progress` (HTTP 409), `scenario_operation_ownership_lost` (HTTP 409).

```json
{}
```

### `POST /tenant/scenario-runs/{runId}/advance`

When runtime guidance selects a server-controlled step, this command dispatches or reconciles that step. Before external dispatch, ModernEDI prepares the current runtime dependencies and reconfirms the managed adapter target against the run's frozen binding authority. A temporary preparation outage is retryable and may return Retry-After; an incomplete or changed binding, or an unavailable target executor, rejects the command before dispatch. A failed adapter or preparation advance is durable: retry it with the current run ETag and a fresh Idempotency-Key. Reusing the failed operation's Idempotency-Key is a pure replay and never attempts preparation or dispatch again. Transient downstream rejections use scenario_adapter_dispatch_retryable; when the supplied x-api-key must be corrected they use scenario_adapter_dispatch_api_key_correction_required. The selected step and occurrence stay in structured run guidance instead of changing the stable error code. Observation-only and runtime-mapping steps still advance through the observation operation. For a waiting scenario run, the same empty-body command can safely ask the evaluator to recheck elapsed time: before every declared transition window and evidence deadline expires it returns HTTP 409 with scenario_observation_required, creates no operation, and leaves the run revision and ETag unchanged; once durable evidence reevaluation reaches a terminal outcome, it atomically persists a reevaluate_graph_clock operation and the completed run. The reevaluate_graph_clock value is the stable operation action recorded for this time-based reevaluation; it does not name another API. This time reevaluation never accepts x-api-key. The command rejects a stale ETag (optimistic concurrency), and replaying the same Idempotency-Key safely returns the original result (idempotency). x-api-key, when required by a selected adapter, is a transient Integration API credential used for that adapter operation only; it is not Workspace API authentication and is never persisted.

Headers: `Idempotency-Key (required)`, `If-Match (required)`, `x-api-key`.

Stable error codes: `invalid_request`, `precondition_required`, `etag_mismatch`, `scenario_run_not_found`, `scenario_run_terminal`, `scenario_adapter_dispatch_response_invalid`, `scenario_adapter_dispatch_unavailable`, `scenario_adapter_not_ready`, `scenario_adapter_reply_ambiguous`, `scenario_adapter_transaction_ambiguous`, `scenario_binding_changed`, `scenario_binding_incomplete`, `scenario_observation_required`, `scenario_predecessor_fact_not_ready`, `scenario_predecessor_observation_required`, `scenario_preparation_unavailable`, `scenario_target_executor_unavailable`, `scenario_target_not_adapter`, `scenario_target_occurrence_unavailable`, `scenario_target_partner_authority_invalid`, `scenario_target_step_unavailable`, `scenario_adapter_dispatch_api_key_correction_required`, `scenario_adapter_dispatch_retryable`, `idempotency_key_conflict`, `scenario_operation_in_progress`, `scenario_run_operation_limit_exceeded`, `scenario_run_result_bytes_limit_exceeded`, `scenario_operation_ownership_lost`, `integration_api_key_required`, `integration_api_key_not_allowed`, `server_error`.

Explicit retryable conflicts: `scenario_adapter_not_ready` (HTTP 409), `scenario_predecessor_fact_not_ready` (HTTP 409), `scenario_predecessor_observation_required` (HTTP 409), `scenario_preparation_unavailable` (HTTP 503), `scenario_adapter_dispatch_api_key_correction_required` (HTTP 409), `scenario_adapter_dispatch_retryable` (HTTP 409), `scenario_operation_in_progress` (HTTP 409), `scenario_operation_ownership_lost` (HTTP 409).

```json
{}
```

### `POST /tenant/scenario-runs/{runId}/observations`

Attaches one exact tenant-visible ModernEDI transaction to an attachable runtime-mapping or observation-only occurrence. The body identifies persisted transaction metadata; raw X12 is never accepted. The transaction must carry the exact partner-configuration fingerprint frozen into the applied binding; legacy or mismatched transactions are ineligible, while acknowledgments and receipts produced under a different configuration remain pending. Repeating the same slot and transaction with the current ETag and a new Idempotency-Key re-reads trusted transaction detail, refreshes pending mapping or acknowledgment evidence, and reevaluates the graph atomically. Reusing the original key is a pure replay and does not refresh evidence. Adapter-controlled steps reject client attachment. Mapper-derived facts use ordinary X12 Mapper semantics, with dynamic durability limits enforced before SQL persistence: collections contain at most 1000 scalar values; text scalars contain at most 4096 UTF-8 bytes; one canonical typed value contains at most 32768 bytes; and one observation's facts JSON contains at most 262144 bytes. A fact provenance receipt contains at most 4096 bytes. Each evidence document contains at most 8192 bytes, with at most 8 non-fact evidence documents and 524288 bytes of aggregate evidence JSON per observation. Capacity failures use fact_value_limit_exceeded, transaction_observation_capacity_exceeded, transaction_fact_evidence_capacity_exceeded, or transaction_evidence_capacity_exceeded. fact_evaluation_timeout and fact_evaluation_busy_or_limited return HTTP 409 with retryable=true and operationStatus=failed; reload the run if needed, then retry with its current ETag and a fresh Idempotency-Key to re-read trusted transaction evidence.

Headers: `Idempotency-Key (required)`, `If-Match (required)`.

Stable error codes: `invalid_request`, `precondition_required`, `etag_mismatch`, `scenario_run_not_found`, `scenario_run_terminal`, `observation_step_not_bound`, `observation_target_controlled`, `observation_occurrence_out_of_range`, `scenario_observation_identity_conflict`, `scenario_checkpoint_conflict`, `scenario_observation_attempt_expired`, `transaction_not_found`, `transaction_messageid_mismatch`, `transaction_transactionkey_mismatch`, `transaction_transaction_set_mismatch`, `transaction_x12_syntax_tree_version_mismatch`, `transaction_partner_mismatch`, `transaction_partner_configuration_mismatch`, `transaction_mapping_mismatch`, `transaction_timestamp_in_future`, `transaction_timestamp_invalid`, `transaction_direction_invalid`, `transaction_direction_mismatch`, `transaction_acknowledgment_timestamp_missing`, `binding_fact_source_missing`, `binding_route_not_observable`, `transaction_fact_extraction_failed`, `fact_evaluation_timeout`, `fact_evaluation_busy_or_limited`, `transaction_observation_capacity_exceeded`, `transaction_fact_evidence_missing`, `transaction_fact_evidence_inconsistent`, `transaction_fact_evidence_capacity_exceeded`, `transaction_evidence_capacity_exceeded`, `fact_value_limit_exceeded`, `transaction_observation_unavailable`, `idempotency_key_conflict`, `scenario_operation_in_progress`, `scenario_run_operation_limit_exceeded`, `scenario_run_result_bytes_limit_exceeded`, `scenario_operation_ownership_lost`, `scenario_observation_unavailable`, `scenario_observation_failed`, `scenario_observation_completion_failed`, `scenario_run_revision_changed`, `scenario_binding_changed`, `server_error`.

Explicit retryable conflicts: `fact_evaluation_timeout` (HTTP 409), `fact_evaluation_busy_or_limited` (HTTP 409), `scenario_operation_in_progress` (HTTP 409), `scenario_operation_ownership_lost` (HTTP 409), `scenario_observation_unavailable` (HTTP 503), `server_error` (HTTP 500).

```json
{
  "stepId": "purchaseOrder",
  "occurrence": 1,
  "messageId": "msg-01K5QED4DP89F67V3MKRK9R5JM",
  "transactionKey": "tx-01K5QED4DP89F67V3MKRK9R5JM"
}
```
