# Component — `detection_client`

**Layer**: Perception (data plane in)
**Status**: forward-looking design (Rust)

## 1. Purpose

Bi-directional gRPC client to the external `../detections` service. Streams frames out, receives bounding-box detections back. Same bboxes are reused by `semantic_analyzer` (Tier 2 ROI selection) and by `telemetry_stream` (operator overlay). This is the only component in autopilot that talks to `../detections`.

## 2. Inputs

| Input | Source | Cadence | Notes |
|---|---|---|---|
| `Frame` | `frame_ingest` | up to 30 fps | Skipped when `ai_locked` is set. |
| Tier-1 service config | startup config | once | gRPC endpoint, TLS settings, request budget, max concurrent streams. |

## 3. Outputs

| Output | Consumer | Shape |
|---|---|---|
| `DetectionBatch` | `scan_controller`, `semantic_analyzer`, `telemetry_stream` | `{ frame_seq: u64, detections: Vec<Detection>, latency_ms, model_version }` |
| Health metric | health aggregator | gRPC connection state, `requests_in_flight`, `latency_p50/p99`, `errors_by_kind`, `model_version`. |

`Detection` mirrors the `../detections` contract: `{ class_id, class_name, confidence, bbox_normalized, optional_mask_or_polyline, source_frame_seq }`.

## 4. Key Responsibilities

- Maintain a single bi-directional gRPC stream to `../detections`. Reconnect on stream loss with bounded exponential backoff.
- Frame budgeting: respect the Tier-1 ≤100 ms/frame target by dropping older in-flight frames if a new frame arrives before the previous response (configurable).
- Validate the response payload against the schema version the client was built against. Surface a hard error on schema mismatch; do not silently downcast.
- Tag each `DetectionBatch` with the source frame's monotonic timestamp so downstream consumers can compute end-to-end latency.

## 5. Internal State

- gRPC channel, stream handle, reconnect state.
- Sliding window of in-flight frame sequence numbers.
- Last-known model version (echoed by `../detections` on each response or on stream init).

State is in-process only.

## 6. Failure Modes

| Failure | Detection | Behaviour |
|---|---|---|
| `../detections` unreachable | gRPC connect error | Bounded exponential backoff; health → red after threshold; `scan_controller` continues but the `detection_client` health flag is red. |
| Mid-stream cancellation by server | stream error | Reopen stream; do not lose frames in flight (best-effort retry on the latest only). |
| Schema mismatch | response decode error | Hard error to the health aggregator; reject the response; alert. |
| Model version change at runtime | new `model_version` on the stream | Log it; if the change implies new classes, surface to `scan_controller` so per-class thresholds can be reloaded. |
| Consistent latency above budget | `latency_p99 > 100 ms` over a sliding window | Health → yellow; `scan_controller` may degrade to alternate-frame inference. |

## 7. Dependencies

**In-process**: `frame_ingest` (input), `scan_controller` / `semantic_analyzer` / `telemetry_stream` (output).

**External**:
- `../detections` gRPC service. Contract owner: `../_docs/03_detections.md`. Bi-directional streaming.

## 8. Non-Functional Targets

| Concern | Target |
|---|---|
| Per-frame round-trip latency | ≤100 ms (Tier-1 NFR; mostly owned by `../detections`, autopilot's call budget respects it) |
| Reconnect latency | ≤2 s after `../detections` returns |
| Throughput | up to 30 fps at 1080p |
| Backpressure | drop oldest in-flight rather than queue indefinitely |

## 9. Open Questions

- Versioning strategy of the gRPC contract (covered in `architecture.md §8 Q4`).

## 10. References

- `architecture.md §1`, `§3`, `§7.6`.
- `system-flows.md §F1`.
- `../_docs/03_detections.md`.
- `data_model.md §Detection`, `§DetectionBatch`.
