authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-02-07 02:14:09-08:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-17 23:21:58-07:00
log6d7576c0766ee4fd023aae3db1fc4ca9f35e9791
tree1d7aa66df6b65a5d8f68e285c651d533e6041b40
parent3b6fe249342235df612779f0593fccb3ee54970a
signature Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

fix: progress estimation interface update

resolves #76 the interface for progress reporting isnt able to identify when more items are added, which causes places like clover file scanner to report badly as it initializes near 90% then goes backwards to 40% (it is increasing both values). so both numbers are passed.

1 files changed, 19 insertions(+), 22 deletions(-)

lib/progress.ts+19-22
......@@ -453,7 +453,7 @@ function newNode<Result, EventMap extends Events.Map>(
453453 estimator = estimateCompletion;
454454 } else estimator = new Ema();
455455 }
456 estimator?.sample(Date.now(), 0);
456 estimator?.sample(Date.now(), 0, 0);
457457
458458 function mutate(key: keyof ReadOnlyNode) {
459459 if (state.detached) return;
......@@ -464,7 +464,7 @@ function newNode<Result, EventMap extends Events.Map>(
464464 // originally, auto-estimation would use the Root's timing primitives,
465465 // but this makes it so that `state.estimatedTime` is in terms of the
466466 // Root, which is unintuitive for everyone but the renderer.
467 const time = estimator.sample(Date.now(), state.value / state.total);
467 const time = estimator.sample(Date.now(), state.value, state.total);
468468 if (time && (!state.estimatedTime || state.estimatedTime !== time)) {
469469 state.estimatedTime = time;
470470 owner.emit("node-change", state, "estimatedTime");
......@@ -1671,9 +1671,10 @@ class KeyPool<T extends number> {
16711671export interface EstimationAlgorithm {
16721672 /**
16731673 * given a timestamp `time` and a progress value `progress`, return the
1674 * timestamp that the action will be finished on.
1674 * timestamp that the action will be finished on. called with (t, 0, 0)
1675 * to initialize the algorithm.
16751676 */
1676 sample(time: number, progress: number): number | null;
1677 sample(time: number, current: number, total: number): number | null;
16771678}
16781679
16791680/**
......@@ -1685,33 +1686,29 @@ export class Ema implements EstimationAlgorithm {
16851686 start: number | null = null;
16861687 estimate: number | null = null;
16871688 /** smoothing factor (0-1) */
1688 alpha: number = 0.25;
1689 alpha: number;
16891690
1690 constructor(alpha: number = 0.1) {
1691 constructor(alpha: number = 0.25) {
16911692 this.alpha = alpha;
16921693 }
16931694
1694 /**
1695 * given a timestamp `time` and a progress value `progress`, return the
1696 * timestamp that the action will be finished on.
1697 */
1698 sample(time: number, progress: number): number | null {
1699 ASSERT(
1700 progress >= 0 && progress < 1,
1701 `progress must be a number between 0 and 1, got ${progress}`,
1702 );
1703 if (this.start == null) {
1695 sample(time: number, current: number, total: number): number | null {
1696 ASSERT(current >= 0 && current <= total);
1697 if (this.start == null || current === 0) {
17041698 this.start = time;
1699 this.estimate = null;
17051700 return null;
17061701 }
17071702
1708 const value = (time - this.start) / progress;
1709 this.estimate = this.estimate != null
1710 ? ((1 - this.alpha) * this.estimate +
1711 this.alpha * value)
1712 : value;
1703 const elapsed = time - this.start;
1704 if (elapsed === 0) return null; // too quick
17131705
1714 return time + (1 - progress) * this.estimate;
1706 const rate = current / elapsed;
1707 this.estimate = this.estimate != null
1708 ? (1 - this.alpha) * this.estimate + this.alpha * rate
1709 : rate;
1710 const remaining = total - current;
1711 return time + remaining / this.estimate;
17151712 }
17161713
17171714 reset(): void {