fix(campaign): record both clocks a run was measured on

Duration came from the monotonic clock, which does not advance while a host
sleeps: one calibration run under-reported by about 15 minutes. A run now
carries monotonic_millis for how long it worked and wall_clock_millis for how
much time passed, which is what makes a sleep visible at all.

Claude-Session: https://claude.ai/code/session_01A5KmftdEJ49A9z5mF5ESrX
This commit is contained in:
pj committed 2026-08-14 17:43:12 +05:30
1 parent 95a474339e
commit c63a2e4897
2 files changed
+86 -15

No files matched your search

@@ -69,6 +69,51 @@ func writeFakeRun(t *testing.T, arguments []string, steps []trace.Step) {
writeRunDirectory(t, argumentValue(arguments, "--output"), "20260101-000000", steps)
}
// readings hands out the given instants in turn, so a test can script a clock
// that jumps across a host sleep independently of one that stops through it.
func readings(instants ...time.Time) func() time.Time {
var index int
return func() time.Time {
instant := instants[min(index, len(instants)-1)]
index++
return instant
}
}
// A sleeping host stops the monotonic clock and not the wall clock, so a run
// timed on the monotonic clock alone reports the sleep as time that never
// passed. The record carries both, named for the clock each came from.
func TestRunSeed_RecordsTheTimeWorkedAndTheTimeThatPassed(t *testing.T) {
directory := t.TempDir()
startedAt := time.Date(2026, 8, 14, 2, 0, 0, 0, time.UTC)
var records bytes.Buffer
sweep := &campaign{
configuration: testConfiguration(t, directory, "--seeds", "1"),
executor: func(context.Context, string, []string, io.Writer) (int, error) {
return 0, nil
},
stdout: io.Discard,
records: &records,
clocks: clocks{
monotonicNow: readings(startedAt, startedAt.Add(2*time.Minute)),
wallClockNow: readings(startedAt, startedAt.Add(17*time.Minute)),
},
}
sweep.report(sweep.runSeed(context.Background(), 1, ""))
var written map[string]any
if err := json.Unmarshal(records.Bytes(), &written); err != nil {
t.Fatalf("decode %q: %v", records.String(), err)
}
if written["monotonic_millis"] != float64((2 * time.Minute).Milliseconds()) {
t.Errorf("monotonic_millis %v, want the two minutes of work", written["monotonic_millis"])
}
if written["wall_clock_millis"] != float64((17 * time.Minute).Milliseconds()) {
t.Errorf("wall_clock_millis %v, want the seventeen minutes that passed", written["wall_clock_millis"])
}
}
func TestRunCampaign_RecordsDispatchedActionsNotSteps(t *testing.T) {
directory := t.TempDir()
configuration := testConfiguration(t, directory, "--seeds", "1")