Files
autopilot/crates/detection_client/proto/detections.proto
T
Oleksandr Bezdieniezhnykh 0854d3be1c [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>
2026-05-20 18:23:56 +03:00

94 lines
3.5 KiB
Protocol Buffer

// AZ-660 / AZ-661 — vendored copy of the `../detections` gRPC contract.
//
// The authoritative schema lives in the `../detections` repository
// (per `_docs/02_document/architecture.md §10`). This vendored copy
// is kept in lock-step with that schema via the `schema_version`
// field on `DetectionResponse`: any breaking schema change MUST
// bump the version, and the client (built against the version pinned
// in `DetectionClientConfig::expected_schema_version`) MUST emit a
// hard `schema_mismatch` error if the server reports a different
// version. The schema version is the explicit handshake that lets
// the autopilot run alongside an evolving detection service without
// silently downcasting unknown response shapes.
//
// Wire shape (one bi-directional stream per session):
// client ─► FrameRequest stream ────► server (../detections)
// client ◄── DetectionResponse stream ◄── server
//
// `FrameRequest` carries the encoded pixel buffer and the source
// frame's monotonic timestamp; the response correlates back via
// `frame_seq`. Frames with `ai_locked = true` upstream are filtered
// by the client and never sent — the server therefore never sees a
// FrameRequest for an AI-locked frame.
syntax = "proto3";
package azaion.detection.v1;
service DetectionService {
// One bi-directional stream per client session. The server may
// close the stream at any time; the client reconnects with
// bounded backoff (`DetectionClientConfig::reconnect_*`).
rpc Stream(stream FrameRequest) returns (stream DetectionResponse);
}
// Pixel formats mirrored from `shared::models::frame::PixelFormat`.
// Encoded as a proto enum so the wire is self-describing.
enum PixelFormat {
PIXEL_FORMAT_UNSPECIFIED = 0;
PIXEL_FORMAT_NV12 = 1;
PIXEL_FORMAT_YUV420P = 2;
PIXEL_FORMAT_RGB24 = 3;
}
// One inference request per frame. The client tracks `frame_seq`
// for response correlation (the response carries the same value
// in `frame_seq`).
message FrameRequest {
uint64 frame_seq = 1;
// Capture timestamp (monotonic, ns) — used by the client to
// compute per-frame round-trip latency from the response.
uint64 capture_ts_monotonic_ns = 2;
uint32 width = 3;
uint32 height = 4;
PixelFormat pix_fmt = 5;
bytes pixels = 6;
}
// Bounding box in [0,1] normalized coordinates (mirrors
// `shared::models::frame::BoundingBox`).
message BoundingBox {
float x_min = 1;
float y_min = 2;
float x_max = 3;
float y_max = 4;
}
// One detection inside a `DetectionResponse`.
message Detection {
uint32 class_id = 1;
string class_name = 2;
float confidence = 3;
BoundingBox bbox_normalized = 4;
optional bytes mask_or_polyline = 5;
uint64 source_frame_seq = 6;
}
// Server-streamed response. `schema_version` is the handshake the
// client validates against `expected_schema_version`; any mismatch
// is a hard `schema_mismatch` error and the response is rejected.
// `model_version` may change at runtime when the inference model
// is hot-swapped — the client emits a `ModelVersionChanged` event
// on the first response with a new version.
message DetectionResponse {
uint32 schema_version = 1;
string model_version = 2;
uint64 frame_seq = 3;
// Server-side processing latency for THIS frame, in milliseconds.
// The client also computes its own round-trip latency from
// `capture_ts_monotonic_ns` so it can detect transport latency
// independently of server-internal latency.
uint32 latency_ms = 4;
repeated Detection detections = 5;
}