Skip to content

WS: server-side seq reset silently dispatches subsequent messages (no gap fired) #196

Description

@TexasCoding

Summary

When the server resets sequence numbers on the same sid (server restart that preserves sid, or any out-of-band reset), incoming seq <= last is logged at DEBUG and track() returns True without updating _last_seq. The message is dispatched normally, the orderbook applies the delta, but the tracker stays pinned at the pre-reset high-water mark.

Every subsequent message until seq again exceeds the old mark is treated as a "duplicate-but-still-dispatched" — no gap is ever fired, the orderbook silently applies a stream of supposedly-old deltas, and the consumer has no signal that anything happened. The recv path silently consumes potentially many messages with no integrity guarantee.

True duplicates (seq == last) should be DROPPED rather than dispatched-and-not-tracked, to avoid double-applying a delta to the orderbook.

Location

kalshi/ws/sequence.py:62-65

Evidence

# kalshi/ws/sequence.py:62-65
if seq <= last:
    # Duplicate or old message, skip
    logger.debug("Duplicate seq %d for sid %d (last=%d)", seq, sid, last)
    return True   # ← dispatches the message but does NOT update _last_seq

Recommended fix

Distinguish three cases:

  1. seq == last (true duplicate) — drop the message: return False so dispatch skips. Log at debug.
  2. seq == last - 1 to seq == last - small_window (within a normal out-of-order window, if such a thing exists for Kalshi) — drop the message: return False. Log at debug.
  3. seq < last - threshold OR seq == 1 while last > 1 (server-side reset / sid reused) — trigger the gap-handler path: clear local state, reset tracker, fire on_gap with a special kind='reset' marker, and (per the separate orderbook resync issue) drive a resubscribe.

Add tests:

  • test_seq_equal_to_last_dropped_not_dispatched
  • test_seq_below_last_triggers_reset_recovery
  • test_seq_1_after_high_watermark_treated_as_reset

Severity & category

high / correctness, ws

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwsWebSocket-related

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions