Skip to content
Conformance

Conformance

This appendix defines what it means to conform to this specification. It names the conformance profiles an implementation claims, and it consolidates the reference’s normative statements into one index for implementers. Apart from the statements this appendix itself defines—the profile and claim rules, the tooling guidance, and the platform boundary—everything here is a summary of a requirement stated in an owning section. The owning section is authoritative; where a summary and its source diverge, the source governs.

Normative language

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this specification are to be interpreted as described in BCP 14 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals, as shown here.

A keyword marks a requirement’s strength; it does not bound what is binding. Behavior the reference states declaratively—“the engine links the superseded failure as previous"—binds a conforming implementation as surely as a MUST. The keywords appear where strength needs saying: where a requirement is absolute, where it may be set aside for good reason, or where behavior is genuinely discretionary.

Normative and informative content

The reference is normative, with two exceptions. Concepts is an informative orientation: it introduces the model’s vocabulary, and the terms it defines, the data plane and the control plane, are used normatively elsewhere, but it states no requirements of its own. Data flow is an informative synthesis: every rule it composes is defined in an owning section. Where either’s phrasing differs from an owning section’s, the owning section governs. The Guide and Rationale are informative in their entirety.

Examples throughout the reference are illustrative. The provider specification documents published with the reference are normative for the providers they specify (see Call providers and Middleware providers).

What a requirement binds

Every requirement binds one of four subjects, named in the requirements index’s Binds column:

  • An implementation: the engine and the platform around it, the software that accepts, validates, and executes workflow definitions. Where the reference says “the engine” or “a platform”, the requirement binds the implementation.
  • A definition: a workflow definition. A definition that violates such a requirement is invalid; an implementation rejects the violation where it is statically detectable, and otherwise fails it at the validation surface that detects it (see Validation).
  • A provider: a call or middleware provider, through its contract, its catalog entry, and the surfaces it declares. The spec-defined providers ship with the implementation; the requirements bind a third-party provider equally.
  • Tooling: validators, linters, editors, and other software that reads definitions without executing them. The recurring shape of a tooling requirement is advisory: warn, never reject.

Conformance profiles

A conformance profile is a named subset of this specification’s requirements, identified by a URI. Profiles are the units of conformance: an implementation conforms to this specification by satisfying the core profile, and its conformance claim states which further profiles it satisfies.

Profile URIs

A profile URI is an opaque identifier. Implementations and tooling compare profile URIs character for character, exactly as written here, and never parse or compare them structurally—the same identity rule provider URIs follow (see Provider URIs). Like the schema documents, profiles are versioned artifacts of a specification release: the path carries the release version, and a release that changes a profile publishes the changed profile at its version. Each URI carries the same commitment the workflow $schema URI makes: it dereferences to the published definition of its profile (see Schema URIs).

URIs under https://mwl.dev/v0.1/conformance/ are minted only by this specification. A platform MAY define profiles of its own, for extension behavior it offers beyond this specification, under URIs it controls; what such a profile requires is its publisher’s to define, and a claim that includes one is portable only where the URI is honored.

The profiles

This version defines seven profiles:

ProfileURI
Corehttps://mwl.dev/v0.1/conformance/core
CELhttps://mwl.dev/v0.1/conformance/expressions/cel
CEL stringshttps://mwl.dev/v0.1/conformance/expressions/cel/strings
CEL listshttps://mwl.dev/v0.1/conformance/expressions/cel/lists
CEL setshttps://mwl.dev/v0.1/conformance/expressions/cel/sets
CEL encodershttps://mwl.dev/v0.1/conformance/expressions/cel/encoders
CEL mathhttps://mwl.dev/v0.1/conformance/expressions/cel/math

Core

Core is every requirement of the normative reference except those scoped to an expression-language profile: the data model and definition format, the Flow, Step, and call model, all seven actions, middleware mechanics, the execution model and execution context, parameter validation, the provider model and the mwl URI scheme, and the spec-defined providers, mock and the four middlewares. Core requires no expression evaluation: every shaping default is defined by the behavior it denotes and realized natively (see Expressions).

The expression profiles

The CEL profile binds the CEL conformance profile as Expressions defines it: full core CEL plus the MWL functions. An implementation SHOULD satisfy it (see Expressions).

The five extension profiles, one per recommended extension capability, each bind the operations their extension defines, with the semantics cel-go documents, however an implementation packages them. They are RECOMMENDED for an implementation claiming the CEL profile. An extension profile extends its base: a claim includes an extension profile only alongside the profile it extends.

A future expression language enters the way the embedding admits it, a new delimiter row and its own profile subsection, and mints its profile as a new URI under …/conformance/expressions/.

Conformance claims

A conformance claim is the set of profile URIs an implementation satisfies.

  • A claim MUST include the core profile.
  • A claim that includes an extension profile MUST include the profile it extends.
  • Each URI in a claim binds every requirement of that profile, at the release the URI names.

The claim is the entire statement: this specification defines no levels, tiers, or partial conformance beyond the profiles named. How a platform publishes or advertises its claim is a platform concern (see The platform boundary).

Expression-language support

Supporting an expression language is not required for conformance. Expressions makes the support posture explicit—an implementation MAY support CEL, another language, or none, and SHOULD support CEL—and defines every shaping default by the behavior it denotes, so a core-only implementation realizes the defaults without an evaluator.

The expression-free subset is a coherent static workflow language. A definition with no expressions dispatches provider and flow calls, routes on failures, fans out over declared work, sleeps, fails, and returns; every value is a literal and every default a passthrough. Expressions light up the dynamic half: shaped inputs and outputs, computed configuration, captured variables, and predicates.

Three constructs depend on expressions:

  • Match is wholly dependent: every cases clause requires a when expression, making it the one action with no expression-free form (see Match).
  • Loop is wholly dependent in use: a Loop entry’s only terminator is onSuccess.when, which every valid entry writes (see The Loop middleware). A core-only implementation still provides the middleware; the dependence binds the definitions that attach it.
  • Gather’s iterate form is practically dependent: over accepts a literal array, but the form exists to fan out over runtime data (see Gather).

A definition is within an implementation’s claim only where every expression it embeds is in a language the claim covers. An implementation MUST reject a definition that embeds an expression in a language it does not support; an expression is never read as a literal (see Expressions).

Tooling guidance

This section owns the two statements below; every other tooling entry in the requirements index summarizes a statement owned elsewhere.

Middleware composition is free by design: ordering is the author’s to choose, and the language does not invalidate a composition for being unusual (see The stack: ordering and composition). Freedom is not advice, and advice is tooling’s to give:

  • Tooling MAY warn about an unusual composition: an ordering whose behavior is well defined but unlikely to be what the author meant.
  • Tooling SHOULD warn about work amplification: a re-running middleware nested inside another re-running middleware multiplies attempts, and the product grows quickly (see Re-execution and re-entry).

The platform boundary

This specification defines a language and its observable execution semantics. Some adjacent concerns are deliberately the platform’s; conformance neither requires nor measures them.

Delivery guarantees under platform failure are platform concerns. The execution semantics imply at-least-once dispatch—the idempotency idiom built from execution.id and step.id exists for exactly that (see step)—but what a platform guarantees when its infrastructure fails, and how, is the platform’s contract with its users, not the language’s.

The same boundary holds elsewhere. What precedes the root frame—submission, queueing, scheduling—is outside the model (see execution). How terminal states are surfaced (see Result types), how the provider catalog is published (see The provider catalog), and how a conformance claim is advertised are operational surfaces of the platform.

Implementation-defined behavior

These choices are deliberately the implementation’s. Each is bounded by its owning section; differing choices here are all conformant.

  • Internal architecture: anything that preserves the execution model’s rules as observable behavior (see The completion contract).
  • Whether, and when, static checks run before execution (see Static checks).
  • The provider catalog’s contents, and the governance of namespaces beyond the reserved two (see The provider catalog and Reserved namespaces).
  • Which expression languages are supported; the conformance claim states the choice (see Expressions).
  • Additional non-success Result types, and the mapping of Result types to terminal states (see Result types).
  • The depth at which a previous chain truncates (see Chaining).
  • The size cap, if any, on System.GatherCompletionUnmet’s failures list (see System.GatherCompletionUnmet).
  • Which dispatches start first under a Gather concurrency cap, and a bound, if any, on the number of dispatches a single fan-out may enumerate (see Gather).
  • Key-order preservation in serialization, and precision handling beyond the interoperable number range (see The data model).
  • Additional temporal formats (see Temporal format profile) and additional schema dialects (see Schema documents).
  • The members of the declared extension surfaces: execution.platform (see execution), a call provider’s window metadata (see The metadata schema), and a middleware’s contributed metadata (see Contributed metadata).

