Agent Snapshot
Drain → snapshot in-flight state; restart → restore + resume. The last substrate slice: makes the orchestrator + idempotency + stream + event-bus + tenant + saga + posture-chain + trace stack operationally durable across deploys + crashes.
Snapshot captures (registry of agents, in-flight streams' last- seen cursors, half-completed saga state, pending event-bus deliveries, idempotency cache hot-subset). Restore re-elects shards, replays buffered events (composes v0.9.22 idempotency to prevent double-execute), resumes sagas from their persisted step pointer.
var snapshot = b.agent.snapshot.create({
orchestrator: orch,
backend: operatorBackend, // { put, get, list, delete }
audit: b.audit,
policy: {
drainTimeoutMs: C.TIME.minutes(2),
snapshotIntervalMs: C.TIME.minutes(5),
maxSnapshotBytes: C.BYTES.mib(50),
},
});
// At SIGTERM:
await orch.drain({});
var snap = await snapshot.takeSnapshot();
await snapshot.persist(snap);
// At restart:
var loaded = await snapshot.loadLatest();
if (loaded) await snapshot.restore(loaded);
b.agent.snapshot.create(opts) #
{
orchestrator: b.agent.orchestrator, // required
backend: { put, get, list, delete }, // required
audit: b.audit namespace, // optional
policy: { drainTimeoutMs, snapshotIntervalMs, maxSnapshotBytes },
}
Create the snapshot facade. Operator wires the durable storage backend; framework owns the envelope shape + drain/restore coordination.
var snapshot = b.agent.snapshot.create({
orchestrator: orch, backend: myBackend,
});
var snap = await snapshot.takeSnapshot();
await snapshot.persist(snap);
b.agent.snapshot.reseal(opts) #
{
backend: { put, get, list }, // the same backend create() was wired with
oldRootJson: string, // b.vault.getKeysJson() of the OLD keypair
newRootJson: string, // b.vault.getKeysJson() of the NEW keypair
}
Re-seal every persisted snapshot envelope from the OLD vault root to the NEW vault root under the SAME column-shaped AAD, for a vault-key rotation. The snapshot seal is a vault.aad: ciphertext hidden behind the snap-sealed-v1: wrapper prefix and written to an operator backend, so a db.enc scan for the bare vault.aad: prefix can neither detect nor reach it — the rotation pipeline drives the re-key through this explicit backend walk. Each row is unsealed under the old root and re-sealed under the new root in memory (composing b.vault.aad.resealRoot); the plaintext envelope is never written to operator-readable storage. The decorative wrapper fields the backend's list() filters on (snapshotId / takenAt / tenantId) are preserved, so the index is untouched.
allowPlaintext envelopes (no sealed wrapper) carry no AAD-sealed blob to re-key and are skipped; the returned resealed count reflects only re-sealed rows. A row sealed by a non-default KMS sealer (the inner blob is not a vault.aad: value) is refused — re-key it through the operator's own KMS, not this path.
var result = await b.agent.snapshot.reseal({
backend: operatorBackend,
oldRootJson: oldKeysJson,
newRootJson: newKeysJson,
});
result.table; // → "agent.snapshot"
result.resealed; // →
Last updated 2026-08-08T16:39:49.652Z by seeder.