test(session): derive watchdog instants from t0, not an accumulated local
Build / macOS (macos-latest) (push) Successful in 49s
Build / Linux (ubuntu-24.04) (push) Successful in 1m9s
Build / Windows (windows-latest) (push) Successful in 4m9s

The MSVC 19.44 x64 Release build hoists the argument of the second
poll() in a fixed-stride loop out of the loop: every iteration of

    early = w.poll(now + milliseconds(29999));
    now  += milliseconds(30000);
    fire  = w.poll(now);

handed poll() the value `now` held BEFORE the first +=. Captured on the
callee side of a noinline wrapper in CI, all six iterations received
t0+32000ms, while a checksum of the caller's own arguments in the same
loop summed to exactly 62000+92000+...+212000 -- the caller's values were
right, the values passed were not. Linux and macOS pass 62000..212000 for
the same source. That, not the backoff arithmetic, is what produced the
11 identical FAILs at test_session.cpp:327/:329 that survived two fixes
to StallWatchdog.

The watchdog is correct: in the same Windows binary, the same instants
written as t0 + milliseconds(at_ms) -- or merely copied into a named
local before the call -- answer correctly on every iteration. Production
is not exposed: watchdogLoop() polls with a fresh steady_clock::now()
each tick, not a loop-carried local. So the test moves to an integer
millisecond cursor off t0, in the shape verified on the Windows runner.

No assertion is weakened -- every gap is still checked one millisecond on
either side of its boundary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-21 11:03:49 -07:00
co-authored by Claude Opus 5
parent cd8123a4ab
commit bff59c4075
3 changed files with 63 additions and 264 deletions
-7
View File
@@ -202,13 +202,6 @@ public:
/// onFrameDelivered and by setExpectingFrames.
int attemptsThisStall() const { return attempts_; }
// TEMPORARY DEBUG ACCESSORS -- remove before merge.
long long dbgBackoffMs() const { return (long long)backoff_.count(); }
long long dbgTimeoutMs() const { return (long long)timeout_.count(); }
long long dbgMaxBackoffMs() const { return (long long)max_backoff_.count(); }
std::chrono::steady_clock::time_point dbgNextAllowed() const { return next_attempt_allowed_; }
std::chrono::steady_clock::time_point dbgBaseline() const { return baseline_; }
private:
std::chrono::milliseconds timeout_;
std::chrono::milliseconds max_backoff_;