Contextfulv0.23.0

Docs / Specification

A-topology — System topology decisions

Status: accepted

cloudflare-d1 — Cloudflare execution metadata uses D1

Cited bytopology.coordinate.backendsrun.journal.d1-profile

The deciding criterion is one metadata backend across the deployment configuration, the execution binding and its conformance suite. Durable Objects still manage Container lifecycle; D1 replaces only the catalog role.

OptionLost onCost
D1 metadata with R2 objects (chosen)—Metadata operations cross the private Worker binding.
D1 and Durable Object SQLite variantsBackend consistencyTwo catalog integrations and conformance paths.

one-egress — One inference egress and one destination; no vendor SDK, no sink plugin

Cited bytopology.compose.inference-egresstopology.compose.vendor-sdkrun.land.unknown-destinationrun.land.no-host-armrun.export-iceberg.egressconnector.infer.model-endpoint

A provider swap is a URL edit, and the host owns credential, rate limit and span. Synthesized output falls under the same grants, masks and retention as landed data.

OptionLost onCost
One compatible endpoint, one destination (chosen)—A vendor feature outside the compatible wire is unreachable.
A vendor SDK per providerDependency custodyEach SDK links its own HTTP stack and dictates auth and retry.
A plugin interface for backends or sinksAttack surfaceA loaded plugin holds credentials; the destination set is unnameable.
A webhook destinationDelivery semanticsAt-least-once messaging, which the commit model cannot honor.

Revisit: a capability a deployment needs that no OpenAI-compatible endpoint exposes.

build-profiles — Profile capabilities are fixed at build; an absent one is a typed refusal

Cited bycorpus.targets.filetopology.package.profiletopology.package.fixed-at-buildtopology.package.profile-leaktopology.package.capability-absenttopology.package.component-hosttopology.package.host-missingtopology.package.crdt-leakread.register.engineread.rank.degradation-not-errorread.rank.caller-embeddingread.embed.required-faceread.embed.absent-read-backendrun.journal.unwired-capability

A capability the running profile does not wire is a typed refusal when reached, never a panic, no-op or look-alike fallback.

OptionLost onCost
Build-time profiles; typed refusal on reach (chosen)—Three artifacts to build, size-gate and release.
One binary with run-time feature detectionFootprintEvery heavy dependency links into the replica.
Dynamically loaded pluginsPortabilityStatic musl targets load no plugins.
Degrade to a partial answerHonesty of the outcomeA lexical-only ranking or empty result reads as complete.

control-crdt — The control plane edits the configuration as one CRDT document and claims through the shared snapshot package

Cited bytopology.package.control-profiletopology.package.control-team-statetopology.package.apply-home

Team state is the configuration itself, so replicas merge offline edits to it, and local and control-plane applies share one version claim, pointer and replay store.

OptionLost onCost
One CRDT document; one shared snapshot package (chosen)—Concurrent edits can merge into invalid TOML, which apply refuses before claiming.
A team-state model beside the configurationSingle sourceTwo documents to reconcile on every apply.
A copy of the snapshot code in the control packageOne homeTwo claim paths whose version races drift apart.
The engine linked into the control profileProfile roleThe control profile links the run path.

public-surfaces — The engine and its consumers meet only at public surfaces

Cited bytopology.compose.three-crossingstopology.compose.undeclared-crossingtopology.bound-application.domain-neutralsurface.package.store-selector

Each shared contract has a version and conformance tests. A behavior becomes shared once a second application needs it; no license check guards a data-plane capability.

OptionLost onCost
Three versioned contracts; domain-neutral engine (chosen)—A new shared contract needs review; a consumer supplies its own domain meanings.
A general internal RPC surfaceReview surfaceEvery call is a place a capability can enter.
A privileged internal API for one consumerWholenessOther consumers receive a subset of the engine.
The first application’s vocabulary as defaultsInheritanceLater applications receive meanings they did not choose.

deploy-observation — A deploy verifies by observation

Cited bytopology.deploy.unsupported-shapetopology.deploy.paritytopology.deploy.parity-divergence

Each hostname descriptor names its worker, contract version and gate with an explicit acknowledgement, and the deploy judges an anonymous GET / against that gate.

OptionLost onCost
Declare, then observe and compare (chosen)—A deploy waits on probes and a soak.
Posture derived from provider configurationRecoverability of intentConfiguration records no gate, so an accidental opening reads as deliberate.
A periodic external monitorTimingThe exposure window is the monitor’s interval.
Per-target expected outputsDetectabilityA divergence arrives as a fixture update, which reviewers approve.

posture-probe — The posture probe runs in build tooling; the gateway caches nothing

Cited bytopology.publish-hostname.posture-mismatchtopology.publish-hostname.probe-table

The gateway sits in front of a retrieval container that enforces grants per request, so a cached answer comes from inside the container, after enforcement. Profile footprint decided where the probe runs.

OptionLost onCost
Probe in contextful-ci, no hop cache (chosen)—Every request crosses to the container; a pipeline that skips the probe goes unprobed.
Probe as an engine subcommandFootprintEvery profile links a client only a deploy uses.
Probe inside the gateway at startTimingA gateway answers traffic before its posture is judged.
A short hop cache keyed on the enforcement subjectMediationA revoked grant still answers from the hop until expiry.

domain-crate — The domain crate holds types and ports with no I/O, and every edge points toward it

Cited bytopology.package.domain-cratetopology.package.domain-impuritytopology.package.dependency-direction

