The SDK is split into three layers so AWS integration and JSON parsing do not leak into the replay hot path.
- Core — protocol values, deterministic identity, replay context, checkpoint state, operations, serializers, and handler result mapping.
- Service adapter — implements
service_clientusing the AWS SDK for C++ Lambda durable APIs. One virtual dispatch occurs per network request, not per local model or serializer operation. - Runtime adapter — translates Lambda invocation JSON/context into
invocation_input, attaches function/tenant metadata, callsrun, and writes the invocation response. - Local runner — implements the same
service_clientboundary in memory, advances a virtual clock, and repeatedly invokes the unchanged handler.
The service and runtime adapters are optional build targets. Applications that use a custom transport or embed the core do not link either AWS dependency.
Lambda invocation
-> runtime adapter
-> execution_state loads all history pages
-> durable_context reserves deterministic operation IDs
-> operation finds checkpoint by ID
succeeded: deserialize and skip user code
pending: suspend invocation
absent/ready: execute and checkpoint
incompatible: fail closed
-> child contexts repeat the same flow in an ID-prefixed namespace
-> parallel/map reserve every branch ID before bounded workers start
-> contending branch checkpoints are flat-combined into atomic API batches
-> flow validates its DAG, prunes unreachable nodes, then pre-reserves every
reachable node context before scheduling ready waves
-> handler returns SUCCEEDED, PENDING, FAILED, or RETRY
- No dependency is required by the core library.
- Invocation JSON is parsed directly into protocol models. Unknown values are skipped recursively without allocating a general-purpose DOM.
- Recursive-level inspection and replacement use a targeted top-level JSON object scanner that preserves all unrelated value slices.
- History lookup accepts
std::string_view, performs no temporary string allocation, and returns an immutable shared snapshot safe across concurrent state refreshes. - Known wire enums store only an enum value; storage is allocated only for an unknown future value.
- Serializers and durable callables are templates, allowing inlining.
- Declarative flow uses type erasure only at graph boundaries. Ordinary step, callback, map, and invoke hot paths remain statically dispatched.
- The local runner uses no scheduler thread and performs no sleeps. Timer transitions advance directly to the next virtual event.
- Exceptions represent invocation control flow and failures; ordinary transport
results use
std::expected. - Callback and chained-invoke results use
std::optionalto represent a successful backend operation without a payload. - Sequential checkpoints use a direct call path. Parallel/map scopes enable a flat-combining queue only while workers are active, avoiding queue and background-thread overhead for ordinary workflows.
- Benchmarks must retain their checksum and run in optimized builds to prevent dead-code elimination.
- User code inside a durable step cannot create nested durable operations.
- At-most-once interrupted steps never rerun the same attempt.
- A replay identity mismatch fails before user code executes.
- Unknown future statuses fail closed when their semantics are unsafe.
- A missing checkpoint token is accepted only after terminal execution updates.
- Callback failures are deferred from creation to
callback_handle::result()so replay always executes code between those two boundaries. - A suspended operation inside a child context never writes a false child failure checkpoint.
- Checkpoint-token mutation is serialized, and history entries are immutable snapshots replaced atomically under a write lock.
- Parallel workers operate on forked durable contexts whose operation counters were pre-reserved on the caller thread.