{"id":"catch-up-uses-event-id-filtering","text":"`catch_up()` calls `read_all(from_position=self._position + 1)` to skip already-processed events, but `_on_event` has no equivalent position guard — an asymmetry that enables duplicate processing","truth_value":"IN","source":"entries/2026/05/29/topic-catch-up-subscription-gap.md","source_url":"","source_hash":"","justifications":[],"dependents":[],"metadata":{},"explanation":{"steps":[{"node":"catch-up-uses-event-id-filtering","truth_value":"IN","reason":"premise"}]}}