Updated apps
This commit is contained in:
@@ -448,7 +448,7 @@ def estimate_phase_progress(
|
||||
return (best_progress, best_variance)
|
||||
|
||||
|
||||
def compute_progress(
|
||||
def _compute_progress_base(
|
||||
device_type: str,
|
||||
matched_duration: float,
|
||||
duration_so_far: float,
|
||||
@@ -549,6 +549,76 @@ def compute_progress(
|
||||
return ProgressResult(progress, smoothed, remaining, total, None, "linear")
|
||||
|
||||
|
||||
def compute_progress(
|
||||
device_type: str,
|
||||
matched_duration: float,
|
||||
duration_so_far: float,
|
||||
prev_smoothed: float,
|
||||
phase_result: tuple[float, float] | None,
|
||||
ml_pct: float | None,
|
||||
logger: logging.Logger | None = None,
|
||||
phase_remaining_s: float | None = None,
|
||||
) -> ProgressResult | None:
|
||||
"""Progress/remaining estimate, optionally blended with a phase-resolved ETA.
|
||||
|
||||
When ``phase_remaining_s`` is provided (opt-in phase matching for a supported
|
||||
device type), the phase-budget remaining is converted to a completion PERCENT
|
||||
and blended into the phase-progress signal **before** delegating to
|
||||
:func:`_compute_progress_base` - so the blend rides the proven, golden-locked
|
||||
EMA + monotonicity + back-calculation guards (design §8, "one smoothing
|
||||
implementation"), rather than re-deriving a raw, unsmoothed progress. The
|
||||
blend leans on the phase budget early (low base progress) and on the proven
|
||||
phase estimate late::
|
||||
|
||||
phase_pct = duration_so_far / (duration_so_far + phase_remaining_s) * 100
|
||||
f = base_phase_progress / 100
|
||||
blended = (1 - f) * phase_pct + f * base_phase_progress
|
||||
|
||||
Because this feeds the percent-domain smoothing, the displayed progress stays
|
||||
monotone/smoothed (no tick-to-tick jitter or collapse-to-99%), and remaining
|
||||
is re-derived by the base from ``matched_duration``.
|
||||
|
||||
Behaviour is BYTE-IDENTICAL to before when ``phase_remaining_s is None`` (the
|
||||
default) - the golden progress snapshot and every existing caller are
|
||||
unaffected. This is the single implementation of the blend; the manager and
|
||||
the Playground SimRunner both go through it.
|
||||
"""
|
||||
blended = False
|
||||
if phase_remaining_s is not None and matched_duration and matched_duration > 0:
|
||||
try:
|
||||
pr = float(phase_remaining_s)
|
||||
except (TypeError, ValueError):
|
||||
pr = float("nan")
|
||||
if math.isfinite(pr) and pr >= 0.0:
|
||||
denom = duration_so_far + pr
|
||||
phase_pct = (duration_so_far / denom * 100.0) if denom > 0 else 0.0
|
||||
phase_pct = max(0.0, min(100.0, phase_pct))
|
||||
if phase_result is not None:
|
||||
base_pp, variance = phase_result
|
||||
f = max(0.0, min(1.0, float(base_pp) / 100.0))
|
||||
phase_result = ((1.0 - f) * phase_pct + f * float(base_pp), variance)
|
||||
else:
|
||||
# No envelope phase-progress: blend the phase budget's implied
|
||||
# percent with the linear (elapsed/matched) percent, still leaning
|
||||
# on the phase budget early and the linear estimate late.
|
||||
lin_pct = max(0.0, min(100.0, duration_so_far / matched_duration * 100.0))
|
||||
f = lin_pct / 100.0
|
||||
phase_result = ((1.0 - f) * phase_pct + f * lin_pct, 0.0)
|
||||
blended = True
|
||||
|
||||
base = _compute_progress_base(
|
||||
device_type, matched_duration, duration_so_far, prev_smoothed,
|
||||
phase_result, ml_pct, logger,
|
||||
)
|
||||
if base is None or not blended:
|
||||
return base
|
||||
# Relabel the source for diagnostics; values already reflect the blend.
|
||||
return ProgressResult(
|
||||
base.progress, base.smoothed, base.remaining, base.total,
|
||||
base.phase_progress, "phase_blend",
|
||||
)
|
||||
|
||||
|
||||
def current_phase(
|
||||
store: Any,
|
||||
state: str,
|
||||
|
||||
Reference in New Issue
Block a user