The requirements index

The tables below collect the reference’s keyword statements: each row summarizes one requirement, names what it binds, and links the owning section that states it in full. The owning section is authoritative. Requirements scoped to an expression profile are marked “claiming CEL”; every other row is core.

The data model

LevelBindsRequirementDefined in
MUSTdefinitionA number is a finite RFC 8259 value; the non-finite IEEE 754 values are not data-model values.The JSON data model
MUST NOTimplementationDepend on object key order for semantics; preserving order for round-trips is permitted.The JSON data model
MAYimplementationTreat negative zero and positive zero as equal.The JSON data model
SHOULDdefinitionKeep numbers within IEEE 754 double-precision range and precision.The JSON data model
MAYimplementationReject, or lose precision on, a number outside the interoperable range.The JSON data model
SHOULDdefinitionCarry an integer identifier beyond 2^53 as a string.A single number type
MUSTimplementationAccept the temporal profile’s timestamp and duration formats; further formats are an extension.Temporal format profile
MUST NOTimplementationReject a well-formed zero or negative duration; the consuming construct defines its meaning.Temporal format profile

The definition format

LevelBindsRequirementDefined in
MUSTdefinitionMember names are unique within a single JSON object.Well-formedness
MUSTimplementationReject a definition with duplicate member names as ill-formed.Well-formedness
MUSTimplementationEvaluate every schema the format uses, meta-schema and parameters alike, under the JSON Schema 2020-12 dialect; further dialects are an extension.Schema documents
MAYtoolingValidate a definition against the published meta-schema.Schema documents
MUSTimplementationPreserve comment values across serialization round-trips.The comment field
MUST NOTimplementationInterpret comment semantically.The comment field
MAYtoolingSurface comment values in operational tooling.The comment field

Expressions

LevelBindsRequirementDefined in
MAYimplementationSupport CEL, another expression language, or none.Expressions
SHOULDimplementationSupport CEL, the language this version standardizes.Expressions
MUSTimplementationReject a definition embedding an expression in a language it does not support; an expression is never read as a literal.Expressions
MUSTimplementationReject an embedded expression in a discriminator or static identifier field (action, type, provider, next, a Step name).Where expressions may appear
MAYdefinitionMatch System.ExpressionEvaluationError in a catch; doing so is discouraged.Evaluation errors
MUSTimplementationClaiming CEL: support full core CEL as the CEL specification defines it, with no reduced subset.Conformance profile
MUSTimplementationClaiming CEL: provide the MWL functions (toJson/fromJson, durationFromIso8601/durationToIso8601, now()/wallTime()).MWL functions
SHOULDimplementationClaiming CEL: provide the recommended extension capabilities.Recommended extensions
MAYimplementationProvide further extensions beyond those recommended.Recommended extensions
SHOULDdefinitionA CEL predicate evaluates to an explicit bool.Truthiness

The Call interface and Results

LevelBindsRequirementDefined in
MUSTdefinitionA call names exactly one target, provider or flow: never both, never neither.The call object
MAYimplementationDefine additional non-success Result types.Result types
SHOULDimplementation, definitionAn extension Result type is PascalCase; the lowercase type space is reserved to this specification.Result types
MAYimplementationSurface terminal states by mapping Result types, for operational purposes.Result types
MUSTimplementationTreat an absent retryable and an explicit null alike.The failure envelope
MUSTimplementationEmit under System. only the codes this specification enumerates.Code namespaces
SHOULD NOTdefinitionMint a System. code from workflow logic.Code namespaces
MAYdefinitionA failure-constructing site sets previous explicitly, overriding the engine’s link; null severs the chain.Code namespaces

