What happened?
Ops inside the confirmation-lag / cursor-rewind window are re-scanned on each poll cycle and re-broadcast to WebSocket subscribers each time. Database writes are idempotent and the bundled frontend dedupes by hash, so first-party behavior is correct — but third-party WS consumers without their own dedup will double-count ops until the block leaves the rewind window.
Area
Backend
Expected behavior
Each op is broadcast at most once per connection — e.g. track a separate last-broadcast cursor distinct from the scan cursor, or dedupe by op hash in the hub before broadcasting.
Steps to reproduce
- Connect a raw WS client to the live feed
- Submit a UserOp and wait for it to be indexed
- Observe the same op hash delivered again on subsequent poll cycles until the block leaves the rewind window
Additional context
Found during code review. Relevant code: rescan/broadcast path in indexer/internal/indexer/indexer.go (~486-501 and ~764). Severity: low.
What happened?
Ops inside the confirmation-lag / cursor-rewind window are re-scanned on each poll cycle and re-broadcast to WebSocket subscribers each time. Database writes are idempotent and the bundled frontend dedupes by hash, so first-party behavior is correct — but third-party WS consumers without their own dedup will double-count ops until the block leaves the rewind window.
Area
Backend
Expected behavior
Each op is broadcast at most once per connection — e.g. track a separate last-broadcast cursor distinct from the scan cursor, or dedupe by op hash in the hub before broadcasting.
Steps to reproduce
Additional context
Found during code review. Relevant code: rescan/broadcast path in
indexer/internal/indexer/indexer.go(~486-501 and ~764). Severity: low.