Checkpoints and recovery

Sequential work needs a key and its current position. A bare key starts at position zero and cannot resume a consumed sequence.

Freeze the logical state

freeze returns the wrapper's immutable cursor. Construct a wrapper from that cursor to continue the same suffix.

using ImmutableRNGs, Random

key = Philox4x32(42)
full = randn(MutableRNG(key), 12)

rng = MutableRNG(key)
head = randn(rng, 5)
midpoint = freeze(rng)
tail = randn(MutableRNG(midpoint), 7)

vcat(head, tail) == full
true

Copying midpoint intentionally replays tail. Pass the new cursor forward when the application must consume rather than replay the suffix.

Store a canonical record

cursor_checkpoint returns a data-only record. restore_cursor validates the schema, generator, stream ID, key codec, and position.

record = cursor_checkpoint(midpoint)
restored = restore_cursor(record)

(restored == midpoint,
 record.stream_id == ImmutableRNGs.stream_id(Philox4x32),
 cursor_position(restored))
(true, true, 0x0000000000000000000000000000000a)

The record contains the complete key and position. It does not encrypt, authenticate, or recover corrupted data. Add those properties in the storage or transport layer.

External samplers own state outside the RNG. For exact application replay, record the model, sampler, dependency versions, worker layout, and sampler state beside the cursor record.

See 04_checkpoint_resume.jl and 18_turing_bridge.jl.