Summary
Grind phase 28 (issue tracking forge's timeMedian extraction in scripts/token-benchmark.ts) promoted median/round1/timeMedian into a new shared scripts/lib/bench-timing.ts module and wired timeMedian into the 3 call sites that were already unconditionally async with no new async boundary needed:
scripts/incremental-benchmark.ts (worker): fullBuildMs, noopRebuildMs
scripts/benchmark.ts (worker): noopRebuildMs
5 more sites duplicate the identical "loop N times, time each run, compute median" pattern but are currently synchronous functions called without await:
scripts/query-benchmark.ts: benchDepths() (used for fnDeps/fnImpact depth-scaling timings), benchDiffImpact()
scripts/incremental-benchmark.ts (parent process): nativeBatchMs computation, jsFallbackMs computation
scripts/benchmark.ts: benchQuery()
Adopting timeMedian at these sites requires converting the enclosing functions to async and threading await through their call sites — a control-flow change, not a mechanical adoption, per the titan-grind skill's "never change control flow" rule. It's also worth verifying end-to-end (these are timing-sensitive benchmark scripts with documented cold-start/warmup sensitivity — see comments in query-benchmark.ts around WARMUP_RUNS and incremental-benchmark.ts/benchmark.ts's references to #1076/#1077/#1113) that adding microtask overhead per timed iteration doesn't perturb measured latencies.
Two more sites (incremental-benchmark.ts's and benchmark.ts's "1-file rebuild" measurement) compute a median-by-timestamp over {ms, phases} pairs (need the phases of the median run, not just the numeric median) — timeMedian's current signature (() => unknown returning only a number) can't carry that side data, so adopting it there would require extending the helper's API, which is more of a forge-shaped change.
Suggested follow-up
Either:
- Convert the 5 sync sites to async and adopt
timeMedian directly (verify no benchmark methodology regression), or
- Extend
timeMedian's API (e.g. an overload/variant that returns {ms, value} pairs sorted by timing) to also cover the 2 side-data sites, then adopt across all 7.
scripts/lib/bench-timing.ts already has median/round1 available for reuse in either approach.
Summary
Grind phase 28 (issue tracking forge's
timeMedianextraction inscripts/token-benchmark.ts) promotedmedian/round1/timeMedianinto a new sharedscripts/lib/bench-timing.tsmodule and wiredtimeMedianinto the 3 call sites that were already unconditionally async with no new async boundary needed:scripts/incremental-benchmark.ts(worker):fullBuildMs,noopRebuildMsscripts/benchmark.ts(worker):noopRebuildMs5 more sites duplicate the identical "loop N times, time each run, compute median" pattern but are currently synchronous functions called without
await:scripts/query-benchmark.ts:benchDepths()(used forfnDeps/fnImpactdepth-scaling timings),benchDiffImpact()scripts/incremental-benchmark.ts(parent process):nativeBatchMscomputation,jsFallbackMscomputationscripts/benchmark.ts:benchQuery()Adopting
timeMedianat these sites requires converting the enclosing functions toasyncand threadingawaitthrough their call sites — a control-flow change, not a mechanical adoption, per the titan-grind skill's "never change control flow" rule. It's also worth verifying end-to-end (these are timing-sensitive benchmark scripts with documented cold-start/warmup sensitivity — see comments inquery-benchmark.tsaroundWARMUP_RUNSandincremental-benchmark.ts/benchmark.ts's references to #1076/#1077/#1113) that adding microtask overhead per timed iteration doesn't perturb measured latencies.Two more sites (
incremental-benchmark.ts's andbenchmark.ts's "1-file rebuild" measurement) compute a median-by-timestamp over{ms, phases}pairs (need thephasesof the median run, not just the numeric median) —timeMedian's current signature (() => unknownreturning only a number) can't carry that side data, so adopting it there would require extending the helper's API, which is more of a forge-shaped change.Suggested follow-up
Either:
timeMediandirectly (verify no benchmark methodology regression), ortimeMedian's API (e.g. an overload/variant that returns{ms, value}pairs sorted by timing) to also cover the 2 side-data sites, then adopt across all 7.scripts/lib/bench-timing.tsalready hasmedian/round1available for reuse in either approach.