turnframe-core
Pure types, pure functions and traits: the contract every other Turnframe crate is written against. No async runtime, no HTTP, no database.
Part of the Turnframe workspace. See the workspace README and architecture guide.
Scope
The crate implements the Flow Map architecture as data and pure logic:
| Module | What it holds |
|---|---|
ids, case, locale, hash, schema |
Identity and version newtypes, CaseRef, localized copy, canonical JSON hashing, schema fingerprints |
flow |
WorkflowDefinition / WorkflowExecutor, WorkflowView, phase ownership, §8.4 invariants, the type-erased WorkflowRegistry |
turn |
TurnInput: text, interaction response, attachments and origin may coexist |
plan |
What an operation declares about where it may run: target policy, mutability, availability; the limits a turn is held to |
operation |
OperationSpec: an operation's arguments, labels, value shapes and examples; DateExpr and Money |
understanding |
Understanding: what a turn was understood to ask, with the words behind every value; the reducer's input |
target |
Opaque target tokens, account-scoped resolution, ResolvedAct |
reduce, policy, command |
Whole-turn reduction contract, policy decisions, command envelopes, origins (what was confirmed, by which option class, on which channel), risk, derived command and batch ids, idempotency keys |
interaction |
Durable server-owned cards, stored options, the status state machine and validate_response |
event, response |
Commits, events, receipts, external statuses, ordered response blocks and the claim guard |
read, knowledge |
Read-only tool and knowledge retrieval contracts |
replay, observe, error |
Replay records (decisions, command outcomes, provider attempts and the outbox and reconciliation handles of a turn's external effects), metrics signals, the typed error family |
The rule the types enforce: the model proposes meaning, deterministic code decides effects, committed events decide claims.
Minimal example
use *;
use ;
use serde_json;
;
let workflow = GreetingWorkflow;
let case_ref = new;
let view = workflow.project;
assert!;
assert!;
Executors implement WorkflowExecutor<W>; WorkflowRegistry::builder().register(def, exec)
erases both behind ErasedWorkflow / ErasedExecutor so the runtime never
needs the concrete types.
Auditing one turn
ReplayRecord is what §26.1 of the specification asks for: everything needed to say why a turn
produced the commands and the answer it did. Besides the understanding, every model task, the
resolutions and the decisions, it names the turn's external effects: outbox_ids for the rows it
enqueued and reconciliation_attempt_ids for the attempts whose outcome never came back, so an
auditor holding only the record can ask the outbox what became of them. pending_reconciliations()
unions those with the attempts recorded against individual commands, once each.
Two shapes of "attempt" meet in that record, on purpose. ProviderAttemptRecord::attempt is a plain
ordinal because a model call that failed left nothing outside the process, and its stage is already
identified. AttemptId is an identifier because an external effect may have happened even though the
answer never arrived, and settling it means naming that exact attempt to a remote system. Both types
document the asymmetry.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.