fraction method
0..1. Time-based against the estimate while running (builds give no finer signal), never below the share of targets already built, and slowing down instead of hitting 100% when a build overruns.
Implementation
double fraction(DateTime now) {
switch (state) {
case JobState.queued:
return 0;
case JobState.succeeded:
case JobState.failed:
case JobState.skipped:
return 1;
case JobState.running:
final est = math.max(estimate.inMilliseconds, 1);
final ms = elapsed(now).inMilliseconds;
final byTime = ms <= est ? 0.9 * ms / est : 0.9 + 0.09 * (1 - est / ms);
final byTargets = 0.99 * targetsDone / job.targets.length;
return math.min(math.max(byTime, byTargets), 0.99);
}
}