Skip to content

Define DetectionSource protocol and refactor TrackerInstance #5

Description

@jonnyspicer

Summary

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.

Changes

New: DetectionSource protocol (tracker_host/detection_source.py)

class DetectionSource(Protocol):
    async def receive(self) -> Optional[dict[str, Any]]:
        """Return next detection frame, or None if no new data."""
        ...

    async def close(self) -> None: ...

    @property
    def is_healthy(self) -> bool: ...

Updated: DetectionFetcher (tracker_host/fetcher.py)

  • Rename fetch() to receive() to match the protocol
  • Add is_healthy property (returns self.state.is_healthy)
  • No other behavioral changes

Updated: TrackerInstance (tracker_host/instance.py)

  • Constructor accepts a DetectionSource instead of creating DetectionFetcher internally
  • _fetch_loop calls self.source.receive() instead of self.fetcher.fetch()
  • ExtendedOutageError handling stays the same (only DetectionFetcher raises it; TcpReceiver will use a different mechanism)

Updated: TrackerConfig (tracker_host/config.py)

  • detection_url becomes Optional[str] (currently required)
  • 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
  • TrackerInstance works with any DetectionSource
  • Existing HTTP polling behavior unchanged (all existing tests pass)
  • detection_url is optional in config
  • Mode inference works: detection_url present → http, otherwise → tcp

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions