Datagen Checkpoint Log¶
Decision¶
Each datagen experiment uses one Lance dataset:
The log is the only durable source of truth. Current state, failures, resume cursors, and trajectories are all derived by folding events. This avoids cross-dataset consistency hazards because Lance does not provide atomic transactions across multiple datasets.
Optional query projections may be added later, but they must be disposable, rebuildable, and excluded from checkpoint correctness.
Event model¶
Every row is an immutable event:
ITEM_CREATEDFIELD_SETFIELD_APPENDSTEP_COMPLETEDFAILEDTERMINAL
Every completed step emits a STEP_COMPLETED event, even when no field changed.
All field events and the completion marker for one step are written in the same
checkpoint batch.
event_id is a deterministic idempotency key. Retrying an ambiguously
acknowledged batch writes the same event ids, and the MemWAL LSM read path
de-duplicates them. item_seq is strictly increasing per item; two different
events at the same sequence are treated as a writer-fencing violation.
Schema¶
| Column | Type | Purpose |
|---|---|---|
event_id |
string | Deterministic event identity and LSM primary key |
item_id |
string | Scoped item identity |
root_item_id |
string | Root of the projected item tree |
parent_item_id |
string? | Direct parent item |
item_seq |
int64 | Per-item event ordering |
checkpoint_id |
string | Atomic step-boundary identity |
event_type |
string | Event kind |
step_name |
string? | Step provenance |
step_index |
int64? | Static step position |
step_instance_id |
string? | Runtime step identity |
iteration |
int64? | Loop/branch iteration |
attempt |
int32 | Execution attempt |
run_id |
string | Run attribution |
writer_epoch |
string | Item ownership/fencing identity |
field_name |
string? | Changed field |
field_type |
string? | Stable codec id |
codec_version |
int32? | Codec compatibility version |
value_kind |
string? | int, float, bool, str, json, or blob |
value_i64 |
int64? | Exact integer value |
value_f64 |
float64? | Floating-point value |
value_bool |
bool? | Boolean value |
value_str |
large_string? | String value |
value_json |
large_string? | Canonical JSON value |
value_blob |
large_binary? | Sparse inline bytes |
payload_size |
int64? | Blob size |
payload_checksum |
string? | Blob integrity |
query_tags_json |
large_string? | Non-authoritative query tags |
terminal |
string? | completed or filtered |
error_type |
string? | Failure type |
error_dump |
large_string? | Serialized failure |
traceback |
large_string? | Failure traceback |
event_ts |
timestamp(us, UTC) | Event time |
schema_version |
int32 | Log schema compatibility version |
value_blob remains inline while MemWAL's LSM scanner cannot materialize
blob-v2 columns. Normal fold and trajectory reads project it out. Blob access
first locates event_id using lightweight columns and then calls take_rows
for the exact _rowid.
Write and recovery invariants¶
- A checkpoint batch is one durable MemWAL generation.
- Log writes are append-only; retries reuse deterministic event ids.
- One live owner writes a given item at a time. Ownership changes require a
new
writer_epoch. - Resume reads
item_id = X, orders byitem_seq, and folds the events. FIELD_SETreplaces a field;FIELD_APPENDaccumulates it.STEP_COMPLETEDreconstructs the resume cursor.FAILEDandTERMINALare ordinary log events, not separate datasets.- Blob bytes are loaded only when the corresponding lazy reference is used.
Maintenance¶
Writers use distinct MemWAL shards. Reads union the base table and all flushed shards, so any instance sees every writer's events. Each writer periodically merges only its own generations into the base table. Shared base-table compaction and index refresh must be scheduled by one elected maintenance worker per experiment.