Repository navigation
Prevent same-second checkpoint ID collisions from overwriting snapshots #38
Description
Defect
At exact default head 685e682ce7fdbca3d2dcf0eb2ba4a1946d0e241a, CheckpointManager.create_checkpoint() derives snapshot_id only to whole-second precision:
snapshot_id = f"SNAP_{now.strftime('%Y%m%d_%H%M%S')}"Two checkpoints created during the same second therefore share one path. The second write replaces the first snapshot, while CHECKPOINT_REGISTRY.json retains two entries with the same snapshot_id. A lookup by the first checkpoint name then loads the second checkpoint's state.
This is reproducible data loss, not a metadata-only concern.
Exact evidence
Pinned source blobs:
rege/persistence/checkpoint.py:7f087d59b730811845415f0a77191b210d6fb5b8rege/persistence/archive.py:afcab8688831f7fe760bb5cfc04aeee3bd1dba1brege/core/models.py:bd8666f9c4486f570706bf8323a529f4afa4d3f9rege/core/exceptions.py:a2a06ef26d677171c24f3162bf77c0066f9e1d83
A deterministic isolated-source reproduction fixed datetime.now() to the same instant for two calls and confirmed:
- both returned the same snapshot ID;
- only one snapshot file remained;
- the registry contained two entries;
- loading the first name returned the second state.
A negative control advanced the clock by one second and preserved two IDs, files, and states.
Scope
Allowed implementation paths:
rege/persistence/checkpoint.pyrege/tests/test_persistence.pyor one narrowly named persistence regression test
Touch rege/persistence/archive.py only if the chosen atomicity fix requires it. Do not change workflows, release configuration, packaging, generated coverage records, source-material archives, or unrelated persistence formats.
Open PRs #15, #31, #33, #35, and #37 do not touch these checkpoint paths.
Acceptance
- Two checkpoints created at the identical wall-clock instant receive distinct stable IDs and distinct snapshot files.
- Each registry entry resolves to its own saved state; no stale-name aliasing or silent overwrite remains.
- Registry update and snapshot persistence fail closed: a failed write must not create an entry that points to missing or different data.
- Existing load, list, export, import, delete, latest-selection, and pruning behavior remains covered.
- Run and record:
python -m pytest -q rege/tests/test_persistence.py rege/tests/test_persistence_coverage.py- the new same-second collision regression independently
- Return exact head, commands, pass/fail counts, and changed paths. Do not weaken assertions or delete historical data to obtain green.
Delivery boundary
Implementation may be prepared as a draft only. This issue grants neither merge nor release authority. The repository's current release-drafter.yml writes release-draft state on pull-request open/synchronize, so dispatch must retain that side-effect gate and revalidate it before creating provider output.
Activity