From 11fa6ba58c688aafcbfa4bf46dda1557d4e2827d Mon Sep 17 00:00:00 2001 From: Steve Shreeve Date: Tue, 22 Sep 2026 18:06:21 -0600 Subject: [PATCH] scripts: a lane that starts between two ticks of the live runner has spent nothing yet, so its bar, its color and the run's share stay in range --- packages/tui/test/live.rip | 11 +++++++++++ scripts/test-live.rip | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/tui/test/live.rip b/packages/tui/test/live.rip index 4d290297..e999b9fe 100644 --- a/packages/tui/test/live.rip +++ b/packages/tui/test/live.rip @@ -104,6 +104,17 @@ test "lanes in flight: a spinner, the name, a bar against the last run — by ti styledRow = cells.styled(view.ansi)[4] ok styledRow.startsWith(' «#22d3ee»⠹«» root (extended tier) «#2cd6d4»█████████▋«dim»────'), "the bar is 24% of the way from cyan to green: #{styledRow}" +test "a lane that starts between two ticks has spent nothing yet: its bar is empty and its colors are colors", -> + board MEMORY(), ({ view, tally, hear, lanes }) -> + hear 0, { type: 'plan' }, { type: 'finish', result: { lane: lanes[3], status: 'skip', ms: 0, why: lanes[3].skip, output: '' } }, { type: 'start', lane: lanes[0] } + # The lanes' clock moves on and a lane starts before the board's next + # tick, so the board's time is older than the lane's start. + tally.now = -> 8000 + tally.hear { type: 'start', lane: lanes[1] } + frame = rows view.frame() + ok frame.some((row) -> row.includes('packages/sites')), frame.join '\n' + ok not /#[0-9a-f]{7}/.test(view.ansi), 'no color of seven digits' + test "a lane past its last duration turns amber, and red past twice it; a first run sweeps a bar with nothing to fill it by", -> board MEMORY(), ({ view, hear, lanes }) -> hear 0, { type: 'plan' }, { type: 'start', lane: lanes[0] } diff --git a/scripts/test-live.rip b/scripts/test-live.rip index dabf448f..4dab6c01 100644 --- a/scripts/test-live.rip +++ b/scripts/test-live.rip @@ -50,6 +50,7 @@ hue =! (name) -> if screen.colors >= 256 then HUES[name] else NAMED[name] # A true color `t` of the way from one to the other. blend =! (from, to, t) -> + t = Math.min 1, Math.max(0, t) mix = (k) -> Math.round(parseInt(from.slice(k, k + 2), 16) * (1 - t) + parseInt(to.slice(k, k + 2), 16) * t) '#' + ((mix(k).toString(16).padStart 2, '0') for k in [1, 3, 5]).join '' @@ -228,7 +229,7 @@ export class Tally return null unless weight total += weight done += weight if entry.result - done += Math.min(now - entry.at, weight) if entry.status is 'running' + done += Math.min(Math.max(0, now - entry.at), weight) if entry.status is 'running' if total then done / total else null # ── The memory of the last run ──────────────────────────────────────────────── @@ -376,7 +377,9 @@ export Board = component running ~= for entry in @tally.entries when entry.status is 'running' - spent = now - entry.at + # `now` is taken once a tick and a lane's start as it arrives, so a + # lane that starts between two ticks has spent nothing yet. + spent = Math.max 0, now - entry.at weight = @tally.estimate entry.lane.label counts = @tally.counted entry.lane.label record = @tally.memory.lanes[entry.lane.label]