require-port-for-service
Consider a consumer-owned port when visible service structure suggests a substitution boundary.
Why
A small port can decouple consumers when they genuinely need to substitute a concrete service boundary.
Fix
When a real consumer needs substitution, define a focused consumer-owned Protocol and type that consumer against it; otherwise suppress the advisory instead of adding an unused abstraction.
Examples
class ThingService: def __init__(self, client: ThingClient) -> None: self.client = client
def read(self, key: str) -> str: return self.client.get(key)
def write(self, key: str, value: str) -> None: self.client.put(key, value)
def sync(service: ThingService) -> None: service.write("inbox", service.read("outbox"))from typing import Protocol
class ThingServicePort(Protocol): def read(self, key: str) -> str: ... def write(self, key: str, value: str) -> None: ...
class ThingService: def __init__(self, client: ThingClient) -> None: self.client = client
def read(self, key: str) -> str: return self.client.get(key)
def write(self, key: str, value: str) -> None: self.client.put(key, value)
def sync(service: ThingServicePort) -> None: service.write("inbox", service.read("outbox"))