test(stream-consumer): fix monotonic-epoch flake blocking fork CI - #32
Merged
Merged
Conversation
Backport of the fix proposed upstream in NousResearch#78107, applied here so this fork's CI stops failing slice 8/8 on every PR while that one is in review. `stream_consumer.py:1718` computes preview age as `time.monotonic() - self._message_created_ts`. monotonic()'s epoch is arbitrary (on Linux, boot), so setting `_message_created_ts = 0.0` does not mean "long ago" — it means "monotonic() seconds ago". On a freshly-booted runner that is a handful of seconds, so the age falls under the 60s threshold, fresh-final never fires, and `adapter.send.call_count` is 1 instead of 2. That is why it is intermittent: it passed on #26/#27/#28/#29 and failed on #25 and #30, purely as a function of runner uptime. Fixed by anchoring to the same clock the production code reads. No assertion weakened, no production code changed. Verified: 10/10 in the file; and with time.monotonic patched to 12.0 to simulate a host booted 12 seconds ago, the test passes where the old form fails at line 79 — the exact CI failure. Touches only tests/, so it does not trip the ci-reviewed workflow gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Ready to approve
The change is a targeted, production-faithful test fix that removes a confirmed nondeterminism without weakening assertions or altering runtime behavior.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Fixes a CI-only flake in the stream-consumer “fresh final” regression tests by ensuring the test’s notion of an “old preview” uses the same clock as the production code (time.monotonic()), avoiding dependence on runner uptime.
Changes:
- Add a monotonic-time based helper (
_stale_ts) and constant to generate a reliably “old”_message_created_ts. - Replace
consumer._message_created_ts = 0.0in affected tests with_stale_ts()to make the age gate deterministic across hosts.
File summaries
| File | Description |
|---|---|
| tests/gateway/test_stream_consumer_fresh_final.py | Makes “preview is old” setup monotonic-clock-correct to eliminate uptime-based test flakiness. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 0
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
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.
Why this exists
Backport of NousResearch/hermes-agent#78107, applied here so this fork's CI stops failing
slice 8/8on every PR while the upstream one is in review. #30 is currently blocked by exactly this.The bug
gateway/stream_consumer.py:1718computes preview age as:monotonic()'s epoch is arbitrary — on Linux, boot. So_message_created_ts = 0.0does not mean "long ago"; it means "monotonic()seconds ago". On a freshly-booted runner that's a handful of seconds, the age falls under the 60s threshold, fresh-final never fires, andadapter.send.call_countis 1 instead of 2.That explains the intermittency exactly: passed on #26/#27/#28/#29, failed on #25 and #30 — purely a function of runner uptime, not randomness. I originally wrote it off as a flake and re-ran it; that was wrong.
Verification
time.monotonicpatched to12.0, simulating a host booted 12 seconds ago: the fix passes where the old form fails at line 79 — the exact CI failureNo assertion weakened, no production code changed (production is correct — only the test's notion of "old" was wrong).
Note on the label gate
This touches only
tests/, so it does not trip theci-reviewedgate and can merge without a label. #30 does touch.github/workflows/**and still needs one.🤖 Generated with Claude Code