The Flow object and validation

LevelBindsRequirementDefined in
MUSTdefinitionentrypoint names a key of the Flow’s own steps object.entrypoint
MUSTdefinitionA parameters schema has "type": "object" at its top level.parameters
MUSTdefinitionStep names are unique within their containing steps object; all routing resolves within that object.Step-name scoping
MUSTdefinitionA flow name resolves within its lexical chain of enclosing flows maps; the nearest declaration wins.Flow-name scoping
MUSTdefinitionflow references form no cycle: no Flow reaches itself through the document’s call targets.Flow-name scoping
MAYtoolingWarn when a flows entry shadows a declaration in an enclosing Flow.Flow-name scoping
MUSTimplementationEvaluate format as an assertion in parameter validation.System.ParameterValidationFailed
MAYimplementationInclude the full JSON Schema validation report in a System.ParameterValidationFailed Result’s details.System.ParameterValidationFailed

Steps

LevelBindsRequirementDefined in
MUSTdefinitionnext names a key of the same steps map as the Step that carries it.Routing: next and terminal Steps
MUSTdefinitionEvery Step has a defined exit path.Routing: next and terminal Steps
MUSTdefinitionA failure matcher has at least one member.Failure matching
MUSTimplementationAccept any syntactically valid codes pattern, declared in a catalog or not.Failure matching
MAYtoolingWarn, using provider and middleware catalogs, about a pattern that matches no declared code.Failure matching, The failure catalog
MAYtoolingWarn about a catch clause made unreachable by an earlier, broader one.catch clauses

Middleware

LevelBindsRequirementDefined in
MUSTproviderA control action that races the operation it wraps defines its acceptance semantics.The phase model
MUSTdefinitionA failure constructed in onFailure has a non-success type.onFailure
MUSTproviderA middleware’s contract documents which phases expose a gateable action.What a middleware declares
MAYtoolingWarn about an unusual middleware composition.Tooling guidance
SHOULDtoolingWarn about work amplification from nested re-running middleware.Tooling guidance

Execution model

LevelBindsRequirementDefined in
MUSTimplementationPreserve the execution model’s rules as observable behavior, whatever the internal architecture.The completion contract
MUSTimplementationEvaluate each expression-valued field exactly once per execution of its containing construct.Expression evaluation timing
MUSTdefinitionCapture a value that must stay stable across re-executions into vars on first evaluation.Nondeterministic sources
MUSTimplementationnow() returns the current construct execution’s entry instant, at every evaluation within it.The clock pin
MUSTimplementationAn interrupting construct constructs its explanatory failure and imposes a cancellation chaining it as previous.The unwind
MUSTimplementationConvert a bare own cancellation at the owner’s seam: the cancellation pops, its previous continues forward.The conversion seam
MUST NOTimplementationConvert a chain whose head a cleanup failure superseded; it ascends as-is.The conversion seam
MAYimplementationSurface an external cancellation’s operational reason through the Result’s message or details.External cancellation

Observable behavior

The completion contract’s observable-behavior requirement covers every rule the execution model states, keyworded or not. Among them, these are easy to miss and load-bearing for concurrency and failure handling; each link is the defining passage:

  • Frame immutability: a frame’s variables change only on the frame’s own serial thread of evaluation. While a Gather fan-out is in flight, no write-capable evaluation runs in the frame, and a dispatch’s call fields read the variable state at the action’s start (see Frames and sequential execution).
  • Deferred arms: a Gather dispatch’s arms evaluate at fan-out completion, in dispatch order, exactly once per settled dispatch; the arms read the target windows and call.result, never step.results (see The arms at fan-out completion and When the arms run).
  • Two-stage determination: completion reads settled Result types, while the Gather’s own Result is determined after the arms run, from the final step.results; an arm fault only tightens the outcome, and settled dispatches’ arms run even on the Gather’s own-failure path (see completion: the completion policy).
  • The Retry restore: on re-entry the frame’s variables restore to their post-onEntry state; the re-entering phase’s assign evaluates against the attempt’s aftermath and applies onto the restored state, and no restore happens on final emission (see The Retry middleware).
  • The unwind’s acceptance boundary: interruption takes only work not yet committed. A target execution whose Result the platform has already accepted resolves as that Result; an interrupted target execution’s Result is the cancellation in flight (see The unwind).
  • Failure-arm faults: a fault in a call’s failure arm supersedes the failure in hand and chains it as previous (see Faults in the call object’s fields).

