Contextfulv0.23.0

Docs / Specification

contract run · 30-run.md · 31-pipeline.md · 32-derive.md · guide · card

Durable runs

A run executes a compiled plan: read a source, record steps, commit rows and advance the source position. Implementers use this contract for the journal, retries and cancellation shared by pipelines and derive tasks. Row processing follows 31-pipeline.md.

The runner records steps, commits rows and publishes run status:

Flowchart diagram Flowchart, top to bottom. 12 nodes, 13 edges. plan reference → runner [content-hashed plan] run contract: runner → journal and blob store [record step]; → land path [batches]; → run record [terminal status]; → live projection [events after durable change] connector contract: connector source → runner [pulled batches] run contract: journal and blob store → runner [replay steps] run contract: awake endpoint → journal and blob store [resume payload] run contract: live projection → run-stream subscribers [wire snapshot] run contract: land path → run commit marker [rows and position] store contract: run commit marker → catalog cursor cache [advance cursor] store contract: catalog cursor cache store contract: stop mark → runner [polled every 500 ms] store contract: run record → live projection [reconciles status] connector contract connector source run contract record step replay steps resume payload batches events after durable change runner journal and blob store awake endpoint live projection land path store contract advance cursor run commit marker catalog cursor cache stop mark run record content-hashed plan pulled batches rows and position polled every 500 ms terminal status reconciles status wire snapshot plan reference run-stream subscribers

journal

The journal records step values, returns those values on replay and deletes records after execution retirement.

  • step-outputtesttesttheoremThe journal records a step’s value exactly once. Its effect runs at least once: a crash between effect and write repeats the effect. Every later call under the key returns the recorded value.
    Whybecause exactly-once effects need the vendor’s cooperation, and the recorded value is the one fact a replay can rely on
  • entry-keytesttesttheoremThe journal keys entries by (execution_id, step_label, input_hash). The first caller claims the key with a pending row before running the effect. A concurrent caller waits for the recorded value without computing.
    Whybecause two racers computing one key issue two billed calls and spend two meter permits
  • claim-takeovertesttesttesttheoremIf a pending claim’s run owner lease expires, owner-lease, the next caller under that key takes over the claim.
  • idempotency-keytestEvery outbound request a step makes carries an idempotency key derived from its entry key, identical on every re-entry of that effect.
    Whybecause a vendor honoring the key turns an at-least-once effect into one billed call
  • inline-cutofftestThe journal stores values of 1 MiB or smaller inline as row bytes. For larger values, the journal stores a content-addressed blob named by its sha256 and a reference in the row.
  • blob-writetestConcurrent writers of one blob hash converge on one stored value and none errors on another’s write; no partial write survives beside it.
    WhyA-run#run-substrate-storage
  • missing-blobtestIf a row references a missing blob, the journal raises BlobMissing carrying the reference. The journal returns no empty replacement value.
    WhyP6
  • collectiontesttestRetiring an execution owner deletes its journal rows in the retiring transaction; a journal store apart from the catalog deletes them after the catalog commits the retirement, and the next open under that scope repeats the delete.
    Whybecause recorded work is needed only while a replay can reach it, and an uncollected journal grows with total ingest
  • one-cutofftesttestEvery step kind follows inline-cutoff: pulls, recorded effects, input steps and awakeable payloads, whose pending row references an offloaded blob. No step kind overrides the cutoff.
    Whybecause one placement rule lets every adapter and the blob sweep read a row without knowing which step kind wrote it
  • fan-out-jointestParallel branches rejoin only at an explicit join node. A failed branch reaching the join fails the run. With allow_partial, the join instead records each failed branch’s label and failure tag on the run record.
    Whybecause an implicit join hides which branch failed, and a partial result recorded as complete reads as one
  • blob-sweeptesttesttesttheoremA mark-and-sweep pass every 24 h deletes each blob that no journal row or pending awakeable references and that is older than 1 h.
    Whybecause the grace window covers a blob written ahead of the row that names it
  • effect-boundarytestA body replays faithfully when every observable side effect passes through a recorded step, a cursor commit or an awakeable; the work between them is pure.
  • unwired-capabilitytestRequesting a capability absent from the running profile raises CapabilityUnwired at the first request, before any partial work.
    WhyA-topology#build-profiles
  • machine-statetestThe host’s own stores hold journal rows, execution owners and awakeables. The derived catalog holds none. A catalog rebuild changes none and reconstructs none from the file tree.

