mirror of
https://github.com/azaion/autopilot.git
synced 2026-06-21 09:51:10 +00:00
[AZ-659] [AZ-660] [AZ-661] Implement frame publisher + gRPC detection client
AZ-659: FramePublisher with per-consumer drop accounting (Arc<Bytes> zero-copy fan-out). Adds ConsumerId enum, PublisherStats, FrameReceiver wrapper, and publisher integration tests (AC-1, AC-2, AC-3). AZ-660: Bi-directional tonic gRPC stream to ../detections. Reconnect with bounded exponential backoff (1 s → 30 s cap). Drop-oldest in-flight budgeting (max_concurrent_in_flight = 2). ai_locked frame skipping. Integration tests against fixture in-process server (AC-1: happy path 30 fps/10 s, AC-2: reconnect, AC-3: budget drops, AC-4: ai_locked skipping). AZ-661: Schema validation (hard SchemaMismatch error on version mismatch), model_version latch with ModelVersionChanged events, sliding-window p99 latency tracker with Tier1Degraded/Tier1Recovered transitions. Integration tests (AC-1, AC-2, AC-3). Also: update module-layout.md for frame_ingest and detection_client to reflect the streaming API shape; code review report batch_18. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -75,8 +75,14 @@
|
||||
- **Epic**: AZ-627
|
||||
- **Directory**: `crates/frame_ingest/`
|
||||
- **Public API**:
|
||||
- `crates/frame_ingest/src/lib.rs` (`FrameIngest`, `FrameIngestHandle::subscribe() -> Receiver<Frame>`, `health()`)
|
||||
- `crates/frame_ingest/src/lib.rs` (`FrameIngest`, `FrameIngestHandle`, `ConsumerId`)
|
||||
- `FrameIngestHandle::subscribe() -> Receiver<Frame>` — raw broadcast receiver (no per-consumer accounting)
|
||||
- `FrameIngestHandle::subscribe_as(ConsumerId) -> FrameReceiver` — receiver with per-consumer lag accounting
|
||||
- `FrameIngestHandle::publisher() -> Arc<FramePublisher>` — direct publisher handle for the composition root
|
||||
- `FrameIngestHandle::dropped_frames(ConsumerId) -> u64`, `publishes_total() -> u64`
|
||||
- `FrameIngestHandle::health() -> ComponentHealth`
|
||||
- **Internal**:
|
||||
- `crates/frame_ingest/src/internal/publisher.rs` (`FramePublisher`, `FrameReceiver`, `PublisherStats`)
|
||||
- `crates/frame_ingest/src/internal/rtsp_client.rs`
|
||||
- `crates/frame_ingest/src/internal/decoder.rs`
|
||||
- `crates/frame_ingest/src/internal/timestamp.rs`
|
||||
@@ -91,14 +97,22 @@
|
||||
- **Epic**: AZ-628
|
||||
- **Directory**: `crates/detection_client/`
|
||||
- **Public API**:
|
||||
- `crates/detection_client/src/lib.rs` (`DetectionClient`, `DetectionClientHandle::request(Frame) -> Result<DetectionBatch>`, `health()`)
|
||||
- `crates/detection_client/src/lib.rs` (`DetectionClient`, `DetectionClientConfig`, `DetectionClientHandle`, `DetectionEvent`, `ConnectionState`, `Tier1DegradationReason`)
|
||||
- `DetectionClient::run(frame_rx: Receiver<Frame>) -> (JoinHandle, DetectionClientHandle)` — spawns the gRPC supervisor task
|
||||
- `DetectionClientHandle::subscribe_events() -> Receiver<DetectionEvent>` — broadcast stream of batches, schema errors, model-version changes, Tier-1 degradation transitions
|
||||
- `DetectionClientHandle::health() -> ComponentHealth`
|
||||
- `DetectionClientHandle::stats() -> Arc<DetectionStats>`, `latency_p50/p99()`, `connection_state()`, `shutdown()`
|
||||
- **Internal**:
|
||||
- `crates/detection_client/build.rs` (`tonic-build` for the gRPC proto)
|
||||
- `crates/detection_client/proto/detections.proto` (vendored copy of `../detections` contract per `architecture.md §10`)
|
||||
- `crates/detection_client/src/internal/grpc/*` (bi-directional streaming client, version handshake)
|
||||
- `crates/detection_client/src/internal/runtime.rs` (supervisor + bi-directional stream session)
|
||||
- `crates/detection_client/src/internal/budget.rs` (drop-oldest in-flight tracker)
|
||||
- `crates/detection_client/src/internal/latency.rs` (sliding-window p99 + degradation latch)
|
||||
- `crates/detection_client/src/internal/stats.rs` (lock-free atomic counters)
|
||||
- `crates/detection_client/src/internal/proto.rs` (generated tonic/prost types)
|
||||
- **Owns**: `crates/detection_client/**`
|
||||
- **Imports from**: `shared`
|
||||
- **Consumed by**: `scan_controller` (handle for direct request), `telemetry_stream` (via constructor-injected `Receiver<DetectionBatch>` for operator overlay)
|
||||
- **Consumed by**: `scan_controller` (subscribes to events), `telemetry_stream` (via composition-root-wired `Receiver<DetectionBatch>` for operator overlay)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user