Conversation
…ing sleeps (#357, #384) TestReconciler_SafetyNetSilencedByRecentDirectEvidence was a coin flip on Windows. It injected direct evidence, slept 35ms, then required that less than FallbackAfter (50ms) had passed -- 15ms of slack against a platform whose default timer granularity is ~15.6ms and whose time.Sleep rounds up to the next tick. One tick of overshoot inverted the assertion. Linux's ~1ms timers hid it, so it only ever failed on the Windows leg, on PRs that had not touched cmd/waired-agent at all (#355, #367, and again here). Both issues asked for the seam rather than a wider window, and CLAUDE.md §Test discipline says the same: put the seam below the behaviour under test. Widening only moves the coin toss. The reconciler turns out to need a very small one. It reaches for the wall clock in exactly two places -- Apply and Tick -- because every disco-driven decision is already stamped from the event's own At (evaluateSwitchLocked takes e.At). So a single `now func() time.Time`, defaulted to time.Now in newReconciler, covers the entire surface. With it, all seven time.Sleep calls in reconcile_test.go are gone: * the five Apply/Tick-timed tests install the fakeClock that setup_desired_test.go already defines for the setup executor, and say the elapsed time exactly rather than approximating it; * TestReconciler_NoFlapWithinDwellTime needed no seam at all -- dwell is measured from lastSwitchAt, which its own event stamped, so it just passes a later At. Of those seven, only the two in the safety-net silencing test were ever at risk: the rest sleep PAST a threshold and want it crossed, so overshoot was harmless. They are converted for determinism, not because they were failing. #357 asked for exactly that sweep. Package tests drop from ~0.5s of real sleeping to 0.27s. Verified the tests did not go green for the wrong reason -- each one still fails with its subject behaviour removed: * silencing rule (reconcile.go:841) neutralised -> SafetyNetSilenced fails * handshake gate (:847) neutralised -> StaysDirectIfHandshake fails * dwell gate (:512) neutralised -> NoFlapWithinDwellTime fails * safety net forced to never fire (:835) -> both firing tests fail TestNewReconcilerHasAClock pins the production wiring: a constructor path that forgets the clock would not fail any timing test (those install their own) -- it would nil-panic in Apply on a real agent. Verified: go build ./..., go vet, gofmt, golangci-lint (0 issues), TestReconciler_* at -count=30. Fixes #357 Fixes #384 Signed-off-by: gen16k <gen16k@gmail.com>
gen16k
force-pushed
the
test/357-reconciler-clock-seam
branch
from
August 2, 2026 06:57
de54217 to
b66c895
Compare
Contributor
Author
|
Closing as a duplicate of #395, which landed on #395 is the better change and it, not this, should stand:
The only delta left here is converting the five remaining |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TestReconciler_SafetyNetSilencedByRecentDirectEvidenceis a coin flip onWindows. It injects direct evidence, sleeps 35 ms, then requires that less than
FallbackAfter(50 ms) has passed — 15 ms of slack against a platform whosedefault timer granularity is ~15.6 ms and whose
time.Sleeprounds up to thenext tick. One tick of overshoot inverts the assertion. Linux's ~1 ms timers
hide it, so it only ever fails on the Windows leg, on PRs that never touched
cmd/waired-agent— #355, #367, and twice in a row just now on #389.Both #357 and #384 asked for a clock seam rather than a wider window, and
CLAUDE.md §Test discipline says the same thing ("put the seam below the
behaviour under test"). Widening only moves the coin toss.
The seam is small
The reconciler reaches for the wall clock in exactly two places —
Applyand
Tick. Every disco-driven decision is already stamped from the event's ownAt(evaluateSwitchLocked(st, e.At, …)), so onenow func() time.Time,defaulted to
time.NowinnewReconciler, covers the entire surface.Production wiring is unchanged in behaviour; the field is read under the same
mutex that already guards
Apply/Tick.What that buys
All seven
time.Sleepcalls inreconcile_test.goare gone:Apply/Tick-timed tests install thefakeClockthatsetup_desired_test.goalready defines for the setup executor, and state theelapsed time exactly instead of approximating it;
TestReconciler_NoFlapWithinDwellTimeneeded no seam at all — dwell ismeasured from
lastSwitchAt, which its own event stamped, so it just passes alater
At.Of the seven, only the two in the silencing test were ever at risk: the rest
sleep past a threshold and want it crossed, so overshoot was harmless. They
are converted for determinism, not because they were failing — #357 asked for
exactly that sweep of the siblings. Package tests drop from ~0.5 s of real
sleeping to 0.27 s.
The tests did not go green for the wrong reason
#384 set this bar explicitly (citing #368). Each converted test still fails with
its subject behaviour removed:
reconcile.go:841) neutralisedSafetyNetSilencedByRecentDirectEvidence:847) neutralisedStaysDirectIfHandshakeSucceeds:512) neutralisedNoFlapWithinDwellTime:835)SafetyNetFiresWhenProbesSilent+ColdStartUsesSafetyNetTestNewReconcilerHasAClockpins the production wiring: a constructor path thatforgets the clock would not fail any timing test — those install their own — it
would nil-panic in
Applyon a real agent.Verification
go build ./...,go vet,gofmt,golangci-lint(0 issues),TestReconciler_*at-count=30.-racenot run locally (no cgo toolchain onthis box); CI covers it.
docs-not-needed: test-only seam plus a private struct field; no user-visible surface changes.
Fixes #357
Fixes #384