Core model·Timelines and contracts

Timelines and contracts

Blue documents become processable when they contain contracts. A contract declares how the document reacts to delivered evidence: which channel accepts an event, which operation it requests, which workflow runs, which Compute step returns patches, which events are emitted, and which checkpoints prevent duplicate delivery.

This page explains the runtime model used by the examples. It is not a replacement for the normative Contracts and Coordination specifications. It is the working model you need before reading Counter or the weekend package checkout.

§Processing is replayable state transition

The central model is:

Snippet
1PROCESS(document, delivered_event)
2 -> new_document
3 -> triggered_events
4 -> gas_and_metadata

In practice, the delivered event is often a timeline entry. The document is the current canonical document state. The processor evaluates registered contract processors. The output is a new canonical document plus emitted events and metadata.

The important promise is determinism. Given the same initialized document, the same ordered input entries, the same repository content, and the same processor implementation, processing should produce the same output document and output identity.

This is not the same as a normal web request handler. A request handler can read a database, call an API, check the clock, generate randomness, and mutate state wherever it wants. A Blue processor should make the explainable state transition visible in the document result.

§Timeline entries are evidence, not commands that automatically mutate state

A timeline entry says that something was delivered in an ordered context. It does not automatically change the document.

A document changes only if its contracts accept the entry and produce changes.

Snippet
1delivered timeline entry
2 -> channel match
3 -> operation match
4 -> workflow execution
5 -> Compute/BEX result
6 -> patch application
7 -> emitted events
8 -> checkpoint update

This distinction is crucial. If every delivered event automatically mutated state, the document would not control its own process. Blue's runtime model lets the document state and contracts explain why a particular entry mattered.

§Channels decide what can enter

A channel is the first gate. In Coordination examples, a timeline channel can bind document logic to a timeline provider and timeline id:

YAML
1contracts:
2 ownerChannel:
3 type: Coordination/Timeline Channel
4 timelineId: counter-demo

In a local test, a fixture channel processor might deliver a Coordination/Timeline Entry with timelineId: counter-demo. In production, the timeline provider has a bigger responsibility: ordering, actor attribution, completeness, source verification, and delivery policy.

Do not treat a timeline channel as a magical global event bus. The Coordination Java processor set intentionally does not register a concrete production processor for Coordination/Timeline Channel. Applications provide the timeline provider behavior appropriate for their trust model.

§Operations name the requested action

A Coordination/Operation declares an operation that can be requested through a channel:

YAML
1contracts:
2 increment:
3 type: Coordination/Operation
4 channel: ownerChannel
5 request:
6 amount:
7 type: Integer

The request shape is part of the operation's contract. A delivered operation request should name the operation and provide a request payload that matches the expected structure.

For Counter, an entry might look like:

YAML
1type: Coordination/Timeline Entry
2timeline:
3 timelineId: counter-demo
4timestamp: 1
5message:
6 type: Coordination/Operation Request
7 operation: increment
8 request:
9 amount: 5

The processor can now ask: does this entry arrive on the right channel? Does it request an operation declared by this document? Does the request match the declared shape? If yes, which workflow implements it?

§Workflows implement operations

A Coordination/Sequential Workflow Operation binds an operation to sequential steps:

YAML
1contracts:
2 incrementImpl:
3 type: Coordination/Sequential Workflow Operation
4 operation: increment
5 steps:
6 - name: IncrementAndEmit
7 type: Coordination/Compute
8 do:
9 - $appendChange:
10 op: replace
11 path: /counter
12 val:
13 $add:
14 - $document: /counter
15 - $event: /message/request/amount
16 - $appendEvent:
17 type: Counter/Incremented
18 amount:
19 $event: /message/request/amount
20 - $return:
21 changeset:
22 $changeset: true
23 events:
24 $events: true

Sequential means the order is meaningful. Later steps can observe prior step results when the host provides those bindings. For most dynamic behavior, the important step type is Coordination/Compute, which executes BEX.

§Compute runs BEX and returns a result

Coordination/Compute is the BEX execution surface in the current Java Coordination implementation. A Compute step can return a changeset and events. The Coordination processor applies returned changes directly and emits returned events directly.

That is the boundary:

Snippet
1BEX computes changeset and events
2Coordination processor applies/emits them

BEX itself does not mutate the document. It accumulates result data. The host decides what to do with the result.

This boundary is important enough to repeat in code:

YAML
1- $appendChange:
2 op: replace
3 path: /counter
4 val: 5
5- $appendEvent:
6 type: Counter/Incremented
7 amount: 5
8- $return:
9 changeset:
10 $changeset: true
11 events:
12 $events: true

The patch and event are not applied merely because the BEX statement exists. They are returned to the Compute host. The Coordination processor is the runtime surface that applies them.

§Checkpoints prevent duplicate delivery

Timeline systems deliver evidence. Real systems also retry. If the same delivered timeline entry is processed twice, a counter should not increment twice and a payment flow should not request completion twice.

Checkpoints record delivered entries or channel-processing state so duplicates can be ignored. In Counter, after a timeline entry increments /counter, the processed document should include checkpoint metadata showing that the entry has been delivered. If the same entry appears again, the channel/workflow should not run the mutation again.

