Captures the ramp/hold/user-confirm phase order and a couple of non-obvious clarifications from a design discussion (ramp is gated purely by the schedule's 'ramp' key, not actual-vs-target temp; WAIT_USER is a distinct phase, not an extended hold), plus one open gap: pure-hold steps never re-set the controller's target temperature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LhiQe64F74uHV8jzuoSa5K
2.7 KiB
components/sud.py step lifecycle spec
Confirmed spec for a Sud schedule step's internal phase order
(components/sud.py), from a design discussion clarifying how ramp/
hold/user-confirm interact.
Phase order
ramp -> hold -> user-confirm. Each step independently opts into
ramp and/or hold by including that key (_build_step(),
sud.py:35-45); the other phase is skipped entirely if its key is
absent. The 'ramp' key's presence is the only trigger for ramping
(_advance(), sud.py:192-210) - there is no diff-based decision
(T_actual vs. T_target) anywhere that decides whether to ramp, and
no internal setpoint-trajectory limiter in the temperature controller
(set_theta_soll() is an instant, unconditional assignment,
components/pid/temp_controller_base.py:81-82). The ramp key both
gates ramping and carries its settings (rate); it does not merely
override settings on top of an always-on ramp.
Duration 0
Supported for hold: hold_remaining = duration * 60.0 can be 0;
tick() (sud.py:186-190) finishes the step on the next tick once
hold_remaining <= 0.
End-of-step branching
_finish_step() (sud.py:212-216): no user_wait_for_continue ->
advances immediately to the next step; user_wait_for_continue: true
-> enters WAIT_USER, resumed only by confirm().
WAIT_USER is not "hold, prolonged": HOLDING and WAIT_USER are
distinct SudState values. The hold countdown runs to completion
before WAIT_USER begins - tick() only decrements
hold_remaining while state == HOLDING, so the timer is frozen
(not extended) during the wait. It delays the next step, but it's a
separate third phase, not a longer hold.
The gating field is user_wait_for_continue, not "presence of a user
message": user_message (display text) and user_wait_for_continue
(the actual block) are independent fields - a step can show a message
without blocking, or block silently.
Open items
- Pure-hold steps never (re-)set the controller's target
temperature. For a step with only
hold(noramp),tasks/sud.py'son_step_changednever callstc.set_theta_soll()- the guard at line 73 requires
ramp is not None. The controller's target temperature for a pure-hold step is whatever was left from the previous step's ramp; there's no explicit fallback to the hold step's owntemperaturefield.README.md(Mash schedules section) documents this as designed behavior ("SudTaskdrives ...theta_soll/heatrate_sollfrom ramp steps ... counts down hold steps' duration"), so it's intentional, not a bug - but it means a schedule can't express a temperature jump straight into a hold without arampblock.
- the guard at line 73 requires