Execution context

LevelBindsRequirementDefined in
MUST NOTimplementationExpose execution-context members beyond those this specification defines and its declared extension points.execution
MAYimplementationExpose additional runtime data under execution.platform, including pre-run instants.execution
MAYimplementationTruncate a previous chain at a platform-defined depth.Chaining
MUSTimplementationReplace the deepest retained previous, on truncation, with a System.FailureChainTruncated error.Chaining

Step actions

LevelBindsRequirementDefined in
MUSTdefinitionA Gather carries exactly one of its two forms: over with call, or calls.Gather
MUSTdefinitioncalls is a non-empty array.Gather
MUSTdefinitionA concurrency cap is a positive integer.Gather
MUSTimplementationFail a Gather whose over result is not an array with System.ParameterValidationFailed.The iterate form: over and call
MAYimplementationCap the System.GatherCompletionUnmet failures list at a platform-defined size; failureCount is never capped.System.GatherCompletionUnmet
MAYimplementationBound the number of dispatches a single fan-out may enumerate, at a platform-defined, documented limit.Gather
MUSTimplementationFail a Gather that exceeds a fan-out bound rather than truncate the fan-out.Gather
SHOULDimplementationFail a fan-out that exceeds the bound at enumeration, before any dispatch starts.Gather
MAYtoolingWarn about an apparent tautology, contradiction, or unreachable Match clause.Predicates and failure
MUST NOTtoolingReject a definition for an apparent tautology, contradiction, or unreachable clause.Predicates and failure
MUSTdefinitionA Sleep carries exactly one of for and until.Sleep
MUSTdefinitionA Raise result type, when written, is a non-success type.Raise
MAYtoolingWarn about a convention-trespassing code in a Raise.Raise
MUST NOTtoolingReject a definition for its choice of code.Raise

Providers

LevelBindsRequirementDefined in
MUSTimplementationSupport the mwl URI scheme.Provider URIs
MUSTproviderA mwl URI conforms to the scheme’s syntax: three slash-separated parts, the segment charset, and no authority, query, or fragment.Syntax
MUST NOTproviderUse . or .. as a URI segment.Syntax
RECOMMENDEDproviderIdentifiers are lowercase with hyphens, and a name ends with a version segment.Syntax, Versions
MUST NOTproviderDefine a provider in the mwl namespace.Reserved namespaces
MUST NOTimplementationCatalog an entry under the example namespace.Reserved namespaces
SHOULDproviderA failure catalog carries a description for each closed code and open sub-prefix.The failure catalog
MAYtoolingValidate a provider specification document against its published schema.The provider definition document
MUST NOTproviderExpose window metadata members beyond the declared metadata schema.The metadata schema
MUSTimplementationProvide the mock provider.The mock provider
MUSTimplementationProvide the four spec-defined middlewares: Retry, Timeout, Loop, and Finally.Spec-defined middleware providers
MAYproviderDeclare a with parameter structural: a definition, not an evaluated value.Structural parameters
MUST NOTproviderExpose contributed metadata members beyond the declared schema.Contributed metadata
MUST NOTproviderName a contributed member enteredAt or exitedAt.Contributed metadata
MUSTdefinitionA Loop entry writes onSuccess.when.The Loop middleware

Implementation notes

This section is informative.

Window retention under Gather

The deferred arms read their dispatches’ target windows when they run, at fan-out completion (see The arms at fan-out completion). Every completed target’s window—for a flow target, the completed frame—is therefore held from the dispatch’s settlement until the fan-out completes. At a large fan-out this is a real memory consideration: the windows an implementation must be able to serve at arm time scale with the fan-out, not with what the arms ultimately capture.

The conformance corpus

A suite of specification-owned, runnable workflows, exercising the language feature by feature against the mock provider (see The mock provider), is planned as a companion artifact for validating implementations. It is not part of this specification version.