You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extract a common DetectionSource protocol from DetectionFetcher and refactor TrackerInstance to use it, enabling pluggable detection sources (HTTP polling or TCP push).
Context
TrackerInstance currently creates a DetectionFetcher directly and calls self.fetcher.fetch() in its fetch loop. To support TCP push alongside HTTP polling, the instance needs to accept either source type interchangeably.
See design spec: docs/superpowers/specs/2026-03-11-tcp-push-detection-forwarding-design.md in the retina monorepo.
classDetectionSource(Protocol):
asyncdefreceive(self) ->Optional[dict[str, Any]]:
"""Return next detection frame, or None if no new data."""
...
asyncdefclose(self) ->None: ...
@propertydefis_healthy(self) ->bool: ...
Add mode: Optional[str] — inferred as "http" if detection_url present, otherwise "tcp"
Add node_id: Optional[str] — required for mode: "tcp" entries
Updated: TrackerManager (tracker_host/manager.py)
Creates DetectionFetcher-backed instances for mode: "http" trackers
Creates instances without a source for mode: "tcp" trackers (source will be attached later when the TCP server integration is added in a follow-up issue)
Acceptance criteria
DetectionSource protocol defined
DetectionFetcher conforms to DetectionSource protocol
Summary
Extract a common
DetectionSourceprotocol fromDetectionFetcherand refactorTrackerInstanceto use it, enabling pluggable detection sources (HTTP polling or TCP push).Context
TrackerInstancecurrently creates aDetectionFetcherdirectly and callsself.fetcher.fetch()in its fetch loop. To support TCP push alongside HTTP polling, the instance needs to accept either source type interchangeably.See design spec:
docs/superpowers/specs/2026-03-11-tcp-push-detection-forwarding-design.mdin the retina monorepo.Changes
New:
DetectionSourceprotocol (tracker_host/detection_source.py)Updated:
DetectionFetcher(tracker_host/fetcher.py)fetch()toreceive()to match the protocolis_healthyproperty (returnsself.state.is_healthy)Updated:
TrackerInstance(tracker_host/instance.py)DetectionSourceinstead of creatingDetectionFetcherinternally_fetch_loopcallsself.source.receive()instead ofself.fetcher.fetch()ExtendedOutageErrorhandling stays the same (onlyDetectionFetcherraises it;TcpReceiverwill use a different mechanism)Updated:
TrackerConfig(tracker_host/config.py)detection_urlbecomesOptional[str](currently required)mode: Optional[str]— inferred as"http"ifdetection_urlpresent, otherwise"tcp"node_id: Optional[str]— required formode: "tcp"entriesUpdated:
TrackerManager(tracker_host/manager.py)DetectionFetcher-backed instances formode: "http"trackersmode: "tcp"trackers (source will be attached later when the TCP server integration is added in a follow-up issue)Acceptance criteria
DetectionSourceprotocol definedDetectionFetcherconforms toDetectionSourceprotocolTrackerInstanceworks with anyDetectionSourcedetection_urlis optional in configdetection_urlpresent → http, otherwise → tcp