symfonic.kernel.contracts.continuation_attestation¶
continuation_attestation ¶
The persisted proof that lets a memory-free root pause resume in a new process.
CORE-194 owner answer (2026-10-15): an Agent WITHOUT memory keeps its durable
pause across a restart. A fresh process never issued the paused run, so the
resumed run could not prove its lineage (run_admission.UNPROVABLE_LINEAGE).
This module is the one authority that can close that gap, and only for a run
the kernel itself judged, while it was live, to be:
- the issued lineage of the paused run id, a resolved root with no parents;
- stamped memory-free from its compiled plan, with no descendant that touched
memory (
RunLineage.memoryis monotone and propagates upward); - holding no capture any declared witness reports (an extra refusal only).
Issuance has no public entry: the human capability's turn-state store calls
the private _seal_minted right after it wrote the turn state itself, with
the SDK-minted claims and the exact bytes it encoded. No caller-chosen mapping
of ids or digests is accepted. :func:admit_root is the only code that
registers a recovered root in the issued table, and only for a row whose MAC a
:class:ContinuationAttestorPort verifies and whose every bound field equals
what the host expected. It returns an opaque :class:RootAdmission the host
holds until the resumed turn ends.
Trust model. Issuance happens once per pause, inside capability.pause, for
the claims it just minted (a fresh jti from uuid4) and the turn text it
just encoded, and only while the kernel judges the live run a memory-free root.
So a public capability.pause called inside such a run legitimately creates
NEW authority for the state it is given -- a new token, never an existing one.
No public surface re-authorizes an existing pause: TurnCheckpointStore.record
writes and never seals; PauseBinding, current_run_binding, reconstructed
or reused claims (a namespace, a real PauseClaims with equal fields, or the
genuine object itself), stored rows, Keyset.sign, EnvelopeSigner.mint
and a checkpoint adapter seeing only what it is asked to write cannot yield an
accepted proof; outside a live memory-free root, or with memory, nothing issues.
Excluded, and trusted as the deployment: a holder of the raw key secret, a
deployment-supplied attestor (see :class:ContinuationAttestorPort), and any
code that calls underscore names or rewrites SDK objects. Python offers no
sandbox against the last; this module does not claim one.
ContinuationAttestorPort ¶
Bases: ABC
Computes the attestation MAC: deployment authority, like a signer.
The SDK implementation is KeysetContinuationAttestor, offered by
EnvelopeSigner.continuation_attestor(). A deployment that injects its
own signer may offer its own attestor; it then carries the same authority as
that signer's pause-token signatures, and a weak one weakens its proofs as
a weak signer weakens its tokens. A signer offering none gets no durable
NoMemory resume (the fresh-process refusal). The hooks are private: a public
method that MACs a caller's body would be a minting oracle.
RootAdmission ¶
A recovered root the kernel admitted; hold it while the resumed run lives.
Source code in src/symfonic/kernel/contracts/continuation_attestation.py
admit_root ¶
Admit the root expected names, from a verified row; refuse otherwise.
Source code in src/symfonic/kernel/contracts/continuation_attestation.py
turn_digest ¶
The digest a proof binds: the exact encoded turn state the SDK wrote.