Expand description
cratefield-core is the runtime-agnostic kernel of the Factory Zero harness:
the Module contract, the Harness builder, port traits, RFC 9457
problem+json errors, the request Scope, an in-process EventBus and
a TemplateRegistry (ADR 0001, 0002, 0007).
Core depends only on http, axum (default features off), serde,
tracing, sea-query and pure-Rust crypto. It must never depend on
worker, wasm-bindgen, tokio, reqwest, sqlx or rusqlite, and
never touches std::fs or std::net — CI enforces this with a
cargo tree check and the wasm build of examples/venture.
§cratefield-core
The runtime-agnostic kernel of the Cratefield harness: the Module
contract, the Harness builder, the port traits, RFC 9457
problem+json errors, the request Scope, an in-process EventBus,
and the template registry (ADRs 0001, 0002, 0007).
Core depends only on http, axum (default features off), serde,
tracing, sea-query and pure-Rust crypto. It must never depend on
worker, wasm-bindgen, tokio, reqwest, sqlx or rusqlite — a
CI job fails the build if one appears. That is what lets the same
modules run on Cloudflare Workers (wasm) and, in phase 3, as a native
binary.
§The shape
Harness::builder()
.venture(Venture::new("acme", "acme.example.com").cors_origins([..]))
.module(EmailSignup::new().double_opt_in(true)) // any Module impl
.templates(EmailSignup::default_templates()) // + overrides
.runtime(Cloudflare::new().db("DB")) // any Runtime impl
.build()? // all problems at oncebuild() refuses a module that requires a port the runtime does not
provide, two modules claiming the same table or route prefix, a module
built against a different contract version (HARNESS_API), or a
template override naming an unknown module — and it reports every
problem in one error, not the first. router(ports) then mounts each
module under /v1/<name>, adds GET /__health / GET /__ready, the
request-scope middleware (request id + Scope in extensions, ADR 0007),
CORS from venture.cors_origins, a 64 KiB body limit and /v1/*
security headers.
§What lives here
| Piece | What it is |
|---|---|
Module / ModuleContext | the module contract; see docs/MODULE-AUTHORING.md |
Harness / HarnessBuilder | composition, validation, router assembly |
ports::* | Database, Mailer, Captcha, RateLimiter, Signer, KeyValue, HttpClient, Clock, IdGen, Defer — Send + Sync trait objects |
Problem / problems! | RFC 9457 errors with a stable slug taxonomy (generated into docs/ERRORS.md) |
Scope | per-request id + span + wait_until, an axum extractor, never shared state |
EventBus | in-process "<module>.<event>" handlers, run in the emitting request’s scope |
TemplateRegistry | mail templates with per-venture overrides |
HmacSigner | signed tokens for confirm/unsubscribe links with key rotation (ADR 0006) |
| admin / csv / email / rate-limit helpers | constant-time admin auth, formula-injection-safe CSV, email normalization |
§Writing a module
Start with docs/MODULE-AUTHORING.md —
it builds a complete module, cratefield-module-hello, step by step.
§Testing a module
cratefield-testing is the conformance kit: fake ports, an
in-memory SQLite Database, and request helpers over the real axum
router, no network. Every module — public or private — passes it.
MIT. Built in the open for Cratefield, a Factory Zero venture.
Re-exports§
pub use axum;
Modules§
- billing
- Provider-neutral billing lifecycle (ADR 0025, issue #593).
- sigv4
- AWS Signature Version 4 for the
Blobport (issue #622).
Structs§
- Accounting
- The price sheet and the ledger every call is recorded to — what the router, the shadow classifier and the corpus runner are all given, so no classifier call through them goes unrecorded.
- Action
- One route the module serves, described for a renderer.
- Actor
Handlers - The handlers a venture registered, by kind. Built from the
HarnessBuilder::actorregistrations so an in-process actor host can dispatch to them. - Actor
Writes - The writes one handler call staged, applied by
ActorStore::commit. - Adapter
Id - The name a venture wires a classifier adapter under — the key prices, thresholds and agreement evidence are kept by. The port does not name its adapters, so the wiring does.
- Agreement
At - The slice of a kind’s evidence the cheap adapter would have been trusted on at some thresholds.
- Agreement
Log - Accumulates an
AgreementReportone compared answer at a time. - Agreement
Report - Agreement between two named adapters, per question kind.
- Answer
- One answer: the value decided, the probability mass per label, and the probability of the value that came back.
- ApiKey
Principal - A verified key’s answer to “who is calling, and what may they do?”.
- ApiKeys
- A store of API keys over the
Databaseport; the owning app shipscreate_table_sqlas a migration. Timestamps are RFC 3339TEXTfrom theClockport, the house shape (cratefield_core::SendCooldowndocuments why lexicographic order on that format is chronological order). - Blob
Meta - What a store knows about an object without reading its bytes
(issue #586): the metadata a
Blob::headcall returns, and one row of aBlobPage. - Blob
Object - A stored object: its bytes and the content type to serve it with.
- Blob
Page - One page of a
Blob::list(issue #586).cursorisNoneon the last page and otherwise an opaque token to hand straight back to the nextlistcall — the module never parses it. - Blob
Stream - A streamed object body (issue #586): what
Blob::get_streamreturns instead of buffering the bytes.sizeandcontent_typeare known before a single chunk is read, so a handler can set response headers from them. - Bounded
Http Client - Wraps any
HttpClientso the port’s bounds hold on every runtime: the deadline is enforced through theClockport (the only timer core is allowed to use), and the response is refused — by declared length before anything else, then by actual size — when it exceeds theHttpPolicycap. - Brand
- Venture branding for mail templates (issue #12). Defaults are text-only: factory-zero orange accent, no logo, no footer line.
- Calibration
Point - The cheap adapter’s confidence and margin on one compared question,
and how it went — the evidence a
Thresholdsis checked against. Only the cheap side is kept: its confidence is what routing reads, and it is not comparable with the expensive one’s. - Call
Record - One classifier call as the ledger receives it.
- Captcha
Binding - What a captcha adapter is actually bound to (issue #133). The harness
reads this at build time to decide whether a production venture’s
HumanFormroutes can really be verified — providing the port is not the same as configuring it. - Catalog
Entry - One declaration, and the module that owns the table.
- Charge
- A created charge/payment-intent and its status as Stripe reported it.
- Checkout
Request - A one-time hosted checkout (Stripe Checkout in
paymentmode). - Checkout
Session - The hosted page to send the browser to, and the session id to reconcile on.
- Classifier
Profile - What a caller can learn about the adapter answering, short of its
identity: the family its
confidencecomes from, and how muchstateit will carry before it truncates. - Column
- A column of a
View::Table. - Completion
- A completed completion: the text, the model that answered (a provider identifier, for the log line), and the token usage.
- Config
Error - Accumulates every configuration problem so
Harness::buildcan report them together instead of one at a time. - Connect
Account Link - The Connect account id (persist it) and the hosted onboarding URL.
- Connect
Account Link Request - Onboards a Connect account (a coach) and returns a hosted onboarding link.
- Consumed
- A successful
consume: the amount was counted. - Corpus
Item - One labelled corpus item: a state, the questions asked of it in one batch, and the gold answer for whichever ids have one (a missing id is ungraded).
- Cost
- The pico-USD cost of one call: a
u64, saturating near $18.4 million, which no single classification spends. - Credential
- The API credential the destination’s tracker expects — the customer
company’s token, decrypted from
cratefield-secretsimmediately before the call and never stored anywhere else. - Custom
Hostname - A hostname as the provider sees it: its id, its state, its certificate and the DNS records the customer must publish.
- Decision
- Disagreement
- One question the two adapters answered differently. Values only, never the state: a report is safe to paste into a ticket.
- Dispute
- A dispute against one payment (issue #602’s shape).
payment_refis the idRefundRequest::payment_reftakes for the same provider (a Stripe payment-intent, a Polar order), so a venture can tie the dispute to what it sold;charge_refis the provider’s underlying charge or payment id. - Dispute
List Request - Which disputes
Payments::list_disputesreturns. - Dispute
Page - One page of disputes, newest first, and the cursor for the next page.
- Drain
Options - How many items a
drain_withinmay process in one tick, under what lease, and what one item costs the budget. - Drain
Report - What one
drain_withinpass did. - Embeddings
- One answered embedding request: one vector per input text, in input order, plus the model that answered and the input tokens it billed.
- Empty
Config - A configuration that always returns
None(tests, offline builds). - Event
Bus - Registry of handlers, built once by
Harness::buildfrom every module’sevents(). Cheap to clone (twoArcs). - Exact
Vector Index - The native, in-process
VectorIndex: exact (brute-force) cosine ranking over an in-memory map — the true top-k, ties broken by id ascending, so the same corpus and query always answer in the same order. For development, tests, and small single-process corpora: data is not persisted, and a restart starts empty. - Exhausted
- A refused
consume: the allowance could not carry the amount, so nothing was counted and no work may proceed. An amount larger than the whole allowance is refused as exhausted from the start — on an empty meter,usedis0. - Filed
- The result of a file that the tracker accepted: its id in the external
tracker (persist it —
Tracker::statusis keyed by it) and the ticket’s human-readable URL, where the tracker has one. - Form
- A form (
application/x-www-form-urlencoded) extractor whose rejections are problem+json with the same shape asJson’s: body reads fail through the shared 413 slug (the size limit), everything else is a 400 validation problem. Needed for cross-siteform_postcallbacks (issue #46). - Github
- GitHub’s scheme (
X-Hub-Signature-256), the shape GitHub App and repository webhook deliveries carry: one header,sha256=<hex>, over the raw body alone. A named scheme so ventures declaring a GitHub delivery do not re-type the equivalentProviderSchemefields. - Gitlab
- GitLab’s scheme: header
X-Gitlab-Tokencarrying the shared secret verbatim. ExactlySharedTokenSchemewith that header fixed. - Harness
- A built harness: immutable after
build(). - Harness
Builder - Builder:
.venture(..),.module(..),.runtime(..),.template(..), then.build(). - Harness
Config - The harness-level keys, parsed once from the environment
Config(issue #3):HARNESS_SECRET(required, ≥ 32 bytes),HARNESS_SECRET_PREVIOUS(optional),ADMIN_TOKEN(optional, ≥ 32 bytes when set — issue #437),ENV(development|staging|production, defaultdevelopment), and the issue #137 key-ring keys:HARNESS_SECRET_REVOKED(optional, comma-separated key ids whose tokens must be refused immediately) andHARNESS_VENTURE(optional label binding tokens to this venture, so one venture’s links cannot verify in another that shares its secret by mistake). - Hmac
Signer - HMAC-SHA256 signer over a
KeyRing(ADR 0006, ADR 0014). - Hostname
Claim - A hostname a customer wants served, and how they will prove they own it.
- Http
Policy - Per-operation outbound bounds, attached to a request as an extension
and resolved by every implementation with
HttpPolicy::of_request. Both fields clamp to the port maxima: a caller may only tighten. - Implicit
Tenant - The resolver a deployment with no control database uses: every
host is the one venture, always
active. - InMemory
Ledger - A
CostLedgerthat keeps every record in memory, oldest first. Process-local — one isolate’s view on Workers — which suits a measurement window and is not a billing system. - Inbound
Message - One inbound message, read out of a verified provider delivery.
- Inbox
- A dedup ledger over the
Databaseport. Construct it with the table the owning module declares (e.g."<module>_inbox"). - Issued
Key - A newly minted key:
tokenis the only time the plaintext exists — show it once, store nothing;prefixis public and safe to display. - Json
- A
Jsonextractor and response whose rejections and serializations are problem+json (architecture section 6). Deserialization failures become a400 validation-failedproblem listing the field. - KeyRing
- A bounded set of token-signing keys with explicit states (issue #137).
- Kind
Agreement - Agreement on one
QuestionKind. - Ledger
Totals - Totals over a set of records.
- Line
Item - One line on a checkout: a name shown to the buyer and its price.
- LocKeys
- Native localisation keys. The strings are looked up in the app’s own catalogue by the operating system, so a notification can be localised without the server knowing the device’s language. Reserved here and mapped by the adapters; rendering is the i18n child’s job.
- MapConfig
- A
Configbacked by a map (tests,fz doctorwith process env). - Member
- A connected participant, identified by the venture after it verified the
upgrade request’s bearer token (through the
Signeror the auth client). ARoomHandleronly ever sees this verified id, never a raw token. - Message
- An outbound mail.
textis always sent alongsidehtml. - Migrations
- The module’s migrations, per dialect.
postgresdiffers fromsqliteonly where the SQL truly differs (ADR 0004). - Module
Config - Typed view over a
Configfor one module: prefixes every key with the module name inSCREAMING_SNAKEand parses values with defaults (issue #3). - Module
Context - Everything a module’s router needs: its declared ports, the typed config, the bus, the templates and the venture identity.
- Module
Surface - One module’s entry in the composed document.
- Money
- An amount in a currency’s minor units (cents), the way Stripe takes and
reports money.
currencyis a lowercase ISO-4217 code ("usd"). - Months
- How many whole months one
Period::Anchoredperiod spans. Must be non-zero; the arithmetic clamps a zero to one. - Noop
Defer - Drops deferred futures with a warning. Used when no runtime defer is available; tests that assert on deferred work supply their own.
- Notification
- One notification, in transport-neutral terms.
datais the custom key-value payload the app reads;collapse_idcoalesces notifications the user has not seen yet. - Outbox
- A durable work queue over the
Databaseport. Construct it with the table the owning module declares (e.g."<module>_outbox"). - Outbox
Record - A leased outbox record handed to a drainer.
- Part
Receipt - One part that was uploaded, as S3 and R2 report it: its number and the
ETagthe store assigned (issue #586). A module collects these fromBlob::upload_partand passes them, in ascending part order, toBlob::complete_multipart. - Payload
- The signed payload:
{ purpose, subject, exp?, kid }. - Pending
Upload - A multipart upload the module started but has not completed or aborted
(issue #586): what
Blob::list_multipart_uploadsreports, so a module can find and abort the ones it abandoned. - Period
Window - A half-open period
[start, end), both instants UTC. - Personal
Data Catalog - Every personal-data declaration in a composition, with the module that made it.
- Personal
Data Set - One table’s worth of personal data, declared by the module that owns it.
- Portal
Session - The hosted portal URL to send the customer to. Short-lived: create one per visit, never store it.
- Portal
Session Request - A hosted customer-portal session (issue #589): the page where a customer
changes plan, updates the payment method, reads invoices and cancels.
customer_refis the provider customer the adapter is configured to name (a provider id, or the venture’s own id where the adapter maps it). - Ports
- The per-request bundle of resolved port implementations plus the typed config the runtime built from environment/secrets.
- Presigned
Put - A presigned upload: the URL to
PUTto, the method, and the headers the client must send exactly — the signature covers each signed header, so a different value is refused by the store (issue #622). - Price
- What one token costs on one adapter, in pico-USD, per side. Pricing is
config, pasted off the vendor’s page through
Price::per_million_tokens. - Price
Sheet - What each adapter costs, wired once where the adapters are wired.
- Problem
- An API error, serialized as
application/problem+json. - Problem
Def - Definition of one problem slug.
- Prompt
- One completion request: the tier asked for, the conversation so far, and what the caller will accept back.
- Provider
Scheme - A provider-specific scheme, configured rather than coded. Entries are separated by commas or spaces, so a provider may send several — for instance during a secret rotation.
- Question
Kind - The id a question is asked under — the key of the map
Classifier::asktakes. A venture asks the same kind of question under the same id, so agreement is measured and routing is decided per id: a classifier reliable on one kind is not therefore reliable on the next. - Quota
- The budget a key spends against, when the limiter knows one (issue
#538). A Workers Rate Limiting binding does not; a D1-backed fixed
window does.
limitis the budget per window,remainingwhat is left of the current one, andresethow long until it turns over — the three numbersrate_limitedputs on theRateLimit-*headers. - Random
Error - Why an entropy draw failed: no key material existed yet, so the message carries only the platform’s own words.
- Redacting
Visitor - A
tracingfield visitor that records(name, redacted value)pairs into a map. Runtimes use it in their formatters; tests use it to prove the redaction rules. - Refund
- A created refund.
- Refund
Request - A refund of a prior payment: the whole amount when
amountisNone, else a partial refund. - Rendered
- A rendered mail, ready for
Message. - Rendered
Surface - A document serialized once, with the strong
ETagclients revalidate against. Built atHarness::buildfor both the public and the admin variant. - Request
Stream - A streamed request body (issue #585). Extracted by a handler on a route
its module declared in
Module::streaming_routes; the router has already put it in the request extensions and emptied the buffered body. - Request
Summary - The per-request span’s fields as plain data, attached to every
response’s extensions by the request-id layer so a runtime with no
tracing dispatcher — Cloudflare — can still log them.
routeis the matched pattern, never the raw path (""when nothing matched). There is noduration_ms: wasm32 has no monotonic clock to measure it with. - Response
Stream - A streamed response body (issue #585).
- RingKey
- One ring entry. Deliberately not
Debug: the ring’s debug view (KeyRing::states) shows ids and states but never key material (issue #135’s scrubbing rule applies to key bytes too). - Routed
- One answer, with who gave it and why.
- Routing
Classifier - Sends each question to the cheap adapter when its kind has earned it
and to the expensive adapter otherwise; see
RoutingPolicy. - Routing
Policy - How
RoutingClassifierdecides. Defaults toRoutingMode::Off: a cheaper adapter is earned by measurement, never assumed. - Routing
Push - Dispatches by
Recipientvariant to the adapter a venture configured for that transport, so venture code holds oneArc<dyn Push>and never matches on the transport itself (ADR 0015). - Routing
Text Model - Dispatches by
Prompt::tierto the adapter a venture configured for that tier, so venture code holds oneArc<dyn TextModel>and never matches on the tier or the vendor itself (ADR 0002). The router lives above the adapters, in core — the same placeRoutingPushdoes, and for the same reason (ADR 0015). - Routing
Tracker - Dispatches by
Destinationvariant to the adapter a venture configured for that tracker, so venture code holds oneArc<dyn Tracker>and never matches on the destination itself. - Row
- One result row: ordered
(column name, value)pairs. - Rows
- A small owned row model. No engine types leak past this point.
- Scheduled
Budget - What one module may spend in one scheduled invocation.
- Scheduled
Limits - The limits one scheduled invocation may spend in total: how long it may
run, and how many subrequest-shaped steps it may make.
Noneis unbounded, which is the only value the native runtime needs —UNBOUNDED. - Scheduled
Split - Divides one invocation’s
ScheduledLimitsacross its modules, in order, with every module’s unspent share rolling forward to the ones after it. - Scope
- Per-request scope, inserted into extensions by the request-id layer
(issue #2). Handlers receive it through the
Scopeextractor; there is no ambient “current request”. - Scoped
Actors - Wraps an
Actorsso a module only reaches the kinds it declared inModule::actor_kinds, the actor equivalent of the table-ownership rule. When the module has aClockwired, every call is also bounded byACTOR_CALL_TIMEOUT; with no clock there is nothing to measure the wait with, so the call is made straight through and the host still serializes it. The harness applies this inPorts::view_for. - Scoped
Blob - Wraps a
Blobso every key is prefixed with<module>/and no key can escape it. The harness applies this inPorts::view_for, so a module sees a store scoped to itself — the blob equivalent of the table-ownership check. - Send
Cooldown - A cooldown ledger over the
Databaseport. Construct it with the table the owning module declares (e.g."<module>_send_cooldown"); the owning module shipscreate_table_sqlas a migration. - Shadow
Classifier - Serves the expensive adapter’s answers, unchanged, and asks the cheap one the same questions to measure agreement. The cheap adapter cannot change or fail a result: its errors are logged, recorded and counted as skipped.
- Shared
Token Scheme - A shared-token scheme: the header carries the secret itself, in the
clear, and a value equal to the secret is what proves the delivery —
there is no signature over the body, so
bodyis ignored entirely. The comparison is the verifier’s constant-time one (the same helper the HMAC path uses); a missing, empty or non-UTF-8 token refuses. Nothing here is bound to time, so a captured token replays: claim each delivery’s event id through theInboxledger. - Sidecar
Mount - One mounted sidecar.
- Sidecar
Mounts - The mount table, parsed from configuration.
- Signed
Delivery - What a
SignatureSchemeread out of one delivery: the bytes the provider signed, the candidate signatures to compare, the timestamp the replay tolerance runs on. - Slugs
- Every slug core emits. Keep sorted by status.
- SqlMigration
- One migration step, embedded with
include_str!fromcrates/<module>/migrations/<dialect>/NNNN_name.sql(issue #8). - Statement
- A rendered SQL statement:
(sql, values)with?placeholders, produced by rendering a sea-query query for a dialect. Modules build queries with sea-query and render through the helpers on this type (or let adapters do it); adapters bindvaluespositionally. - Status
Only - Marks a request whose caller wants only the status line. An
implementation that honours it returns a response with no body and no
body-describing headers (
Content-Length,Content-Encoding,Transfer-Encoding), because there is no body here to describe. - Status
Update - A ticket-state change a tracker reported on its inbound status webhook:
the same shape
Tracker::statusanswers with, pushed instead of pulled.Ok(None)from a parse means a verified event that carries no status change (a comment, a ping) — not an error. - Step
Usage - The usage of one model call inside a tool loop (issue #665): the same
three token fields
Completionreports, plus how many tool calls that step’s completion asked for. - Stream
Route - One route a module serves in streaming mode (issue #585).
pathis relative to the module’s/v1/<name>mount and uses axum’s pattern syntax: a literal segment,{param}for exactly one segment, or{*rest}for the remaining one-or-more (/upload,/files/{id},/files/{*rest}). - Stripe
Style - Stripe’s scheme, the shape
adapter-stripeverifies: one header oft=<unix>,v1=<hex>[,v1=<hex>…], payload{t}.{body}. The header name is configurable because other providers use the same layout under their own name. - Subject
- The person a verified credential speaks for.
- Subject
Via - One hop to the subject, through a table that holds the id requests are made with.
- Subscription
- A recurring subscription as the provider reports it (issue #589).
customer_refnames the customer the way the adapter is configured to name customers (a provider id, or the venture’s own id where the adapter maps it); the fields mirror what a billing module reconciles against, never an entitlement. - Subscription
Checkout Request - A recurring hosted checkout (Stripe Checkout in
subscriptionmode) against a Stripe Price the venture configured (e.g.$15/mowith a trial). - Surface
- What a module declares from
Module::surface. - Surface
Document - The document
GET /__surfaceserves: composed atHarness::build, one entry per module in mount order, modules with an empty surface omitted. - Svix
- Svix’s scheme — the one Resend, Clerk and a growing list of providers
sign with. Headers
svix-id/svix-timestamp/svix-signature(thewebhook-*aliases are accepted too); payload{id}.{timestamp}.{body}; signature header a space-separated list of<version>,<base64>pairs of which onlyv1is read — how an endpoint survives a secret rotation. - System
Clock - Real wall clock (
timecrate). Its timeout runs futures to completion — tests that need a real timeout supply their own clock. - Template
Registry - Immutable registry: venture overrides are inserted after module defaults
at
Harness::build, so they win on id collision. - Tenant
- The tenant a request belongs to. Immutable, and built only by core’s resolution layer from a registry row — never from a header, a path segment, or module code.
- Tenant
Conn - A database handle bound to the request’s tenant.
- Tenant
Id - A tenant’s key in the control database’s registry.
- Tenant
Summary - One row of the registry, as this port reports it.
- Thresholds
- When the cheap adapter’s answer is good enough to serve: at least
min_confidenceand a top-two margin of at leastmin_margin, under theCalibrationthese numbers were tuned for. - Ticket
Comment - A note added to an existing ticket — e.g. linking a duplicate report to
the ticket it duplicates. Adapters map the fields their tracker has and
document what they drop;
body_markdownis the only content every tracker takes. - Ticket
Draft - A ticket to file, in tracker-neutral terms: every adapter maps the
fields its protocol has and documents what it drops.
titleandbody_markdownare the only content every tracker takes;labelsandenvironmentare requests an adapter may flatten into the body, a label list, or nothing. - Ticket
Status - A ticket’s current state and, where the tracker renders one, its URL.
- Token
Policy - A per-purpose lifetime ceiling (ADR 0014, issue #137).
- Tokens
- The tokens one call spent, and where the count came from.
- Tool
Budget - How far a tool loop may run (issue #665): a hard cap on model calls, and an optional cap on the tokens those calls may spend.
- Tool
Call - One tool call the model asked for: which call it is, which tool, and the
arguments the model produced (issue #665). The arguments are exactly
what the model sent —
run_tool_loopvalidates them against the tool’s schema before any executor sees them. - Tool
Loop Outcome - What a finished tool loop produced (issue #665).
- Tool
Result - The result of running one
ToolCall, fed back to the model as context (issue #665). A tool-level failure is aToolResult::error, not a failed loop: the model is given the error text and may try again. - Tool
Spec - A tool the model is offered: a name, the instruction a model reads when deciding whether to call it, and the JSON Schema of the arguments object the call must carry (issue #665).
- Transfer
Charge - A destination charge with an application fee: the buyer is charged
amount,application_feeis kept by the platform, and the remainder is transferred todestination_account(the coach’s Connect account). - Turn
- One message of the conversation a
Promptcarries. - UiContext
- What a UI renderer gets from the harness (ADR 0010). Built by
Harness::routerfor every router it assembles. - Ulid
IdGen - Real ULID generator (monotonic per process).
- Unconfigured
- The verifier a deployment gets when it asked for one from the environment and the environment did not have it.
- Upload
Id - Identifies one multipart upload in flight (issue #586). Opaque: an
adapter mints it in
Blob::create_multipartand a module only ever hands it back to the other multipart methods. - Usage
- A usage-meter table over the
Databaseport: durable per(subject, meter, period)counters. Construct it with the table the module declares (e.g."<module>_usage") and shipcreate_table_sqlas its migration.subjectis who the allowance belongs to;meteris which resource is counted, so one table holds every meter. - Usage
Report - A metered usage amount to report to the billing provider (Stripe Billing
Meters).
meter_event_namenames a meter the venture configured;customer_refis the provider customer id the meter maps the event to;valueis the amount counted, in the meter’s own unit;identifieris the caller-chosen exactly-once key;timestampis when the usage happened. - Usage
Reported - The outcome of a
report_usage: the identifier that was reported and whether the provider said it had already been reported. A duplicate is success, not failure — the window was counted exactly once — so a caller completes the work either way. - Validation
- One DNS record the customer has to publish for validation — a
TXTpre-validation record (DCV), or aCNAMEpointing the name here. - Vector
Filter - Equality on metadata: a record matches when its metadata holds every
key with an equal value; values compare as JSON, so
"1"and1differ. The default matches all. Hosted indexes may filter only on keys pre-registered as metadata indexes; the exact index filters on all. - Vector
Match - One nearest neighbour: the record’s id, its cosine similarity to the query (higher is closer), and its metadata.
- Vector
Namespace - The search space one call sees: one tenant’s slice of the index.
- Vector
Record - One stored vector: its id, its embedding, and the metadata a filter can
select on — carried back on every
VectorMatch. - Venture
- Identity and CORS configuration for the venture this harness serves.
- Venture
Surface - The venture identity a renderer needs.
- Vercel
- Vercel’s scheme: header
x-vercel-signature, a lowercase hex HMAC-SHA1 over the raw body — no prefix, no timestamp header. The digest is SHA-1 but the construction is HMAC, so SHA-1’s collisions do not apply (see the module docs); with no timestamp, replay defence is theInboxdedup ledger’s job. - Verdict
- A captcha verification verdict.
ok: falsewith areasonfrom the provider’serror-codes; transport-level unavailability surfaces asok: false, reason: "unavailable"unless the adapter is configured fail-open (staging only). - Webhook
Event - A webhook event the adapter has verified (signature + timestamp) before
returning.
kindis Stripe’s event type ("checkout.session.completed");datais the event’sdata.objectfor the module to interpret. - Webhook
Verifier - The signature core every scheme shares: compute what a matching delivery must carry — an HMAC (SHA-256 or SHA-1) over the scheme’s signed payload, or, for a token scheme, the secret itself — compare it against every candidate in constant time with no early exit, and hold the delivery to its timestamp.
- Write
Guards - What the composed modules demand of the runtime, module by module.
Enums§
- Actor
Error - Actor failures.
- Answer
Value - The decided value of one
Question, shaped to match it. - ApiKey
Error - Why a key operation failed; in every variant, nothing was written.
- ApiKey
Mode - Which environment a key belongs to: sandbox or production money.
- Audience
- Who an action is for. Drives the public/admin split of
/__surfaceand, in the renderer, which pages need the admin session. - Auth
Error - Why a caller could not be identified.
- Blob
Error - Blob store failures.
- Calibration
- Which family of numbers an adapter’s probabilities come from.
- Call
Outcome - How a recorded call ended. A failed call is recorded too: a cheap adapter that fails often is not cheap.
- Call
Role - Which side of a routing decision a recorded call was on.
- Caller
- Who the request is from.
- Capability
- Something a
TextModeladapter may or may not be able to do beyond a plain completion. A port whose shape grows over time needs a way for the router to ask “can the model behind this tier actually do this” before a caller wastes a request on one that cannot. - Captcha
Error - Certificate
Status - The edge certificate’s state — separate from
ProviderStatus, since a hostname can be validated while its certificate is still issuing. - Classifier
Error - Classification failures.
- Consumption
- The outcome of one
consume: matched on directly. - Control
Level - How severe a forwarded control event is (issue #441).
- Custom
Hostname Error - Custom-hostname failures. Every variant that carries the provider’s own
text is scrubbed in
Display(issue #235), the same wayMailError’s is;Debugstays raw for tests. - Data
Kind - The category a row falls into, in the vocabulary a privacy page and an App Store questionnaire both use.
- DbError
- Database failures, sanitized for logs and problem details.
- Destination
- Where a ticket is filed. One variant per supported tracker, because the
eleven do not share a shape: a GitHub destination is an owner and repo, a
webhook is a URL, and Intercom and
HubSpotaddress nothing but the credential — the workspace/portal the token belongs to is the destination, so those variants carry no fields at all. - Digest
- The hash an HMAC scheme runs on. SHA-256 everywhere it is not otherwise
named; SHA-1 only where a provider signs with it (
Vercel). - Dispatch
Error - Disposition
- What erasure does to these rows.
- Dispute
Phase - The coarse dispute lifecycle a venture acts on: flag an account while a
dispute is
Open, restore it when the dispute isWonorClosedwithout a chargeback, and act on aLostone (revoke what the payment funded). - Dispute
Status - Where a dispute (a chargeback, or the inquiry before one) stands, in the
shape issue #602 set out, plus the two states a Merchant of Record reports
around it. The provider’s own spelling is kept on
Dispute::provider_status;DisputeStatus::phaseis the coarse lifecycle a venture reacts to. - DnsRecord
Type - The DNS record type a
Validationnames. - Embed
Error - Embedding failures.
EmbedError::Providercarries the provider’s own words, so it is scrubbed inDisplay(issue #235);Debugstays raw. - Erasure
Step - One step of a tenant’s erasure, in the order
docs/TENANT-ONBOARDING.md§2 gives it. - Ground
Truth - Which adapter the ground truth sided with when the two disagreed.
- Hostname
Refusal - Why a hostname was refused before it ever reached the provider.
- Http
Error - Image
Limit - Which image bound a
Promptcrossed (issue #628): the count, one image’s encoded size, or the whole prompt’s. Carries only sizes and indices — never user content — so it is safe in a log line as-is. - Image
Media Type - The media type of an image a
Partcarries (issue #628): the closed set the providers accept, so a caller picks one rather than handing the provider a bare string to validate.#[non_exhaustive], so amatchcarries a wildcard. - Inbound
Mail Error - An inbound-mail failure.
Signaturecarries no provider text —WebhookVerifier::verifyanswers a boolean, fail closed with no detail to leak — andMalformedscrubs the adapter’s own description inDisplay, because a payload can quote the message and its sender. - Inbound
Status Error - A status-webhook failure. The
Signaturevariant carries no provider text:WebhookVerifier::verifyanswers a boolean — fail closed with no detail to leak — and the port keeps that property rather than inventing prose a log could leak.Malformedcarries the adapter’s own description, scrubbed inDisplaythe wayTrackerError::Rejectedscrubs the tracker’s words. - KeyState
- A key’s role in the ring (ADR 0014, issue #137).
- Kid
- Which key in the
crate::KeyRinga token was signed with. Tokens name their key so rotation never breaks links in flight. - KvError
- Mail
Error - Mailer failures, mapped by the adapter from provider responses.
- Model
Tier - Which class of model a completion asks for — a tier, never a vendor or a model name. A venture maps each tier onto a provider in its own wiring, and can move drafting from one vendor to another without touching a module.
- Origin
Error - Why a string is not an origin this harness will name.
- Outcome
- What the browser should do with a successful response.
- Part
- One piece of a
Turn: text, or an image with its media type and raw bytes (issue #628). A parts-bearing turn carries them in order;#[non_exhaustive], so a part is built withPart::textandPart::imagerather than a struct literal. - Payments
Error - Payment failures.
NotConfiguredlets a venture build and run without Stripe (the port reports it rather than erroring); the rest map an upstream failure.SignatureInvalidis separated so a webhook handler answers400and never processes an unverified event. - Period
- How a period is cut. Every variant converts to UTC first, so an instant in any offset names the same window as its UTC spelling.
- Platform
- The transport a
Recipientis reached over, which is not a statement about the device: a UnifiedPush endpoint isPlatform::Webon an Android phone (ADR 0015). - Port
- Every port a module can declare in
requires()/optional()(architecture section 4). - Priority
- How urgently the notification should be delivered. Maps to APNs priority
10(deliver now, may wake the device) and5(deliver to save power); toandroid.priorityHIGH/NORMAL; to the Web PushUrgencyheaderhigh/normal. - Processed
- What the handler made of one record.
- Provider
Status - The hostname’s own state at the provider.
- Push
Error - Push failures.
Unregisteredis separated because the caller must act on it — the recipient is dead and should be pruned — where the others are transient or a bad request. - Push
Outcome - The result of a send that the provider accepted.
- Question
- One question asked of
state. Three shapes, because a classifier is asked three kinds of thing: pick one of a named set (Question::Choice), place on an ordered scale (Question::Score), or answer yes or no (Question::Noul). - Rate
Limit - Outcome of consulting the limiter for one request.
- Rate
Limit Error - Rate
Limit Failure - What a limiter transport error means for the request (issue #133). Every call site picks one deliberately; it used to be an implicit “allow” buried in each module’s copy of the limiter loop.
- Realtime
Error - Realtime failures.
- Recipient
- Where a notification is sent. One variant per push transport, because the three do not share a shape: APNs and FCM take an opaque token, Web Push takes a subscription of three parts (RFC 8291).
- Resolution
- What a deployment’s registry says about a host.
- Role
- Who is speaking in a
Turn. A prompt is a conversation, and a provider needs to know which side each part came from. - Route
Policy - How a request to a declared route proves it is legitimate.
- Route
Reason - Why a question went where it went.
- Routing
Error - Refusals from
RoutingClassifier::new: a policy that cannot mean what it says for these adapters is rejected at wiring time, not at the first question. - Routing
Mode - Whether routing happens at all.
- Send
Outcome - Result of a send attempt.
- Severity
- How urgently the ticket should be attended to. Adapters map this onto
whatever their tracker has — a GitHub label, a Jira priority, a Slack
Notification-Alert— and document what they drop. - Signature
Encoding - How a provider encodes signature bytes in its header.
- Signature
Error - Failures surfaced by
verifybeyond “the token is simply invalid”, which is reported asNone. - Signature
Verification - Which verifier proves a module’s
RoutePolicy::Signaturedeliveries (issue #533): thePaymentsport — the default every existing module was built against — or the corewebhook_signatureHMAC scheme keyed by the module’s own config secret. The production gate demands whichever the module named, never both and never neither. - Signer
Error - Errors from constructing an
HmacSigneror aKeyRing. - Stream
Error - Why a
RequestStreamended early. - Subscription
Status - Where a recurring subscription stands (issue #589), in the provider’s own
vocabulary — Stripe’s subscription statuses today, plus
Otherfor one this version does not know. This is the provider’s word, not an entitlement: a billing module reads it and decides what access it grants (ADR 0025). - Template
Error - Tenancy
- Which of the two tenancy shapes served a request.
- Tenant
DbError - Why a tenant’s database could not be handed over. Deliberately carries the tenant id and nothing else — no DSN, no driver message.
- Tenant
Lifecycle Error - Why a registry write did not happen.
- Tenant
Status - A tenant database’s reconciliation status.
- Text
Model Error - Completion failures.
- Ticket
State - A ticket’s state as the tracker last reported it. Adapters map their
tracker’s workflow states onto these five, and onto
TicketState::Unknownanything they cannot name — they never invent a sixth state, and a caller that needs the tracker’s own raw state name asks the tracker’s API byexternal_id. - Token
Source - Where a token count came from.
- Tool
Choice - How the model should choose among a prompt’s
Prompt::tools: freely, not at all, mandatorily, or pinned to one named tool (issue #665). - Tool
Loop Error - Why a tool loop stopped without a usable answer (issue #665).
- Tracker
Error - Tracker failures.
- Validation
Method - How the provider proves the customer controls the hostname: over HTTP
(the provider fetches a token) or a
TXTrecord the customer publishes. Cloudflare forSaaSdefaults to HTTP. - Vector
Index Error - Vector-index failures. Provider-text variants are scrubbed in
Display(issue #235);Debugstays raw for tests. - Venture
Env - Deployment environment. Mirrors the
ENVconfig key;Productiondrives the mandatory-captcha rule (architecture section 11). - View
- How actions compose into something to render.
Constants§
- ABOUT_
BLANK - The
typeURI of a problem that has no URI of its own to name (RFC 9457 §4.2.1): a venture with no public URL, or a response rendered outside any venture’s context. The slug stays in the body’s title and in logs; callers branch on it where one exists. - ACTOR_
CALL_ TIMEOUT - How long one
Actors::callmay take before the caller gives up. The host keeps serializing the actor; the caller just stops waiting. - ALLOW_
UNLIMITED_ PUBLIC_ ROUTES - Config key holding an operator’s explicit, recorded acceptance that
this deployment serves its public writes and admin routes with no
resolved rate limiter (issue #437). Same contract as
ALLOW_UNPROTECTED_WRITES: the value is the reason, and a blank one does not count; the boot gate records it once, wherever the operator ships logs. It exists because the limiter was opt-in — a runtime that failed to resolve its binding degraded to no limiter and served — and because the escape from that must be as deliberate as the gap it accepts. Resolve the binding and delete the key. - ALLOW_
UNPROTECTED_ WRITES - Config key holding an operator’s explicit, recorded acceptance that this deployment serves guarded routes it cannot fully protect (issue #143).
- CARD_
DATA - Card-data fragments the harness never stores. With a normal Stripe
integration the card details go straight to Stripe (Checkout, Elements, the
SDKs) and never reach a backend, so a column or secret shaped like a card
number, verification code or full expiry is a mistake. Deliberately the
specific forms and not bare
pan,trackorexpiry, which collide with legitimate columns — an audiopan, a musictrack, asession_expiry(issue #44). - CONFIRM_
TOKEN_ MAX_ TTL_ SECS - Seven days: the ADR 0006 confirmation default, expressed as a policy ceiling rather than a caller habit.
- DEFAULT_
MAX_ STATE_ CHARS - Chars of
statea conservative adapter will send before it truncates: roughly 4 chars per token against the 32k-token window Workers AI documents, which leaves room in that window for the questions and the answer. An adapter whose provider has a different budget reports its own limit throughClassifierProfile::max_state_chars— this is the default, not a law. - DEFAULT_
MAX_ TOKENS - The token ceiling a
Promptstarts with: enough for a drafted reply, small enough that a forgotten.max_tokens(..)cannot turn into a run away bill. Explicit in the type so “how long can the answer get” is a field a caller can read, not an adapter’s private default. - DEFAULT_
PRESIGN_ TTL - The presign lifetime a caller gets when it does not choose one: one hour — long enough for a browser to fetch or upload, short enough that a leaked URL ages out (issue #622).
- DEFAULT_
RESPONSE_ TIMEOUT - Deadline applied to an outbound call that asks for none. Longer than the strictest in-tree self-bound (Turnstile’s 5s verify), shorter than anything that could pin a request.
- DEFAULT_
TOKEN_ MAX_ TTL_ SECS - The default ceiling for any purpose not listed explicitly. An unknown purpose can never mint a non-expiring token by omission.
- DEFAULT_
TOLERANCE_ SECS - How far a delivery’s timestamp may be from now, in seconds, either way —
Svix’s and Stripe’s own tolerance, and the
WebhookVerifierdefault. The signature stays valid forever; the timestamp is what stops replays. - FORMULA_
PREFIXES - Characters that make a cell a formula when it starts with one of them.
- GATEWAY_
ADMIN_ PURPOSE - The purpose the host mints only after its own
require_adminhas passed for an admin path (issue #131). It is what lets a sidecar re-materialize its own admin token: a token proving nothing more than “this came through the host” must not open the admin plane, or any captured forwarded stamp would be an admin credential for its whole lifetime. - GATEWAY_
PURPOSE - The token purpose bound into the gateway MAC. A token minted for any other purpose — a confirm link, an admin session — cannot pass verification, and vice versa (issue #137’s rule, applied to #131).
- GATEWAY_
TOKEN_ TTL_ SECS - Gateway token lifetime: a forwarded request completes in one hop, so a minute is generous. Short TTLs shrink the replay window a stolen token buys an attacker (issue #131).
- HARNESS_
API - Contract version shared by core and every module.
Harness::buildrejects modules whoseharness_apidiffers. Bumped only on breaking contract changes;cratefield-core’s major follows it. - HARNESS_
ONE_ WORKER - Truthy declares “this venture deploys as one Worker”: mounting a sidecar
then contradicts the shape, and
SidecarMounts::from_configrejects the mount table rather than starting a deployment that cannot reach it (issue #131). - HARNESS_
SIDECARS - Config key holding the mount table, a JSON object of
{"<module name>": "<service binding>"}. - HINT_
KEYWORDS - The
x-cf-*extension keywords the renderer understands on a field schema. Anything else underx-cf-is ignored, never an error, so a module can target a newer renderer than the one that serves it. - IMPLICIT_
TENANT - The registry id a deployment without a registry resolves to.
- MAX_
ACTOR_ KEY_ BYTES - The longest an actor key or a storage key may be. Both are bounded by the
same constant, the way they are addressed (
"<kind>:<key>"). - MAX_
ACTOR_ KIND_ BYTES - The longest an actor kind may be. Kind names are
[a-z0-9_-], so"<kind>:<key>"splits unambiguously. - MAX_
ACTOR_ MESSAGE_ BYTES - Hard ceiling on one message sent to an actor.
- MAX_
ACTOR_ REPLY_ BYTES - Hard ceiling on one reply an actor returns.
- MAX_
ACTOR_ VALUE_ BYTES - Hard ceiling on one stored value. An actor holds small coordination
state, not a store: past this bound the state belongs in the database,
reached through
Ports::db. - MAX_
BLOB_ BYTES - Hard ceiling on one stored object (issue #136). The port exists for
small media — a coach’s voice clip, an avatar — and every caller
reaches it through
ScopedBlobor an adapter that enforces this bound before allocating or writing. Ten MiB is well past any legit clip at conversational bitrates and far below what threatens a self-hosted process or an isolate that buffers the bytes. - MAX_
BODY_ BYTES - Default request body limit for
/v1/*JSON endpoints. - MAX_
CONCURRENT_ REQUESTS - Per-process budget for concurrent outbound requests. The native runtime shares one connection pool across the tenant it serves; this is what stops one request’s fan-out (say a cron fanning out emails) from monopolising the pool and the response-buffer memory behind it.
- MAX_
EMAIL_ BYTES - The maximum accepted address length in bytes (RFC 5321 “forward-path”).
- MAX_
EXPORT_ ROWS - Maximum rows one admin-export page may carry (issue #136). Exports are
paged (
limit/offsetquery params) and clamped to this: an unboundedSELECT *of a subscriber table into one in-memory String is an outage a hostile sign-up wave can trigger, and the bound is what a Worker isolate budgets for one response.x-cf-export-more: truetells the operator a next page exists. - MAX_
IMAGE_ ENCODED_ BYTES - The most base64 bytes one image may encode to (issue #628): 3.75 MiB,
the vendors’ per-image ceiling.
encoded_image_lengives a raw image’s encoded length;Prompt::check_imagesrefuses any over it. - MAX_
KID_ NAME - The longest accepted
Kid::Namedwire name. Key ids ride inside every token; the bound keeps a hostile payload from claiming arbitrary storage. - MAX_
LARGE_ BLOB_ BYTES - The harness-wide absolute cap on the large-object limit a module may declare (issue #586). Five GiB is a harness-chosen ceiling — large enough to stream a video for a person who uploaded one, and well under R2’s ~5 TiB single-object maximum — so no module can declare its way past a bound the harness is willing to enforce.
- MAX_
LIST_ LIMIT - The most objects one
Blob::listcall may return (issue #586): R2’s list cap.ScopedBlobclamps a caller’slimitinto1 ..= MAX_LIST_LIMITbefore any adapter sees it. - MAX_
LOCAL_ BYTES - The maximum local-part length in bytes (RFC 5321).
- MAX_
MULTIPART_ PARTS - The most parts one multipart upload may have (issue #586): S3’s and
R2’s own limit.
Blob::complete_multipartrefuses more, and part numbers are1 ..= MAX_MULTIPART_PARTS. - MAX_
NAMESPACE_ BYTES - The longest namespace name accepted, in bytes: Cloudflare Vectorize’s limit, and so the port’s.
- MAX_
PRESIGN_ TTL - The longest presign lifetime a store accepts: seven days, the S3 maximum.
ScopedBlobrefuses a longer one before any adapter sees it (issue #622). - MAX_
PROMPT_ IMAGES - The most images one
Promptmay carry (issue #628): four, inside the vendors’ own per-request range.Prompt::check_imagesrefuses more. - MAX_
PROMPT_ IMAGE_ ENCODED_ BYTES - The most base64 bytes all of a prompt’s images may encode to
together (issue #628): 4 MiB, the same
MAX_RESPONSE_BYTESceiling theHttpClientport puts on a response body.Prompt::check_imagesrefuses a total over it. - MAX_
RESPONSE_ BYTES - Hard ceiling on a response body this port may return: an adapter’s
largest legitimate upstream reply (JWKS documents, Stripe objects,
LinkedIn
peoplepayloads) is orders of magnitude below it, and it is far below anything that threatens isolate memory. Callers may lower it per operation, never raise it. - MAX_
RESPONSE_ TIMEOUT - Ceiling on a caller-supplied deadline. A 30 s Worker request cannot responsibly spend more than half of it waiting on one upstream.
- MAX_
SIDECAR_ ACTIONS - Largest action list a merged sidecar surface may declare (issue #131).
- MAX_
SIDECAR_ SURFACE_ BYTES - Largest sidecar surface document the host will merge (issue #131). A whole module’s declaration is a few kilobytes; anything approaching this cap is hostile or accidental, and parsing it costs the host.
- MAX_
SIDECAR_ VIEWS - Largest view list a merged sidecar surface may declare (issue #131).
- MIN_
MULTIPART_ PART_ BYTES - The smallest a non-final multipart part may be (issue #586): R2’s
rule. Every part except the last one listed must be at least this,
and R2 additionally requires all non-final parts to be the same size;
ScopedBlobleaves that to the adapter, which alone sees the parts as they are written. - MIN_
SECRET_ BYTES - Minimum secret length.
HARNESS_SECRETmust be at least 32 bytes. - SIDECAR_
GATEWAY_ SECRET - Shared secret between the host and a sidecar that enforces the gateway
(issue #131). The host mints short-lived per-request tokens with it; the
sidecar verifies them on
/v1/*and/__surface. It is its own secret —HARNESS_SECRETstays venture-local (ADR 0009) — and must appear on both ends of a mounted pair. - SIDECAR_
REQUIRE_ GATEWAY - Sidecar-side switch: truthy means every
/v1/*and/__surfacerequest must carry a valid gateway token minted withSIDECAR_GATEWAY_SECRET. Requiring it without the secret is a configuration error and fails closed, not open (issue #131). - SLUGS
- STATUS_
TOKEN_ MAX_ TTL_ SECS - The status-token policy (issue #137): a waitlist position is not secret, but a URL that never expires is a URL forever in logs, forwards and bookmarks. Ninety days, renewed on every confirm hit.
- SURFACE_
API - Contract version of the surface document, independent of
HARNESS_API: a renderer or the control plane checks it before reading the document. - UNSUBSCRIBE_
ACTION - The one action with a deliberately non-expiring ceiling, justified in
ADR 0014: unsubscribe must always be reachable, and the longevity the
signed link used to buy from the global key ring is now also carried
by the per-subscription opaque token in
module-email-signup, which outlives any key rotation because it lives in the subscriber’s row. - X_
HARNESS_ API - Contract version stamped on every harness response, checked by the host on every forwarded response. Stamping beats a cold-start handshake because an isolate outlives a sidecar redeploy (ADR 0009).
- X_
HARNESS_ GATEWAY - Gateway token header, minted by the host per forwarded request and
verified by a sidecar that set
SIDECAR_REQUIRE_GATEWAY(issue #131). - X_
HARNESS_ MODULE - Module name stamped alongside
X_HARNESS_API. - X_
REQUEST_ ID x-request-id: accepted from the client when it matches^[A-Za-z0-9_-]{8,128}$, otherwise generated as a ULID. Always set on the response (architecture section 6).
Traits§
- Actor
Context - The operations an
ActorHandlerperforms on its actor while handling a message or an alarm. Writes are staged and committed together by therun_actor_message/run_actor_alarmrunners. - Actor
Handler - The protocol for one kind of actor. A module implements it and registers
it with
HarnessBuilder::actor; the host owns the serialization and calls these. - Actor
Store - The backing store for one actor instance. An adapter implements this
per instance; core owns the atomicity, so an implementation need only
make
commitapply its whole set or none of it. - Actors
- An actor host: it owns serialization and durable storage for every actor
instance on the runtime. Implemented by the runtime adapters (a Durable
Object namespace on Cloudflare, an in-process registry natively, a fake
in tests); a module only ever reaches a
ScopedActors. - Auth
- Turns a request’s headers into the caller they speak for.
- Blob
- A blob store. Keys are module-prefixed; the harness wraps this in a
ScopedBlobper module so a module cannot name another’s objects. - Captcha
- Classifier
- Answers a set of typed questions about a
state, over whichever classifier the venture wired. The sibling ofTextModel: a module asks “which of these is it, and how sure are you” and holdsArc<dyn Classifier>without learning who answered. - Clock
- Config
- Read-only key/value configuration, resolved per runtime from environment
variables and secrets (Workers
Env) or the process environment. - Cost
Ledger - Sinks what classifier calls cost.
- Custom
Hostnames - Claims, reads and releases custom hostnames at whichever provider the venture wired.
- Database
- Execute statements against the venture database. Implementations: D1 (Workers), rusqlite (tests, self-hosted), Postgres (phase 3).
- Defer
- Dispatcher
- Embedder
- Embeds texts, over whichever provider the venture wired: exactly one vector per input text, in input order, so a caller can zip them.
- Http
Client - IdGen
- Inbound
Mail Source - A vendor’s inbound-mail webhook, implemented per vendor by adapter
crates: how to verify a delivery’s signature and how to read a message
out of the verified body. The inbound sibling of
StatusWebhookand the mirror ofMailer— it hands a parsedInboundMessageto a module, whereMailertakes one from it. - KeyValue
- Mailer
- Module
- A Factory Zero module. Object-safe; composed as
Arc<dyn Module>. - Payments
- Moves money for a venture. Stripe today; the trait names only Stripe identifiers and hosted URLs, never card data.
- Push
- Sends notifications to a device, over whichever transport the
Recipientnames. An adapter serves one transport and returnsPushError::unsupported_recipientfor the rest;RoutingPushfans a mixed set of recipients out across the adapters a venture configured. - Random
Bytes - The CSPRNG
ApiKeysdraws key material from. Injected like every environment effect (ADR 0002) — core carries no entropy source, and the deployment (or a test) supplies its own. An app crate declaringgetrandom(the workspace-wide leaf pattern) writes: - Rate
Limiter - Realtime
- Poke a room from outside a socket — a module’s HTTP handler (e.g. an admin
ends a session) or a cron. The socket lifecycle itself is the runtime’s job
(it calls
RoomHandler); this is the part a module holds viaPorts. - Resolve
Tenant - How a deployment turns a request’s host into a tenant.
- Room
Context - The operations a
RoomHandlerperforms on its room while handling an event. The handler holds no sockets of its own — it reaches them through this context — so a Durable Object can hibernate between events. - Room
Handler - The protocol for one kind of room. A module implements it; the runtime owns the sockets and calls these as events arrive.
- Runtime
- A runtime resolves environment bindings into
Portsand declares statically which ports it can provide, soHarness::buildcan reject a module that requires something the runtime will never hand it (ADR 0002). Reference implementation:cratefield-runtime-cloudflare. - Signature
Scheme - How a provider puts its signature material on the wire. Implement this
for a provider none of the built-in schemes speak; the verification core
is
WebhookVerifier’s either way. Fail closed:Nonefor a delivery whose headers cannot be read in full, never a guess. - Signer
- Produces and verifies
base64url(json).base64url(mac)tokens where the MAC is computed over the encoded payload string, so a token has exactly one valid encoding (ADR 0006). - Status
Webhook - A tracker’s inbound status webhook, implemented per vendor by adapter crates: how to verify a delivery’s signature and how to read a state change out of the verified body.
- Surface
Source - Where the current surface comes from (issue #76). With no sidecar
mounted this is the document composed at build; with sidecars, each
call fetches every mounted sidecar’s
/__surface(public part) and merges it in, so a sidecar redeploy is seen on the next request (ADR 0009). An unreachable sidecar contributes nothing and is logged. - Template
- One template.
datais the caller’s JSON payload;localeis the requested locale tag (en,de, …) used by the implementation for its own variants. - Tenant
Databases - How a deployment turns a resolved tenant into a database handle.
- Tenant
Lifecycle - The write half of the tenant registry: create a tenant, read the registry, and walk a tenant through its erasure.
- Tenant
Routing - A deployment’s tenant plane: a host becomes a tenant, and a tenant becomes a database handle.
- Text
Model - Completes a prompt, over whichever provider the venture wired for the
Prompt::tierit was asked for. An adapter serves any tier it is configured for (typically one);RoutingTextModeldispatches between the adapters a venture configured. - Text
Model Ext - Structured output on any
TextModel(issue #580). Blanket-implemented for everyTextModel, so an adapter cannot override — and cannot skip — the schema check, the validation, or the repair retry; import the trait to call the methods. - Tool
Executor - Runs one tool call and reports its result (issue #665).
- Tracker
- Files tickets into a tracker and reports their status.
- TryFrom
Value - Conversion from a sea-query
SeaValuefor typed row access. - UiMount
- A renderer the venture mounts at
/uiwithHarnessBuilder::ui(ADR 0010). Core defines the seam;cratefield-uiis the implementation, kept out of core so a venture without a UI carries nomaud. - Vector
Index - Stores and ranks embedding vectors, within the namespace every call
names — the sibling of
Embedder, which makes the vectors this one keeps and searches. Hosted adapters (Vectorize) are eventually consistent — a write may take seconds to become queryable — whileExactVectorIndexis immediate.
Functions§
- allowance_
exhausted - A
429 usage/allowance-exhaustedproblem (issue #588): a metered allowance is spent for the current period. The body carries extension members a caller acts on — themeter, thelimit, theusedtotal and theperiod_endas RFC 3339 — andRetry-Afteris the delta-seconds to that reset, the same headerrate_limitedsets. - answer_
margin - How narrowly the answer won: the top probability minus the runner-up, never negative.
- assert_
migration_ set - Rejects a malformed migration set at compile time.
- bearer_
token - Extracts the bearer token from
Authorization: Bearer <token>. - blob_
error_ from_ stream - Maps a mid-stream failure to a
BlobError(issue #586): a ceiling breach isBlobError::TooLarge, a transport failure isBlobError::Operationwith the detail for logs. - captcha_
effective - Whether the runtime’s
Captchaport can really verify a token in production: the port is provided and, when the adapter reports, hostname-bound and not fail-open. An adapter that does not report (Captcha::binding=None) counts as effective — presence is all the harness can know about a third-party implementation; the adapter contract carries the duty to fail closed per request. - card_
data_ hit - The first card-data fragment
textcontains (case-insensitive), orNone. Keeps card numbers, verification codes and full expiry out of migrations and secret names — with a normal Stripe integration none of them should exist (issue #44). - check_
actor_ call - Validates the
(kind, key, message)one call carries: the kind, the key and the message size. Shared by both runners, the scoped view and the Cloudflare host, so all of them refuse a call the same way — the message bound is checked here rather than only inside a handler. - check_
blob_ size - Rejects a write whose payload exceeds
MAX_BLOB_BYTES(issue #136). EveryBlob::putimplementation MUST call this before touching storage;ScopedBlob(the module-facing wrapper) already does, so an adapter’s own call is the second, defence-in-depth gate for runtimes-wired stores and direct users. - check_
hostname - Validation helper, called by adapters before any provider call:
normalises
hostname(trimmed, lowercased, one trailing root dot stripped) or says why it cannot serve. - check_
part_ number - Rejects a multipart part number outside
1 ..= MAX_MULTIPART_PARTS(issue #586) before any store sees it. - check_
rate_ limit - Shared limiter loop: every key must pass, and a transport error is
resolved by
on_failureat the call site rather than per-module convention. No limiter configured (None) allows the request: composition chose to run without one. - client_
ip - The client IP for rate limiting, from the headers.
- constant_
time_ eq - Constant-time equality of two secrets, via fixed-length digests so timing does not leak the configured token’s length.
- created_
tables - Every table
sqlleaves behind, in the order it creates them. - csv_
escape - Escapes one CSV field: formula-guard, then RFC 4180 quoting.
- csv_row
- Escapes and joins one CSV row, with a trailing newline.
- declared_
content_ length - The declared
Content-Lengthof a response, when it parses as a non-negative size. Implementations check this before touching the body, so an oversized declared length is refused without allocating for it (issue #136). - deployed_
env - The environment this deployment runs in (issue #143).
- encode_
image - The standard, padded base64 encoding of an image’s raw bytes (issue #628) — the form every provider expects for inline image data. Here so an adapter needs no base64 dependency of its own.
- encoded_
image_ len - The length of
encode_image’s output forraw_lenraw bytes (issue #628):4 * ceil(raw_len / 3), padding included. Pure arithmetic, soPrompt::check_imagescan size an image without encoding it — to refuse an over-limit image before the allocation, not after. - env_
disagreement - Whether the deployment’s environment contradicts the compiled one (issue #143). Not an error by itself — the stricter answer wins — but it means the build-time gate ran against the wrong environment, so the caller re-checks and says so.
- forward_
control_ event - Forwards a one-line boot-time control event to the installed sink at its own level (issue #441); a no-op when none is installed (native, tests).
- harness_
api_ mismatch - The message
Harness::buildandfz doctorreport for a module whoseModule::harness_apidiffers from core’s: it names the module, the module crate’s version, the API it targets, and thecratefield-corecrate with its version and API (issue #17). - hint_
field - Sets one
x-cf-*(or any) keyword on a field of an object schema after derivation, for hints that only exist at runtime: aselectwhose options are the configured product list. Unknown fields are ignored so a rename in the body type cannot panic at build. - invalid_
email_ problem - A
400 validation-failedproblem for a rejected address. - is_
email_ field - Whether a field is expected to carry an email address.
- is_
idempotent_ sql - True when the SQL carries an idempotence guard, so re-running it
after a crash is safe. Required of every migration marked
transactional: false(RECONCILIATION.md §4). - is_
plain_ identifier - An unquoted SQL identifier: ASCII letters, digits and underscore, starting with a letter or underscore, at most 63 bytes — the shortest limit among the dialects the harness targets (Postgres truncates there; SQLite does not care).
- is_
secret_ field - Whether a field name marks a secret: matches
(?i)secret|token|key|authorization|password. - is_
valid - A conservative validator: non-empty, one
@, sane lengths, an ASCII local part from the unreserved set, and a dot-separated alphanumeric domain with no empty or hyphen-edge labels. - limit_
stream - Wraps a byte-chunk stream so that the chunk which would push the total
past
max_bytesis replaced byStreamError::TooLarge(it is not delivered), the source is dropped, and every later poll answersNone(issue #586). The tool an adapter reaches for to implementBlob::put_streamandBlob::upload_partwithout buffering, and the same enforcement, one layer down, thatScopedBlobapplies. - lint_
card_ data - Card-data column or table names found in
sql, as(fragment, why)pairs. Comments and string literals are ignored, so documenting the rule does not trip it. - lint_
portable_ sql - Returns
(token, explanation)pairs found insql. - measure_
agreement - Asks both adapters every corpus item — one batch per item, cheap first,
expensive only when cheap answered — and reports agreement per kind.
Every call is recorded to
accountingasCallRole::Shadow. An adapter error skips the item’s questions rather than aborting the run: a failure rate is evidence too. - migration_
checksum - The sha256 of a migration’s SQL, lowercase hex. Recorded in
harness_migrationswhen the migration is applied, so a later run can tell “already applied” from “applied, then edited” — the rule forward-only migrations rest on, enforced by the database rather than by a lockfile in one repository (issues #28, #34). - migration_
edited - The message a migration whose recorded checksum no longer matches gets. Shared so both engines say the same thing.
- migration_
missing_ guard - The message a non-transactional migration without an idempotence guard gets. Shared so both engines say the same thing.
- migration_
tables - Every table a module’s migrations leave behind, on either dialect.
- normalize_
email - Trim, Unicode NFC normalise, then lowercase. Idempotent.
- origin_
of - The RFC 6454 origin of
url: scheme, host and non-default port, ASCII serialized. - payments_
effective - Whether the runtime can verify webhook signatures for the
RoutePolicy::Signature-guarded routes whose modules verify throughPayments(the default): signature verification is the adapter’s per-request duty (verify_webhook+Inbox), and which secret it checks against is deploy configuration. A module that declaredSignatureVerification::Hmacis not this function’s business — its production requirement is its secret key, checked bywebhook_secret_readiness. - problem_
registry - Every core slug definition, for tests and docs.
- production_
readiness - The production abuse-control gate (issue #133), as collected error
strings (the
ConfigErrorconvention: report every problem at once). Empty for anything butProduction. - rate_
limit_ keys - The rate-limit keys for one request: always
ip:<ip>(orip:unknownwhen no address is visible), plusemail:<normalized>when an address is known. The limiter is consulted per key, in order. - rate_
limited - A
429 rate-limitedproblem (architecture section 6).Retry-After: <seconds>comes from theDecision’s own pause, falling back to the quota’s reset when the limiter reports a window but no pause; a known quota also rides the IETF draftRateLimit-Limit,RateLimit-RemainingandRateLimit-Resetheaders (delta-seconds), so a well-behaved client can pace itself without probing (issue #538). A decision with no quota at all — a Workers Rate Limiting binding, or a failure resolved at the call site — is a bare429+Retry-After, exactly as before. - rate_
limiter_ effective - Whether the runtime has a limiter it can actually consult (issue #437).
- receive_
mail - Verifies a webhook delivery against
source’s verifier, and only then parses it:parsenever sees unverified bytes. The parameters areWebhookVerifier::verify’s — the endpoint’ssecret, the request’sheaders, the rawbodybytes andnow_unixfor the replay tolerance. - receive_
status - Verifies a webhook delivery against
hook’s verifier, and only then parses it:parsenever sees unverified bytes. The parameter shapes areWebhookVerifier::verify’s — the endpoint’s per-tenantsecret, the request’sheaders, the rawbodybytes (before anything parsed them) and the currentnow_unixfor the replay tolerance, where the vendor’s scheme carries a timestamp. - redacted_
value - How one recorded field is stored:
[redacted]for secrets, the hash for emails, the value passed throughscrub_textotherwise (issue #135: a secret inside a genericuri/message/errorvalue is invisible to the field-name rules alone). - remaining_
erasure - The erasure steps still outstanding for a tenant in
status. - request_
id_ is_ valid - The character class and length bounds of an accepted request id.
- require_
admin - Checks
Authorization: Bearer <ADMIN_TOKEN>for one admin request. - require_
api_ key - The per-request gate, the API-key sibling of
cratefield_core::require_admin: readsAuthorization: Bearer <token>, verifies it againstkeys, and demandsscope. A missing header, malformed token, unknown prefix, revoked key or wrong secret all answer401 api-key-unauthorized, one uniform problem so a probe cannot tell which held; a valid key withoutscopeanswers403 api-key-forbidden; a store failure answers503 not-ready(generic detail — the error itself is only logged). - retry_
after Retry-After(RFC 9110 §10.2.3) as a duration, so a caller can honour what a provider asked for.- run_
actor_ alarm - Runs a fired alarm. The staged context starts with the alarm cancelled, so a handler that does not re-arm leaves none set; a handler error commits nothing and returns the error, and the host retries.
- run_
actor_ message - Runs one message: validates the kind, key and message size, runs the handler against a staged context, checks the reply size, and only then commits the staged writes. A handler error or an oversized reply commits nothing.
- run_
tool_ loop - Runs
promptto completion throughmodel, running any tool calls withexecutor, withinbudget(issue #665). - schema_
for - Generates the schema for
Tthe way every action does: draft 2020-12, definitions inlined so a renderer never has to resolve$ref. - scrub_
request_ url - Cuts one known request URL back to its origin everywhere it appears
in
message, and redacts that request’s bare target as well (issues #228, #229). - scrub_
text - Scrubs secrets out of a free-text value (issue #135).
- set_
error_ forwarder - Installs a process-wide forwarder for internal-error diagnostics (architecture section 11).
- set_
log_ pseudonym_ key - Installs the key that
subject_hashuses to pseudonymise email values in logs (issue #135). A bare SHA-256 of a low-entropy email is dictionary-reversible, so a runtime derives this fromHARNESS_SECRETand installs it once at startup;subject_hashthen emitsHMAC(key, email)instead. Unset (tests, or a runtime whoseHARNESS_SECRETfailed validation) makessubject_hashemit a fixed all-zero000000000000placeholder — fail-closed; no digest of the address ever reaches a sink. Boot-time infrastructure, not request state (ADR 0007); first-install-wins. - signer_
effective - Whether the runtime can issue and verify the artifacts a
RoutePolicy::SignedLinkroute rests on (issue #143). - stated_
reason - The operator’s reason, if they actually gave one.
- subject_
hash - The redacted form of an email-ish value: a 12-hex pseudonym, no
@ever reaching the logs. When a pseudonym key is installed it isHMAC-SHA256(key, domain ‖ value)(a keyed pseudonym, resistant to dictionary reversal); when it is not, a fixed all-zero placeholder — correlation is lost, but a bare digest never leaks (issue #135, fail-closed). - svix_
secret_ key - An Svix endpoint secret’s key bytes: base64, with or without the
whsec_prefix Svix writes it with.Nonewhen it does not decode. - timeout
- Typed wrapper over
Clock::timeout_any.Nonemeans the clock abandoned the future afterafter. - ttl_
secs - A
Notification::ttlas the whole seconds every push protocol takes. - undeclared_
tables - The tables a module owns and has said nothing about: the gap this type exists to close, named so a test can fail on it.
- unlimited_
public_ routes_ override - The operator’s recorded reason for serving public writes and admin routes unlimited, if they set one (issue #437).
- unlisted_
tables - The tables a module’s own migrations create and its
Module::tablesnever mentions: the hole the declaration rule cannot see (issue #272). - unprotected_
writes_ override - The operator’s recorded reason for serving guarded routes unprotected, if they set one (issue #143).
- validate_
actor_ key - Rejects an actor key or storage key that is empty or longer than
MAX_ACTOR_KEY_BYTES. - validate_
actor_ kind - Rejects an actor kind that is not
1..=MAX_ACTOR_KIND_BYTESof[a-z0-9_-], so"<kind>:<key>"is unambiguous. - validate_
questions - Checks a question set before an adapter renders it, so a malformed set
is
ClassifierError::Rejectedand never a panic anywhere: every adapter calls this first, and every caller knows the shapes it hands the provider are whole. - validation_
error - The reason an address is rejected, for problem
details. - values_
agree - Whether two answer values are the same answer.
- verify_
human_ form - The shared CAPTCHA gate for
HumanFormhandlers (issue #133): the single place a module asks “is this form submission a human?”. - webhook_
secret_ readiness - The boot-time leg for HMAC-verified signature modules (issue #533): in
production, each one’s configured secret key must be present and
non-blank, or the module’s handler refuses every delivery. The errors
name the module and the config key, never the value, and there is no
waiver: an operator who wants the endpoint unverified removes the
route, which is a build-time decision. Run by the boot gate
(
Harness::router’s readiness re-check), which holds the deployment config; the build-time gate has none, so it skips this leg — the same split as the overrides there.
Type Aliases§
- AnyError
- Error type for handler and scheduled-work results.
- BoxFuture
- An owned dynamically typed
Futurefor use in cases where you can’t statically type your result or need to add some indirection. - BoxStream
- A type-erased,
Sendstream of body chunks: the shape a runtime bridges to the wire, and whatResponseStream::takehands one. Same definition asfutures_util::stream::BoxStream, written here because core depends onfutures-coreonly. - Event
Handler - A registered handler: receives the emitting request’s scope and the payload.
- Event
Name - Event names are
"<module>.<event>", e.g.waitlist.confirmed.