The weekend package example adds BEX guards on top of checkpoints. For example, if a payment token is already attached, the attachPaymentToken workflow returns unchanged. If a component order is already attached and the new snapshot does not match the existing document/session identity, the workflow emits a rejection event instead of overwriting it.

Use both layers:

  • checkpoints protect the processing infrastructure from duplicate delivery;
  • BEX guards protect the business workflow from repeated or invalid actions.

§Triggered events are not automatically external side effects

A workflow can emit events:

YAML
1- $appendEvent:
2 type: PayNote/Complete Payment Requested
3 amount: 49900

That event is part of the processing result. It may trigger another contract inside the same document, be delivered to another document, be picked up by a host integration, or be stored for audit. But emitting an event is not the same as calling a bank, sending an email, or booking a hotel.

External effects belong outside the deterministic processor. The document can request or record them. The host system decides how to integrate with external rails and then delivers authoritative evidence back into the Blue process.

In PayNote terms, a participant's request is not proof that money moved. A guarantor response is the authoritative evidence that the rail action happened or failed.

§Embedded documents have scopes

A parent document can embed child documents:

YAML
1embeddedDocs:
2 packagePayNote:
3 type: PayNote/PayNote
4 kind: PayNote
5 orders:
6 hotelOrder:
7 kind: Order
8 orderKind: hotel
9 restaurantOrder:
10 kind: Order
11 orderKind: restaurant

Contracts can process embedded scopes and observe child events:

YAML
1contracts:
2 embeddedPackagePayNoteEvents:
3 type: Core/Embedded Node Channel
4 childPath: /embeddedDocs/packagePayNote
5
6 processEmbeddedDocs:
7 type: Core/Process Embedded
8 paths:
9 - /embeddedDocs/packagePayNote
10 - /embeddedDocs/orders/hotelOrder
11 - /embeddedDocs/orders/restaurantOrder

In the weekend package flow, this is what lets the parent package order react when the embedded PayNote emits PayNote/Payment Completed, and what lets the PayNote observe confirmation events from embedded hotel and restaurant orders.

The embedded child is still document content. The runtime scope says how processing is routed.

§Lifecycle events initialize documents

Some processing should happen when a document is initialized, not when a user sends a business operation. A lifecycle channel can react to document processing initiation:

YAML
1contracts:
2 initLifecycleChannel:
3 type: Core/Lifecycle Event Channel
4 event:
5 type: Core/Document Processing Initiated
6
7 initializeOrderTemplateSourceOfferLink:
8 type: Coordination/Sequential Workflow
9 channel: initLifecycleChannel
10 steps:
11 - name: BuildOrderTemplateLinkPatch
12 type: Coordination/Compute
13 do:
14 - $appendChange:
15 op: replace
16 path: /orderTemplate/document/contracts/links/packageOffer/documentId
17 val:
18 $document: /contracts/initialized/documentId

The weekend package offer uses this pattern to connect the order template back to the source offer after the offer has an initialized document id. It is a good example of lifecycle logic that belongs in the document because it affects future processing and links.

§What the processor does and does not do

The processor does:

  • receive a current document and delivered event;
  • evaluate registered channel, operation, workflow, marker, and embedded processors;
  • execute BEX inside Compute steps;
  • apply returned canonical patches;
  • collect emitted events;
  • record checkpoints and metadata;
  • return a new canonical document and output identity.

The processor does not:

  • decide your production timeline trust model by itself;
  • fetch arbitrary untrusted history unless you build that provider;
  • call payment rails directly from BEX;
  • give BEX ambient network, file, clock, or random access;
  • make a participant request authoritative without a workflow that accepts it as evidence.

This is how Blue stays deterministic while still integrating with real systems.

§Reading Counter through this model

Counter has the smallest useful runtime shape:

Snippet
1entry: increment by 5
2 -> ownerChannel accepts timelineId counter-demo
3 -> increment operation matches
4 -> incrementImpl workflow runs
5 -> Compute reads /counter and event request
6 -> BEX returns replace /counter with 5
7 -> BEX emits Counter/Incremented
8 -> processor applies patch and records checkpoint

If this loop is clear, you understand the base runtime.

§Reading Weekend package checkout through this model

The weekend package flow is the same loop repeated across several contracts:

Snippet
1seller confirms package order
2 -> package status moves toward checkout preparation
3
4seller attaches payment token and expected PayNote descriptor
5 -> payment token is stored
6 -> order becomes ready_for_checkout
7
8PayNote is attached
9 -> package embeds the PayNote
10 -> payment state moves to paynote_attached
11
12PayNote emits Funds Secured
13 -> parent package marks payment_secured
14
15hotel and restaurant order snapshots attach
16 -> child orders become embedded component state
17
18hotel and restaurant confirm
19 -> PayNote sees both confirmations
20 -> PayNote emits Complete Payment Requested
21
22payment completes
23 -> embedded PayNote emits Payment Completed
24 -> parent package marks payment completed and ready_to_use

The business flow is larger, but the runtime idea is the same: delivered evidence meets document-owned contracts and produces deterministic document changes.