mirror of
https://github.com/azaion/autopilot.git
synced 2026-06-21 14:51:10 +00:00
[AZ-680] [AZ-681] operator_bridge command dispatch + safety lane
Add the operator-command dispatcher behind a typed CommandAck: 60 s per-command-id idempotency cache, surfaced-POI registry with unknown_poi_id + expired gates, BIT-degraded ack severity check, and SafetyOverride forwarding to mission_executor with structured audit log (redacts signature + session_token). Cross-layer wiring goes through three new traits in shared::contracts (ScanCommandRouter, MissionSafetyRouter, BitReportSeverityLookup) so operator_bridge stays free of direct scan_controller / mission_executor imports. scan_controller::ScanControllerHandle implements the scan router; a new mission_executor::SafetyDispatchHandle wraps the BIT ack channel + battery monitor handle and implements the safety router; BitControllerHandle gains a bounded (16-entry) report-severity cache for the lookup trait. scan_controller also picks up ConfirmPoi handling: PoiQueue::confirm removes the entry and SubmitOutcome::Confirmed carries the typed (target_mgrs, target_class) hint for AZ-684/AZ-686 downstream. Tests: 9 new integration tests in operator_bridge/tests/dispatcher.rs cover AZ-680 AC-1..AC-5 + AZ-681 AC-1..AC-4. scan_controller adds 2 ConfirmPoi tests. All modified-crate suites green; one pre-existing mission_executor state-machine test flake (already documented in _docs/_process_leftovers) updated to note ac1 also affected. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -153,7 +153,73 @@ async fn decline_poi_via_operator_command_emits_action() {
|
||||
assert_eq!(action.mgrs, "decline-me");
|
||||
assert_eq!(action.class_group, "armor");
|
||||
}
|
||||
SubmitOutcome::Accepted => panic!("decline must return Declined action"),
|
||||
other => panic!("decline must return Declined action, got {other:?}"),
|
||||
}
|
||||
assert_eq!(h.poi_queue_len().await, 0);
|
||||
}
|
||||
|
||||
/// AZ-680 — ConfirmPoi via operator command returns
|
||||
/// `SubmitOutcome::Confirmed` with the typed target hint and drains
|
||||
/// the POI from the queue.
|
||||
#[tokio::test]
|
||||
async fn confirm_poi_via_operator_command_emits_action() {
|
||||
// Arrange
|
||||
let h = ScanController::new().handle();
|
||||
let p = poi(0.8, "confirm-me");
|
||||
let id = p.id;
|
||||
let expected_class = p.class.clone();
|
||||
let expected_group = p.class_group.clone();
|
||||
h.submit_poi_candidate(p, 0.5).await;
|
||||
|
||||
let cmd = OperatorCommand {
|
||||
command_id: Uuid::new_v4(),
|
||||
session_token: "s".to_string(),
|
||||
sequence_number: 1,
|
||||
issued_at_wallclock: Utc::now(),
|
||||
kind: OperatorCommandKind::ConfirmPoi,
|
||||
payload: json!({ "poi_id": id.to_string() }),
|
||||
signature: vec![],
|
||||
};
|
||||
|
||||
// Act
|
||||
let outcome = h.submit_operator_cmd(cmd).await.expect("confirm accepted");
|
||||
|
||||
// Assert
|
||||
match outcome {
|
||||
SubmitOutcome::Confirmed(action) => {
|
||||
assert_eq!(action.poi_id, id);
|
||||
assert_eq!(action.target_mgrs, "confirm-me");
|
||||
assert_eq!(action.target_class, expected_class);
|
||||
assert_eq!(action.class_group, expected_group);
|
||||
}
|
||||
other => panic!("confirm must return Confirmed action, got {other:?}"),
|
||||
}
|
||||
assert_eq!(h.poi_queue_len().await, 0);
|
||||
}
|
||||
|
||||
/// AZ-680 — ConfirmPoi for an unknown poi_id must NOT silently
|
||||
/// succeed. Returns a `Validation` error so `operator_bridge` can
|
||||
/// surface a typed NACK to the operator UI.
|
||||
#[tokio::test]
|
||||
async fn confirm_poi_unknown_id_is_validation_error() {
|
||||
// Arrange
|
||||
let h = ScanController::new().handle();
|
||||
let cmd = OperatorCommand {
|
||||
command_id: Uuid::new_v4(),
|
||||
session_token: "s".to_string(),
|
||||
sequence_number: 1,
|
||||
issued_at_wallclock: Utc::now(),
|
||||
kind: OperatorCommandKind::ConfirmPoi,
|
||||
payload: json!({ "poi_id": Uuid::new_v4().to_string() }),
|
||||
signature: vec![],
|
||||
};
|
||||
|
||||
// Act
|
||||
let err = h
|
||||
.submit_operator_cmd(cmd)
|
||||
.await
|
||||
.expect_err("unknown poi must error");
|
||||
|
||||
// Assert
|
||||
assert!(matches!(err, shared::error::AutopilotError::Validation(_)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user