Health: count only flows the engine acts on, format durations with their unit
The "running" tile counted paused and invalid flows as running, so it read "5/5" beside "1 flow(s) cannot run". Its note is now additive rather than a precedence chain, so a quarantine no longer hides the invalid count. Adds dur() beside si(): a ms reading picks its own unit, so a slow run reads "1.24 s" instead of "1.2k ms". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HTsT1isxUjw5gtkJk8WhuA
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* The cases `si` gets wrong when its rounding is written the obvious way.
|
||||
* The cases `si` and `dur` get wrong when their rounding is written the
|
||||
* obvious way.
|
||||
*
|
||||
* Run: `bun src/lib/utils.check.ts` (there is no unit runner; the suite in
|
||||
* `tests/` drives a running stack).
|
||||
*/
|
||||
import assert from "node:assert/strict"
|
||||
|
||||
import { si } from "./utils"
|
||||
import { dur, si } from "./utils"
|
||||
|
||||
// Nothing is prefixed in the plain window: these are written with a unit after
|
||||
// them, and "400m ms" is not an improvement on "0.4 ms".
|
||||
@@ -30,3 +31,22 @@ assert.notEqual(si(1234, 4), si(1235, 4))
|
||||
assert.equal(si(Number.NaN), "--")
|
||||
|
||||
console.log("si: ok")
|
||||
|
||||
// The unit follows the size, so no reading is left as a shortened number in
|
||||
// front of a unit the call site guessed.
|
||||
assert.equal(dur(0), "0 ms")
|
||||
assert.equal(dur(203.63), "204 ms")
|
||||
assert.equal(dur(1240), "1.24 s")
|
||||
assert.equal(dur(90_000), "1.5 min")
|
||||
|
||||
// The plain window down to 0.01 ms, so a fast run keeps one unit across polls.
|
||||
assert.equal(dur(0.4), "0.4 ms")
|
||||
assert.equal(dur(0.0031, 4), "3.1 µs")
|
||||
|
||||
// Rounding must not leave a value in the step it just rounded out of.
|
||||
assert.equal(dur(999.7), "1 s")
|
||||
assert.equal(dur(59_999), "1 min")
|
||||
|
||||
assert.equal(dur(Number.NaN), "--")
|
||||
|
||||
console.log("dur: ok")
|
||||
|
||||
@@ -41,3 +41,38 @@ export function si(value: number, digits = 3): string {
|
||||
const [factor, suffix] = SI_STEPS.find(([step]) => size >= step) ?? [1, ""]
|
||||
return `${Number((rounded / factor).toPrecision(digits))}${suffix}`
|
||||
}
|
||||
|
||||
/** Floor, divisor and unit per step, largest first. */
|
||||
const DUR_STEPS: [number, number, string][] = [
|
||||
[60_000, 60_000, "min"],
|
||||
[1_000, 1_000, "s"],
|
||||
[0.01, 1, "ms"],
|
||||
[0, 1e-3, "µs"],
|
||||
]
|
||||
|
||||
/**
|
||||
* A duration in milliseconds at `digits` significant digits, carrying the unit
|
||||
* it picked: 1240 → "1.24 s", 90000 → "1.5 min", 203.63 → "204 ms".
|
||||
*
|
||||
* Unlike `si` the unit is not the caller's to write. Shortening the number in
|
||||
* front of a fixed " ms" gives "1.2k ms", which is a duration nobody reads —
|
||||
* so the step moves the unit instead, and the value is rounded before that
|
||||
* step is picked, so 999.7 reads "1 s" rather than "1000 ms".
|
||||
*
|
||||
* Below a millisecond it holds down to 0.01, which is `si`'s own plain-number
|
||||
* window transposed onto units. That floor is deliberate: without it a tile
|
||||
* polled every ten seconds flips between "400 µs" and "1.2 ms", and a reading
|
||||
* that changes unit on every poll reads as broken rather than as fast.
|
||||
*/
|
||||
export function dur(ms: number, digits = 3): string {
|
||||
if (!Number.isFinite(ms)) return "--"
|
||||
const rounded = Number(ms.toPrecision(digits))
|
||||
const size = Math.abs(rounded)
|
||||
if (size === 0) return "0 ms"
|
||||
const [, factor, unit] = DUR_STEPS.find(([floor]) => size >= floor) ?? [
|
||||
0,
|
||||
1,
|
||||
"ms",
|
||||
]
|
||||
return `${Number((rounded / factor).toPrecision(digits))} ${unit}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user