One small boundary
The whole processing model is one function:
PROCESS(document, event) → new document + emitted events + gas used
Deterministic, atomic, no wall clock, no network, no hidden state. Same document, same event — same result, on any conforming implementation, forever. If processing fails, the previous document stands untouched. There is no half-applied state to clean up, because half-applied states cannot be expressed.
Events arrive through channels
A document declares named routes through which events may enter:
contracts:
restaurantChannel:
type: Timeline Channel
# bound to the restaurant's verified history — see Timelines
Where those events come from and why they're trustworthy is the Timelines section's job. For now: an event enters through a channel, and behavior binds to channels — not to "anything that looks right."
Handlers and Operations
A Handler reacts to events on its channel. The most useful kind is an Operation — a named, callable capability. Here is a dinner order the restaurant can confirm:
name: Dinner Order
status: proposed
contracts:
restaurantChannel:
type: Timeline Channel
confirm:
type: Sequential Workflow Operation
channel: restaurantChannel
request:
reference:
type: Text
steps:
- name: Apply Confirmation
type: Compute
do:
- $appendChange:
op: replace
path: /status
val: confirmed
- $appendEvent:
type: Order Confirmed
- $return: true
Interface and implementation, visible in one place: the operation is confirm, it belongs to the restaurant's channel, it takes a reference, and its exact steps are right there — with their own BlueId, like everything else.
Nobody writes /status directly. A caller submits an Operation Request:
type: Operation Request
channel: restaurantChannel
operation: confirm
request:
reference: DINNER-8841
The operation owns the transition. That single discipline — requests name operations, operations own state — is what keeps invariants enforceable and history explainable. It matters doubly once callers include machines: an operation surface is discoverable and constrainable; raw writes are neither.
Documents have lifecycles
Documents aren't rows that exist until deleted. They initialize, live, and terminate — and each phase is processed behavior:
initialize → active → ... → terminated
Initialization is itself processed: handlers can react to Document Processing Initiated like any other event — establishing derived state, checking required configuration, or failing deterministically before anything else runs. Termination is graceful: handlers get to react, the final state remains inspectable, and the history explains why it ended.
Different documents live differently, with no extra machinery:
- a standing agreement initializes once and lives through months of operations;
- a one-shot approval initializes, processes one decision, emits a result, terminates;
- an embedded order is born when its parent creates it and reaches a terminal state without ending the parent;
- a Mandate moves Pending → Active → Terminated, and its current stage is its authority.
Nothing vanishes; things conclude — with an exact final state and a reason.
BEX: logic as data
The do: blocks above are BEX — Blue's deterministic expression language, written as data, not as code strings. A BEX program reads the document and event, computes values, and returns effects — changes and events — which the processor applies under its own rules. Because BEX programs are Blue nodes, they have BlueIds: behavior is versioned, referenced, and audited exactly like data. No clock, no randomness, no network — by construction.
Gas
Deterministic processing needs a deterministic budget, or a malformed document could react forever. Gas is Blue's answer, and it belongs to the language's processing model as a whole — not to any single runtime. The processor meters everything it does — patches, event routing, validation, lifecycle — and every runtime it hosts reports into the same ledger; BEX contributes its own counters (expressions evaluated, reads, items examined) as one participant among others.
Two properties matter. The total is identical across implementations: same document, same event, same gas, on a laptop or a server farm. And it is representation-neutral: warm caches and pre-expanded nodes make processing faster, never cheaper — and a workflow that never reads a ten-thousand-node archive pays nothing for the archive's existence. Gas prices meaning, not plumbing.