pulls

A journaled pull records its guarded batch, and a journal hit hands that batch to the land path.

storage

Journal rows, blobs and awakeables persist through storage ports that SQLite, PostgreSQL and D1 serve.

store-driven input

A store-driven run records its input once and runs its registered body once per input row.

callback-guard

A D1 callback guard under d1-guard: the rows it protects, the effect identity it records, its release after the holder stops, and what an operator sees of it.

Scenarios

items

The engine executes isolated input items with independent completion receipts, bounded retries and leased entity keys.

Scenarios

unsettled: Does a job credential holding a mask exception record its entity key in the clear on _items, or does the item record apply the source column’s mask itself? owner: run-path affects: run.items

advance

The engine commits source positions according to cursor kind and re-reads rows at each poll’s boundary.

Scenarios

suspend

The engine suspends runs durably until an external callback resolves an awakeable or its deadline expires.

retry

The runner classifies failures and schedules step retries through one retry layer.

own

An execution owner binds pending work to a scope, connector build and plan identity.

body pins

A registered body’s owner pins bind its executable, its dependencies and its parent execution before any input read.

operator retirement

An operator verb or an applied declaration retires a pending owner and records the retirement as a run row.

staging and checkpoints

A run stages each batch as a part, bounds its staged bytes and commits its parts once or at checkpoints.

Flowchart diagram Flowchart, top to bottom. 10 nodes, 11 edges. run open → marker past cached position? [cached position] marker past cached position? → fresh execution id [yes, retire pending owner]; → pending owner? [no] fresh execution id → close status [new run] pending owner? → fresh execution id [no]; → pinned identity unchanged? [yes] pinned identity unchanged? → terminal failure [no: ExecutionPinMismatch]; → recorded step replay [yes] recorded step replay → close status [replayed run] close status → released owner [success, no batch, reproducible failure]; → held owner [any other status] cached position yes, retire pending owner no no yes no: ExecutionPinMismatch yes replayed run new run success, no batch,reproducible failure any other status run open marker past cached position? fresh execution id pending owner? pinned identity unchanged? terminal failure recorded step replay close status released owner held owner

Scenarios

unsettled: Which pass collects the staged parts of a run that crashed before its commit, and after what age? owner: run-path affects: run.own

cancel

The engine stops work at run or pipeline scope through a shared cancellation token and records the remaining durable state.

Scenarios

record

The store records run status, owner leases and execution history. History requests select a time window and row ceiling.

Scenarios

project

The runner publishes a best-effort live view of run progress to subscribers.

sweep

The scheduler runs one store-driven job per origin across a declared span. Each origin reads data available at that origin under one frozen transaction-time bound.

Scenarios

unsettled: Does a carried-state sweep resume from the last committed origin or replay from the start? owner: run-path affects: run.sweep

orchestrate

Each deployment supplies a durable orchestrator implementing the execution interface. This section specifies provider steps and the engine behavior inside each step.

Scenarios

unsettled: Where does a target profile record a provider’s step ceiling, so a backfill whose chunk plan passes it refuses at planning? owner: topology affects: run.orchestrate

Shapes

Run statuses:

State diagram State diagram, top to bottom. 9 states, 13 transitions. start → pending pending → running running → waiting [awakeable]; → success; → partial_failure; → failed; → canceled waiting → running [resumed]; → canceled success → end partial_failure → end failed → end canceled → end awakeable resumed pending running waiting success partial_failure failed canceled