Description
InMemoryCheckpointStorage.get_latest picks max() by timestamp alone. Checkpoints at the same superstep boundary legitimately carry identical timestamps (the WorkflowCheckpoint docstring on iteration_count says so explicitly), and datetime.now() resolution means even distinct boundaries can collide. When timestamps tie, max() returns whichever checkpoint the dict iterates first, so the result depends on save order:
storage = InMemoryCheckpointStorage()
parent = WorkflowCheckpoint(workflow_name="w", graph_signature_hash="h", checkpoint_id="parent", timestamp=ts)
child = WorkflowCheckpoint(workflow_name="w", graph_signature_hash="h", checkpoint_id="child", timestamp=ts, previous_checkpoint_id="parent")
# save parent then child -> get_latest returns parent
# save child then parent -> get_latest returns child
A workflow resuming via get_latest can therefore restore the stale checkpoint, with no error anywhere.
FileCheckpointStorage.get_latest has the same timestamp-only max(); it happens to mask the issue via list ordering, but the same identical-timestamp input can pick the wrong one.
The checkpoint docstring itself says ordering is defined by the previous_checkpoint_id lineage chain, not timestamps alone.
Expected behavior
Ties on timestamp resolve through the lineage chain: the checkpoint that no other checkpoint supersedes is the latest, regardless of save order.
Environment
agent-framework python main (astryx-era clone from this week), Python 3.12
Description
InMemoryCheckpointStorage.get_latestpicksmax()by timestamp alone. Checkpoints at the same superstep boundary legitimately carry identical timestamps (theWorkflowCheckpointdocstring oniteration_countsays so explicitly), anddatetime.now()resolution means even distinct boundaries can collide. When timestamps tie,max()returns whichever checkpoint the dict iterates first, so the result depends on save order:A workflow resuming via
get_latestcan therefore restore the stale checkpoint, with no error anywhere.FileCheckpointStorage.get_latesthas the same timestamp-onlymax(); it happens to mask the issue via list ordering, but the same identical-timestamp input can pick the wrong one.The checkpoint docstring itself says ordering is defined by the
previous_checkpoint_idlineage chain, not timestamps alone.Expected behavior
Ties on timestamp resolve through the lineage chain: the checkpoint that no other checkpoint supersedes is the latest, regardless of save order.
Environment
agent-framework python main (astryx-era clone from this week), Python 3.12