OptionLost onCost
A pure centre of types and ports, edges inward (chosen)—Adapters restate small conversions; a port change touches every adapter.
A centre with its own runtime and formatFootprintThe replica and control plane link a runtime neither uses.
A shared utility crate both directions useDirection reportabilityA cycle re-enters legally, with no single offending edge.
Ports beside their adapters, no centreNeutral homeThe shared error enum has nowhere to live.

Revisit: two adapters convert the same shape differently; a port change deferred more than once.

enforcement-stack — Every access to data traverses the enforcement stack, and no configuration disables it

Cited bytopology.compose.mediation

No flag, environment variable or build feature disables access controls. A surface holding the only handle to data reaches it through an adapter over the stack.

OptionLost onCost
Mediation as a build property (chosen)—A bulk export or offline diagnostic is slower than a direct read.
An operator flag marking a trusted pathFailure modeA flag set once stays set while the deployment looks healthy.
Per-surface opt-in enforcementCoverageEvery new surface is a fresh chance to omit it.
Enforcement asserted by review aloneDetectabilityA bypass reads as a call-site move in a refactor.

Revisit: an adapter through the stack misses a stated throughput requirement.

export-committed — Export reads committed runs and is no second destination

Cited byrun.export.post-commit-read

_ingested_at is stamped per run, so a cursor over it skips a run that commits late under an earlier stamp. Export target secrets resolve and leave through the same egress as every other secret.

OptionLost onCost
Commit-sequence cursor (chosen)—A commit waits for every lower value to publish; a target sees duplicates on recovery.
Export as a second land destinationDelivery semanticsA failing target fails the landing run.
A cursor over _ingested_atSkipped rowsA late run under an earlier stamp is skipped.
A sink plugin per backendCredential custodyLoaded code holds target credentials.

commit-lock — A commit holds the commit lock to reserve its value and to publish, not to write

Cited bystore.reserve.commit-seqstore.reserve.commit-orderstore.reserve.commit-lock-spanstore.reserve.commit-waitstore.reserve.commit-markerstore.reserve.commit-seq-seed

A lock spanning the Parquet write serializes a table’s landings. A commit instead locks a ticket file naming its value while it writes parts; a dead holder’s ticket unlocks with its process, leaving a gap.

OptionLost onCost
Lock to reserve and publish, ordered by ticket (chosen)—A slow part write delays later publications; a vintage table stays serial.
Lock over the part writeThroughputA table’s landings write parts serially.
Tickets without livenessDead landingsA dead ticket holder stalls later commits.
Readers skip unpublished valuesPrefixAn export cursor passes a value that publishes later.

queue-ingress — A managed queue extends ingress behind a port; the writer stays in the engine

Cited bytopology.compose.queue-extensionrun.export.export-blockrun.export.commit-orderrun.export.deliveryrun.export.at-least-once

On a container with an ephemeral disk, the local spool loses a batch on eviction and a cold boot blocks every sender. Single-node and edge shapes keep no external queue.

OptionLost onCost
Queue port, managed queue where declared (chosen)—A sender wanting the outcome reads it by batch key; an expired key ends a batch as a refusal.
Local spool on every shapeDurabilityAn evicted container loses a spooled batch.
A managed queue on every shapeOne treeLaptop and edge shapes gain an external process.
Store writes in queue consumersOne writerCommit ordering rests on locks a consumer does not hold.

catalog-read-add-on — A catalog query engine over Iceberg exports is an optional read face beside the Container

Cited byrun.export-iceberg.blockrun.export-iceberg.file-sizerun.export-iceberg.route

A Container query face that sleeps pays a full hydration on its next read: 145 s for 1 GB in 8,157 objects, answering 503 until ready. Basin SQL over an Iceberg export of 10M rows answers a first read in 3.6 s and a warm one in 0.7 to 1.6 s at p50; a warm Container over 1.27M rows answers in 0.2 to 0.4 s. Read latency, idle cost and the frontier a reader sees decide.

At Workers Paid list prices, an always-on standard-1 Container costs about $27.5 a month whatever its query count. Basin SQL bills $2.50 per TB scanned with a 10 MB minimum per query, so a small query costs $25 per million, beside R2 writes and retained snapshot copies. They meet near 1.1 million queries a month. A 4,000-file table raises warm p50 1.2 to 2.1 times against 40 files and takes 24 s cold, so file size bounds latency and cost.

OptionLost onCost
Container face for all, a catalog engine per exported audience (chosen)—An opted-in audience reads a copy 39 to 54 s behind a 5.1 GB fold.
Container face aloneIdle costA sporadic audience keeps a Container warm or waits minutes on a first read.
Catalog engine for every callerRead latencyHot callers pay 2 to 5.2 times the warm p50.
A catalog over the store’s own filesP5Any engine skips the caller’s relation.

Revisit when a catalog engine’s warm p50 falls below 300 ms.

aws-fargate — AWS hosts every process on Fargate, and Lambda hosts none

Cited bytopology.package.edge-eligibility

Serving is long-lived by design: serve holds a hydrated snapshot set, refreshes it on an interval and answers concurrent requests from one process. A function instance freezes between requests, handles one request at a time and hydrates on each cold start, so one host lifecycle across every AWS process decides this.

OptionLost onCost
Every process on Fargate (chosen)—An idle serving task costs its reservation.
contextful-edge on Lambda for readsHost lifecycleRefresh stops while an instance freezes, bursts multiply cold hydration, and a second runtime joins the parity check.
Lambda reconciler starting Fargate tasksOne scheduler pathA function exists only to start a task EventBridge Scheduler starts directly.
Step Functions orchestrationOne durable recordA second step history beside the engine journal in the catalog.

Revisit: many small stores whose idle serving cost outweighs a second runtime’s upkeep, once a small task or a service scaled to zero no longer answers it.