[AZ-626] Decompose complete: 47 tasks + docs + module layout

Greenfield Steps 1-6 baseline for the autopilot rewrite from legacy
Qt/C++ to a Rust workspace.

- Remove legacy Qt/C++ tree (ai_controller, drone_controller,
  misc/camera, python_scaffold, root Dockerfile, autopilot.pro,
  legacy main.py / requirements.txt).
- Add _docs/00_problem (problem, restrictions, acceptance criteria,
  security approach, input data + fixtures).
- Add _docs/01_solution/solution_draft01.
- Add _docs/02_document (architecture, system-flows, data_model,
  glossary, decision-rationale, deployment, 13 component descriptions,
  tests/ specs, FINAL_report, module-layout).
- Add _docs/02_tasks/todo with 47 task specs (AZ-640..AZ-686, one
  bootstrap + 46 component tasks) and _dependencies_table.md.
- Add .cursor/rules/artifact-srp.mdc (single-responsibility rule for
  canonical _docs artifacts).
- Track autodev state in _docs/_autodev_state.md (Step 6 completed,
  ready for Step 7 Implement).

Jira: bootstrap AZ-626; component epics AZ-627..AZ-639; tasks
AZ-640..AZ-686. Total complexity 173 points across 12 epics.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-19 11:02:01 +03:00
parent f7d6cb4a3a
commit bc40ea7300
235 changed files with 12585 additions and 15097 deletions
@@ -0,0 +1,64 @@
# Multi-Consumer Frame Publisher + Back-Pressure Drops
**Task**: AZ-659_frame_ingest_publisher
**Name**: Tokio broadcast publisher + per-consumer drop counters + zero-copy `Arc<Bytes>`
**Description**: Publish `Frame`s through a single multi-consumer channel using `Arc<Bytes>` for pixel data so consumers do not copy. Drop frames when downstream consumers fall behind beyond a configured queue depth; record per-consumer drop counters with reason tags.
**Complexity**: 3 points
**Dependencies**: AZ-640_initial_structure, AZ-657_frame_ingest_rtsp_session, AZ-658_frame_ingest_decoder
**Component**: frame_ingest
**Tracker**: AZ-659
**Epic**: AZ-627
## Problem
Three downstream consumers (`detection_client`, `movement_detector`, `telemetry_stream`) all need the same frames at the same rate. A single-consumer queue would serialise the slowest; a per-consumer fan-out with cloned pixel buffers would multiply memory. The right structure is a Tokio `broadcast` channel (or equivalent) carrying `Arc<Bytes>` so pixels are shared by reference. Slow consumers drop their oldest frame, with the drop counted (and reason-tagged) — never silently coalesced.
## Outcome
- `FramePublisher::subscribe() -> FrameReceiver` returns a per-consumer receiver.
- `Frame` carries `Arc<Bytes>` for `pixels` so consumers do not copy.
- When a consumer falls behind beyond `channel_depth` (configurable, default 4), the oldest frame is dropped for THAT consumer; per-consumer counters increment with reason tag (`{detection_client_slow, movement_detector_slow, telemetry_slow}`).
- Health surface: per-consumer drop counters, total publish count.
## Scope
### Included
- `tokio::sync::broadcast` (or equivalent) with `Arc<Bytes>` payload.
- Per-consumer drop counter (statically known three consumer ids; future-extensible).
- Channel-depth config.
### Excluded
- RTSP session (task 18).
- Decoder (task 19).
## Acceptance Criteria
**AC-1: Three consumers receive every frame at nominal rate**
Given three subscribers consuming at 30 fps and source at 30 fps
When the publisher runs for 10 s
Then each consumer observes ~300 frames; per-consumer drop counters = 0.
**AC-2: Slow consumer drops, fast consumers unaffected**
Given a slow consumer that yields every 200 ms while source is 30 fps and `channel_depth = 4`
When the publisher runs for 5 s
Then the slow consumer's drop counter increments and fast consumers continue to receive every frame.
**AC-3: Zero-copy under load**
Given a publisher emitting at 30 fps for 60 s with three subscribers
When peak memory is sampled
Then memory does not scale linearly with consumer count (i.e. `Arc<Bytes>` is correctly shared).
## Non-Functional Requirements
**Performance**
- Publish-to-consumer p99 ≤5 ms (helps keep total RTSP-rx-to-publish under the 30 ms p99 budget).
**Reliability**
- Drops are counted with reason; never silent.
- No unbounded memory growth on slow consumer.
## Runtime Completeness
- **Named capability**: lossy multi-consumer frame fan-out with `Arc<Bytes>`.
- **Production code that must exist**: real broadcast channel; real per-consumer drop accounting.
- **Unacceptable substitutes**: cloning pixel buffers per consumer is unacceptable (multiplies memory); blocking the publisher on a slow consumer is unacceptable (gates the whole pipeline).