Bounded durable resume
Durable resume continues the same operation after process interruption. Touba loads a checkpoint, revalidates current authority and reconciles each external effect with its journal before proceeding. Restart never resumes automatically.
Choose the recovery mechanism
Checkpoints serve several different paths. Select the path for the interrupted boundary instead of restarting the program from the beginning:
| Need | Path | State and boundary |
|---|---|---|
| Wait for a human decision | --human-checkpoint-out, then --human-resume-checkpoint with an exact decision; durable waits through the server | Source/agent stacks, loops and parallel continuations are preserved; each decision belongs to one occurrence. |
Persist a parallel group's progress | --parallel-checkpoint-out, then --parallel-resume-checkpoint | Completed branches return without new calls; private journals and budgets are preserved at group boundaries, not at every instruction after the join. |
| Resume an interrupted sequential operation | /operations/{id}/recovery projection, then explicit resume request | The direct, acyclic profile below, a touba-run-checkpoint-v1 checkpoint and effect journal. |
Retain the same build and compatible artifacts, private checkpoints and effect journal. Incomplete or altered state is refused, not converted. Reconcile an unknown external outcome according to its effect contract; never assume success. Handlers still implement the external service's real idempotency. See Human validation, the CLI reference and SDK guide.
Eligible sequential workflows
The supported entry graph is direct, sequential and acyclic: pure bind
nodes, direct call_tool nodes, and a terminal give or stop. A human decision
can be consumed only if it is already available and still valid at entry.
Reachable tools must declare their effect contracts in a V1 manifest, including
tools with kind: none.
Raw runtime inputs currently exclude this durable-resume path. The project server can execute runs with inputs normally, but does not label them resumable. Intermediate human pauses, loops and nested agent calls are not covered by this resume mechanism. Human checkpoints remain a separate mechanism.
Recover an operation after a lost HTTP response
Create a session with POST /interactions/sessions and retain its
session_id. Submit work to POST /interactions/sessions/{session_id}/messages
with a unique, client-generated message_id retained by your application.
After a lost response, GET /interactions/sessions/{session_id} lists operations
with their message IDs. Use the matching operation_id to read
GET /operations/{operation_id}/recovery. Resending the exact same message
with the same identity also returns its existing operation. Use a new identity
for new business work. The server persists this correlation before execution.
These authenticated APIs work after a server restart. The host application controls user access. Sessions retain at most 100 messages and 50 operations; the store holds at most 100 sessions. Keep identifiers in your application and recover missing responses promptly. HTTP 202 means accepted; the operation carries the execution result.
Budget interrupted attempts
Before dispatch, Touba reserves the handler's timeout_ms. A crashed attempt
keeps that reservation because its exact elapsed time could not be confirmed.
A retry reserves its own timeout.
| Run budget | Interrupted attempt | New reservation | Outcome |
|---|---|---|---|
| 15,000 ms | 10,000 ms | 10,000 ms | refused before dispatch |
| 40,000 ms | 10,000 ms | 10,000 ms | reservation possible, with room for remaining work |
Add confirmed active time, other operations and a margin. The total must stay
strictly below max_run_ms. Time spent with the server stopped is excluded.
RunTimeBudgetExceeded details expose activeElapsedMs, reservationMs
and remainingMs. The dispatch_refused_budget_exceeded event exposes
active_elapsed_ms, reservation_ms, remaining_ms and limit_value.
Inspect before requesting resume
GET /operations/operation%3Aexample/recovery
The touba-operation-recovery-v1 response contains state, freshness, correlations,
effect summaries, allowed actions and structured refusal reasons. A client must
use this response rather than infer authority from a visible button or cache.
POST /runs/sandbox/resume
Content-Type: application/json
{
"schema_version": "touba-operation-resume-request-v1",
"operation_id": "operation:example",
"checkpoint_revision": 4,
"checkpoint_digest": "sha256:...",
"resume_request_id": "resume:example:1"
}
Use the actual revision and digest returned by the server. Reading requires
executions.read; resuming requires executions.run. Duplicate requests with
the same identity and revision are coalesced. A stale revision or conflicting
concurrent request produces DurableResumeConflict. Cancellation, revoked
authority and changed artifacts are checked before a handler is launched.
Effects and budgets
| Recovered state | Outcome |
|---|---|
applied, result available | Restore without launching the handler. |
applied, result unavailable | Refuse with EffectResultUnavailable. |
unknown, idempotency key | Retry with the same effect_id and a new call_id. |
unknown, reconciliation | Require provider-specific reconciliation. |
unknown, no safe retry | Refuse with EffectOutcomeUnknown. |
kind: none, result lost | May repeat the call with a new attempt and budget charge. |
Interrupted attempts remain charged. Restoring an already-applied result does not consume another tool call. Journal and checkpoint reconciliation requires exact call, attempt and effect-ordinal correlation; it does not skip to an unrelated later journal entry.
Persistence and trust
touba-run-checkpoint-v1 stores execution position, validated JSON bindings,
artifact digests, consumed budgets, effect identity and trace-prefix correlation.
It does not store resolved secrets or authority tokens. Secrets are resolved
again; a dynamic identity service is rechecked immediately before handler spawn.
The supplied store is single-host and single-process. A digest detects drift,
not hostile rewriting by someone able to replace the file and recompute it.
Produced values can remain in later checkpoints even after their last use.
The runtime cannot identify an unknown credential incorrectly returned as
business data. After a host SIGKILL, a handler may outlive the host unless
the configured sandbox terminates descendants; the parent timeout does not
survive that crash. There is no distributed transaction or exactly-once claim.
See Effect contracts and Durable human waits.