Skip to content

eta: the estimate clamps to exactly 2 hours and presents it as a real number #85

Description

@LeyckerS

Reported from a real run: the ETA showed ~4-5 minutes, jumped to 2 hours for a few seconds, came back to 2-3 minutes, then oscillated — 2.10, then 1.99, then 2.22 — before settling. On a second run it swung from 5 hours to 2 minutes and then to --.

Two separate causes, both in Engine.snapshot() (moon_engine.py:586-591).

1. The 2 hours is a clamp, not an estimate

eta = min(files_remaining * avg_file / (mbs * 1_048_576), 7200)

7200 seconds is exactly 2 hours. Whenever the computation blows up — which it does early in a run, when mbs is momentarily tiny — the result is clamped and the GUI renders it as "2h", indistinguishable from a genuine estimate. The operator sees a confident, precise, wrong number.

A clamped value means "I don't know". It should be displayed as unknown (--), the same as the eta = 0.0 branch already is, not as its ceiling.

2. The estimate is built on a badly skewed average early on

avg_file = total_downloaded / dl_done

total_downloaded sums bytes from every file including the ones still in flight, while dl_done counts only the ones that finished. Early in a run — say 40 files downloading, 2 finished — this divides 40 files' worth of bytes by 2, so avg_file is wildly overestimated and the ETA with it. That is the "5 hours" reading.

3. The oscillation

mbs comes from a 3-second window:

recent = [(t, b) for t, b in snap if t > now - 3.0]

Three seconds is short enough that normal chunk-arrival jitter moves the ETA visibly every refresh. 2.10 → 1.99 → 2.22 is that noise, not the estimate genuinely changing.

What to do

  • Return None (rendered --) when the estimate is clamped or not yet meaningful, instead of the ceiling
  • Compute avg_file from completed files only, or from bytes_total / (dl_done + partial progress of in-flight files) — either is defensible, say which you chose
  • Smooth the rate used for the ETA over a longer window than the 3 seconds used for the live speed display, or apply an exponential moving average. The displayed speed should stay responsive; the ETA does not need to be

Acceptance criteria

  • No run ever displays exactly "2h" as a result of the clamp
  • The ETA does not visibly jitter every refresh once a run is in steady state
  • The live speed readout stays as responsive as it is today

tests/test_snapshot.py is the place for the regression tests, and #57 is adding contract tests there already — coordinate if both are in flight.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinghelp wantedExtra attention is needed

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions