mirror of
https://github.com/azaion/autopilot.git
synced 2026-06-21 16:01:10 +00:00
[AZ-683] scan_controller POI queue + 5/min cap + decision window
ci/woodpecker/push/build-arm Pipeline failed
ci/woodpecker/push/build-arm Pipeline failed
Adds the prioritized POI queue on top of the AZ-682 FSM substrate: priority = confidence x proximity x age_factor; rolling 60s window caps surfaces at 5; confidence-scaled decision window (40% -> 30s, 100% -> 120s, linear; <40% never surfaces); tick() runs the timeout sweep and silently forgets expired POIs (no IgnoredItem per spec); DeclinePoi via operator command returns a DeclineAction for AZ-685 to persist. ScanControllerHandle gains submit_poi_candidate / next_poi_for_surface / decline_poi / poi_queue_len / pois_in_window. submit_operator_cmd return type widens from Result<()> to Result<SubmitOutcome>. ScanMetrics and health() surface queue depth and counters. Tests: 26 unit + 11 integration in scan_controller (all AC1..AC5 + DeclinePoi end-to-end). Workspace clippy on scan_controller clean. Pre-existing autopilot::Runtime::vlm_provider_name dead-code error from batch 4 still open (see cumulative C5). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
# POI Queue: Priority Ordering + 5/min Rate Cap + Confidence-Scaled Decision Window
|
||||
|
||||
**Task**: AZ-683_scan_controller_poi_queue_and_window
|
||||
**Name**: POI queue ordered by confidence × proximity × age + 5/min hard cap + decision-window mapping
|
||||
**Description**: Maintain the POI queue ordered by `confidence × proximity_to_current_camera × age_factor`. Hard-cap output to ≤5 POIs/min. Map confidence to operator-decision deadline: 40% → 30 s, 100% → 120 s, linear; below 40% the POI is NOT surfaced. Timeout → forget. Decline → IgnoredItem append (via dispatch in task 46).
|
||||
**Complexity**: 5 points
|
||||
**Dependencies**: AZ-640_initial_structure, AZ-682_scan_controller_state_machine
|
||||
**Component**: scan_controller
|
||||
**Tracker**: AZ-683
|
||||
**Epic**: AZ-635
|
||||
|
||||
## Problem
|
||||
|
||||
The 5-POI/min cap is a product-level invariant (operator cognitive load). The decision window is confidence-scaled because the operator deserves more time on ambiguous targets and less on obvious ones. The priority ordering keeps the most actionable POI in front of the operator first. Confidence < 40 % means "don't surface" — silent suppression, not a low-priority enqueue.
|
||||
|
||||
## Outcome
|
||||
|
||||
- `PoiQueue` with ordered insertion by `priority = f(confidence, proximity, age)`.
|
||||
- Hard cap: rolling 60-s window tracks POIs surfaced; new POI surface request blocked if cap would be exceeded; blocked POI stays in queue for later.
|
||||
- `decision_window(confidence)` returns `Duration` per the linear 40 % → 30 s / 100 % → 120 s mapping; returns `None` for confidence < 40 %.
|
||||
- Timeout → `forget` (POI removed from queue, no IgnoredItem).
|
||||
- Decline command from `operator_bridge` → emit `MapObjectsAction::AppendIgnored(mgrs, class_group)` (dispatched by task 46).
|
||||
- Health: `pois_in_queue`, `pois_per_min`.
|
||||
|
||||
## Scope
|
||||
|
||||
### Included
|
||||
- Priority-ordered queue.
|
||||
- Rate cap with rolling-window enforcement.
|
||||
- Decision-window mapping.
|
||||
- Timeout → forget.
|
||||
|
||||
### Excluded
|
||||
- State machine (task 43).
|
||||
- Evidence ladder (task 45).
|
||||
- MapObjects dispatch (task 46).
|
||||
- Gimbal issuance (task 47).
|
||||
- Operator command dispatch (`operator_bridge` task 41).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
**AC-1: Priority ordering correct**
|
||||
Given 3 POIs with `(confidence, proximity, age) = (0.9, 0.5, 0), (0.6, 0.9, 0), (0.7, 0.6, 60)`
|
||||
When `next()` is called repeatedly
|
||||
Then the order respects `confidence × proximity × age_factor`.
|
||||
|
||||
**AC-2: 5/min hard cap**
|
||||
Given 10 POIs above 40 % confidence in 30 s
|
||||
When the cap window is queried
|
||||
Then at most 5 are surfaced; the rest remain queued until window rolls.
|
||||
|
||||
**AC-3: Decision window linear mapping**
|
||||
Given confidences `[0.40, 0.70, 1.00]`
|
||||
When `decision_window(c)` is called for each
|
||||
Then the returned `Duration` is `[30 s, 75 s, 120 s]` (linear).
|
||||
|
||||
**AC-4: Sub-40 % not surfaced**
|
||||
Given a POI with confidence 0.39
|
||||
When considered for surface
|
||||
Then `decision_window` returns `None`; the POI is NOT surfaced.
|
||||
|
||||
**AC-5: Timeout forgets**
|
||||
Given a surfaced POI whose deadline expires with no operator action
|
||||
When timeout fires
|
||||
Then the POI is removed from the queue; no IgnoredItem is created.
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
**Performance**
|
||||
- Queue insertion: ≤1 ms p99.
|
||||
- Cap-window check: O(window_size) where window_size is small (5).
|
||||
|
||||
**Product**
|
||||
- 5/min hard cap is a non-negotiable invariant from `description.md §8`.
|
||||
|
||||
## Runtime Completeness
|
||||
|
||||
- **Named capability**: priority POI queue + 5/min rate cap + confidence-scaled deadline.
|
||||
- **Production code that must exist**: real priority math; real cap enforcement; real linear mapping.
|
||||
- **Unacceptable substitutes**: ignoring the 5/min cap "for testing" in production is unacceptable.
|
||||
Reference in New Issue
Block a user