Updated apps

This commit is contained in:
2026-07-20 22:52:35 -04:00
parent 28a8cb98f6
commit a0c3271743
1164 changed files with 94781 additions and 6892 deletions
+71 -1
View File
@@ -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,