In wait_for_condition.execute(), state is restored only when checkpointed_result.result is truthy:
if checkpointed_result.is_started_or_ready() and checkpointed_result.result:
current_state = deserialize(..., checkpointed_result.result, ...)
else:
current_state = self.config.initial_state
serialize(None) yields None, so a check that returns None gets checkpointed as None, and on resume the falsy check resets current_state to initial_state instead of restoring None. None is overloaded as both "no result yet" and "result is None."
Impact: polling state is lost across attempts for a falsy/None state; a strategy that stops based on state (not attempt) may never complete.
Fix: distinguish a resumed retry from a fresh start via attempt count (not result truthiness) - restore via deserialize when attempt >= 1 (maps None → None), use initial_state only on first start. Add a continue-then-resume test with a None-returning check.
Note: pre-existing on main, surfaced during the #550.
In
wait_for_condition.execute(), state is restored only when checkpointed_result.result is truthy:serialize(None) yields None, so a check that returns None gets checkpointed as None, and on resume the falsy check resets current_state to initial_state instead of restoring None. None is overloaded as both "no result yet" and "result is None."
Impact: polling state is lost across attempts for a falsy/None state; a strategy that stops based on state (not attempt) may never complete.
Fix: distinguish a resumed retry from a fresh start via attempt count (not result truthiness) - restore via deserialize when attempt >= 1 (maps None → None), use initial_state only on first start. Add a continue-then-resume test with a None-returning check.
Note: pre-existing on main, surfaced during the #550.