@@ -1484,6 +1484,13 @@ def _run_in_configured_mode(
14841484 # downstream code can reference it by name.
14851485 if not state .checkpoint .store_is_open ():
14861486 state .checkpoint .restore (resume_after = "_" )
1487+ # Truncate checkpoint history to only the current restored state.
1488+ # Without this, model names from a prior complete run remain in
1489+ # self.checkpoints and trigger DuplicateWorkflowNameError when
1490+ # those models need to re-run later in the calibration loop
1491+ # (Runner's "good to go" fast-path skips the truncation that
1492+ # checkpoint.restore normally provides).
1493+ state .checkpoint .checkpoints = state .checkpoint .checkpoints [- 1 :]
14871494 state .checkpoint .add (original_last_model )
14881495 return
14891496
@@ -1573,6 +1580,14 @@ def _restore_parent_state_from_pipeline(state: workflow.State) -> None:
15731580 state .checkpoint .close_store ()
15741581 state .checkpoint .restore (resume_after = "_" )
15751582
1583+ # Truncate checkpoint history to only the current restored state.
1584+ # Without this, model-level checkpoint names from a prior run remain
1585+ # visible in self.checkpoints. When Runner.__call__ later takes its
1586+ # "good to go" fast-path (skipping checkpoint.restore and its built-in
1587+ # history truncation), _pre_run_step sees those stale names and raises
1588+ # DuplicateWorkflowNameError for models that legitimately need to re-run.
1589+ state .checkpoint .checkpoints = state .checkpoint .checkpoints [- 1 :]
1590+
15761591 # After restore, all tables are clean (status=False). Mark them dirty so
15771592 # the next checkpoint.add() writes them to disk at a known checkpoint name.
15781593 # This ensures apportion subprocesses find table files at a single,
0 commit comments