laundry: cite the machine_state history confirming #358's tail

The reporter's machine_state history for the same two cycles flips to
idle on the exact second progress reads 'Drying' (12:08:51 and 14:01:26),
which settles what the previous commits had to infer: rep_fn returns
'Idle' whenever state isn't active, so it cannot have produced that
value, and the only remaining path was the ungated sticky_live_fn the
bypass returned in its place. Replaying the sequence against the pre-fix
path reproduces the reported Cooling, Finish, Drying, Idle exactly; the
fix holds Finish through it.

Comments only -- swap the inference for the observation that confirms it.
This commit is contained in:
Marc Billow
2026-08-12 14:39:18 +00:00
parent f12f67b2b3
commit 67b28ed10f
2 changed files with 15 additions and 11 deletions
@@ -67,11 +67,14 @@ def _new_cycle_running(rep):
early once a new cycle is genuinely running.
Gated on `state == 'active'`, unlike _just_finished's arm condition
above: issue #358's dryer replays a running stage ('Drying') for a few
seconds after Finish while `state` already reads idle, and a bypass
keyed on the progress code alone read that tail as a new cycle and
republished it. Releasing late costs nothing -- an unreleased hold
still expires on its own -- so this side takes the stronger signal."""
above: issue #358's dryer resets `progress` to its course's first
stage ('Drying') in the same moment `state` goes idle, ~4s before
settling to 'None' -- confirmed by the reporter's machine_state
history, which flips to idle on the exact second progress reads
'Drying', in both captured cycles. A bypass keyed on the progress
code alone read that as a new cycle and republished it. Releasing
late costs nothing -- an unreleased hold still expires on its own --
so this side takes the stronger signal."""
v = rep.get("x.com.samsung.da.progress")
return _state_is_active(rep) and v is not None and v not in ("None", "Finish")
+7 -6
View File
@@ -166,12 +166,13 @@ def test_a_new_cycle_starting_overrides_the_hold():
def test_a_running_stage_after_finish_does_not_break_the_hold():
"""Issue #358: the reporting dryer replays a running stage after
Finish -- observed twice, identically, as Cooling -> +60s Finish ->
+24s 'Drying' -> +4s settled, with `state` already idle throughout the
tail. The hold must survive it, so the cycle still reads Drying,
Cooling, Finish, Idle rather than the reported Drying, Cooling,
Finish, Drying, Idle."""
"""Issue #358: the reporting dryer resets `progress` to its course's
first stage in the same moment `state` goes idle -- observed twice,
identically, as Cooling -> +60s Finish -> +24s 'Drying' -> +4s
settled, with the reporter's machine_state history flipping to idle on
the exact second progress reads 'Drying'. The hold must survive that,
so the cycle still reads Drying, Cooling, Finish, Idle rather than the
reported Drying, Cooling, Finish, Drying, Idle."""
desc = replace(_PROGRESS_DESC, sticky_seconds=0.2)
sensor, coordinator = _sensor(desc)