Forecast a Sud schedule through its confirm steps, not just up to the first one

A user_wait_for_continue step used to stop SudForecastEstimator.estimate()
dead, so the GUI's forecast plot only ever showed the first segment on Load.
Model the wait as a zero-delay auto-confirm instead, so the whole schedule's
projected curve is visible right away; correct that assumption piecewise as
real confirmations actually happen, anchored at the real elapsed time and
temperature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk
This commit is contained in:
2026-06-22 17:12:19 +02:00
co-authored by Claude Sonnet 4.6
parent 6e5fd23ccb
commit 84b1607c78
4 changed files with 144 additions and 123 deletions
+18 -14
View File
@@ -294,20 +294,24 @@ re-anchoring itself to match whatever's actually happening would no longer
be a meaningful baseline to compare reality against. It's computed once,
up front, and left alone.
The one exception is a step with `user_wait_for_continue`: a human's
response time genuinely can't be forecast, so `SudForecastEstimator.
estimate()` simply stops simulating there instead of assuming a delay (the
old behavior - zero delay - quietly understated the schedule). The
forecast is therefore piecewise: `tasks/sud.py`'s `SudTask` sends the first
segment (up to the first such step, or the end of the schedule if there is
none) on Load, marking it `Finished: false` if it stopped early. The *next*
segment is only computed once the real confirmation actually happens,
anchored at the real elapsed time and real current temperature at that
moment - so the unforecastable wait shows up honestly as a gap in the
timeline rather than as a guess - and appended to what's already shown.
While waiting, the GUI just repeats the forecast's last value out to "now"
(`SudForecastPlot.extend_forecast_while_waiting()`) rather than leaving a
visual gap, then snaps to the new segment the moment it arrives.
The one wrinkle is a step with `user_wait_for_continue`: a human's response
time genuinely can't be forecast. Rather than stall the whole estimate
there, `SudForecastEstimator.estimate()` models it as a zero-delay
auto-confirm and keeps simulating straight through to the schedule's actual
end - so the full projected curve is visible right away on Load, instead of
stopping at the first such step. `estimate()` also returns `confirm_points`:
where (in step index and simulated time) each of those zero-delay
assumptions was made.
That assumption gets corrected once the real confirmation actually
happens: `tasks/sud.py`'s `SudTask._continue_forecast_after_confirm()`
looks up the relevant `confirm_points` entry, truncates the forecast right
back to that point, and splices in a freshly anchored simulation of the
remaining steps - anchored at the real elapsed time and real current
temperature, so an actual delay shows up honestly as a gap in the timeline
rather than as the assumed zero. The corrected forecast is sent in full
each time, so the GUI's `SudForecastPlot.show_forecast()` simply redraws
the dashed line outright rather than patching it up itself.
Comparing the two lines: real-world divergence from the forecast - more
than a transient blip during a ramp's settling - is worth investigating as