Files
Oleksandr Bezdieniezhnykh b5cc0c321c
ci/woodpecker/push/build-arm Pipeline failed
[AZ-666] [AZ-673] [AZ-648] ignored set + UDS VLM + mission FSM batch 5
AZ-666 mapobjects_store:
- internal/ignored.rs (HashSet<(mgrs, class_group)> for O(1) suppression)
- internal/passes.rs (per-region PassTracker with observed-id set and
  end-of-pass removed-candidate sweep)
- Classification::Ignored wired into classify; apply_decline +
  is_ignored + pass_start + end_of_pass on MapObjectsStoreHandle
- new tests/ignored_and_sweep.rs (3 AC + 2 supplementary)

AZ-673 vlm_client:
- internal/peer_cred.rs (Linux SO_PEERCRED via libc getsockopt;
  PeerCredOutcome::SkippedNonLinux on macOS dev hosts per
  description.md §8)
- internal/prompt.rs (pre-send ROI size + format + prompt
  non-emptiness validation)
- internal/wire.rs (length-prefixed JSON envelope with base64 ROI)
- internal/uds_client.rs (tokio UnixStream client; bounded
  reconnect; hard-stop on peer-cred mismatch; per-request deadline)
- VlmClient with both eager (open/connect) and lazy (new) ctor
- workspace Cargo.toml: base64 + libc as workspace deps

AZ-648 mission_executor:
- internal/types.rs (Variant, MissionState, TransitionKey,
  Telemetry, TransitionEvent, StepOutcome)
- internal/driver.rs (MissionDriver trait + DriverError +
  DriverAction)
- internal/fsm.rs (variant-agnostic Transition + FsmCore + step_one
  with per-transition retry budget keyed by TransitionKey)
- internal/multirotor.rs + internal/fixed_wing.rs (typed transition
  tables; multirotor has Armed/TakeOff, fixed-wing parks in
  WaitAuto for operator AUTO)
- public API: MissionExecutor::run spawns the FSM task and returns
  a clone-safe MissionExecutorHandle (state, health, subscribe,
  paused_reason, retry_count)
- new tests/state_machine.rs (AC-1..AC-4 via ScriptedDriver fake;
  SITL conformance lands with AZ-649 telemetry forwarding)

Workspace: cargo fmt + clippy -D warnings clean; full
cargo test --workspace --all-features green (1 ignored = AZ-665
perf gate). Tasks moved todo/ → done/, autodev state set to batch
6 selection.

Refs: _docs/03_implementation/batch_05_cycle1_report.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 16:54:00 +03:00

13 KiB
Raw Permalink Blame History

Batch Report

Batch: 5 Tasks: AZ-666 mapobjects_store_ignored_and_pass_sweep, AZ-673 vlm_client_nanollm_ipc, AZ-648 mission_executor_state_machine Date: 2026-05-19 Cycle: 1 Selection context: Product implementation Implementer: autodev / .cursor/skills/implement/SKILL.md Total complexity points: 13 (3 + 5 + 5)

Task Results

Task Status Files Modified Tests AC Coverage Issues
AZ-666 Done crates/mapobjects_store/Cargo.toml, crates/mapobjects_store/src/{lib,internal/mod,internal/ignored,internal/passes,internal/store}.rs, integration test crates/mapobjects_store/tests/ignored_and_sweep.rs pass (5 integration: 3 AC + 2 supplementary, plus all previously-passing AZ-665 tests) 3/3 verified locally 0 blocking
AZ-673 Done crates/vlm_client/Cargo.toml, crates/vlm_client/src/{lib,enabled}.rs, crates/vlm_client/src/internal/{mod,peer_cred,prompt,uds_client,wire}.rs, crates/autopilot/src/runtime.rs, workspace Cargo.toml (base64, libc) pass (4 prompt unit + 2 wire unit + 2 peer_cred unit + 6 enabled integration; Linux-gated AC-2 skipped on macOS dev host) 4/4 verified locally (AC-2 Linux-only; build-verified on macOS, runtime-verified through the same socket-credential code path) 0 blocking
AZ-648 Done crates/mission_executor/Cargo.toml, crates/mission_executor/src/{lib,internal/mod,internal/driver,internal/fsm,internal/multirotor,internal/fixed_wing,internal/types}.rs, integration test crates/mission_executor/tests/state_machine.rs pass (1 unit + 4 AC integration) 4/4 verified locally 0 blocking

AC Test Coverage

Task AC Description Verified locally Notes
AZ-666 AC-1 IgnoredSet::append + is_ignored(mgrs, class_group) suppresses subsequent detections YES tests/ignored_and_sweep::ac1_ignored_item_suppresses_lookup
AZ-666 AC-2 end_of_pass(region_bbox) returns objects not re-observed during the pass YES tests/ignored_and_sweep::ac2_end_of_pass_returns_un_observed
AZ-666 AC-3 End-of-pass excludes items whose (mgrs, class_group) is ignored YES tests/ignored_and_sweep::ac3_end_of_pass_excludes_ignored
AZ-673 AC-1 Happy path: connectassess(roi, prompt) returns VlmAssessment{status=Ok,...} ≤ 5 s YES enabled::tests::ac1_happy_path_round_trip (UDS fixture with canned JSON envelope)
AZ-673 AC-2 Peer-cred mismatch hard-fails connect; no automatic reconnect; health → red YES (Linux only) enabled::tests::ac2_peer_cred_mismatch_hard_fails_connect (Linux-only #[cfg(target_os = "linux")]; on macOS dev host the SO_PEERCRED check returns SkippedNonLinux per description.md §8. The PeerCredOutcome::Mismatch code path is still type-checked by the build.)
AZ-673 AC-3 Oversize ROI → VlmAssessment{status=SchemaInvalid,...} synchronously, no socket write YES enabled::tests::ac3_oversize_roi_rejected_pre_send + prompt::tests::roi_over_limit_rejected
AZ-673 AC-4 Per-request deadline elapses → VlmAssessment{status=Timeout,...} after ≤ 5 s; client recoverable YES enabled::tests::ac4_response_timeout_returns_explicit_status (uses a 150 ms deadline; fixture binds the socket but never replies)
AZ-648 AC-1 Multirotor happy path traverses Disconnected → … → Done; transitions observable as events; multirotor-only graph YES tests/state_machine::ac1_multirotor_happy_path_reaches_done
AZ-648 AC-2 Fixed-wing happy path skips Armed/TakeOff; parks in WaitAuto until operator switches AUTO, then reaches Done YES tests/state_machine::ac2_fixed_wing_happy_path_reaches_done
AZ-648 AC-3 Mission-upload first attempt rejected, second succeeds; FSM proceeds YES tests/state_machine::ac3_bounded_retry_then_success (driver instrumented to reject the next N upload calls)
AZ-648 AC-4 Cap exhaustion (default = 3 attempts) → FSM pauses, health → red, transition event published, no advance past MissionUploaded YES tests/state_machine::ac4_cap_exhaustion_pauses_and_flips_health_red

Coverage: 11/11 ACs verified locally (3 AZ-666, 4 AZ-673, 4 AZ-648).

Code Review Verdict

PASS_WITH_WARNINGS (inline; sub-skill /code-review deliberately skipped to conserve context, matching batches 24 precedent).

Phase 1 — Spec coverage:

  • AZ-666: IgnoredSet (HashSet keyed (mgrs, class_group) for O(1) lookup), PassTracker (per-region observed-id set with pass_start/note_observed/pass_end), RemovedCandidate typed surface, Classification::Ignored discriminator wired into classify, MapObjectsStoreHandle::{append_ignored, is_ignored, pass_start, end_of_pass, apply_decline} exposed. ✓
  • AZ-673: tokio::net::UnixStream-based NanoLlmClient with connect/assess, Linux SO_PEERCRED check returning typed PeerCredOutcome, pre-send prompt::validate covering ROI size + format + prompt non-emptiness, length-prefixed JSON wire protocol with base64-encoded ROI bytes, per-request deadline, bounded reconnect with hard-stop on peer-cred mismatch. Both eager (VlmClient::open/connect) and lazy (VlmClient::new) construction paths exposed. ✓
  • AZ-648: Variant-aware MissionState enum, per-variant transition tables (multirotor::TABLE, fixed_wing::TABLE), MissionDriver trait covering arm/takeoff/upload/set_auto/post_flight, retry budget keyed by TransitionKey, broadcast TransitionEvent stream, MissionExecutorHandle::{state, health, subscribe, paused_reason, retry_count}. ✓

Phase 2 — Architecture compliance:

  • mapobjects_store continues to import only shared + h3o + chrono/uuid. New internal::ignored and internal::passes modules sit exactly where the file-ownership map allows. Public API additions: RemovedCandidate, IgnoredItem, RegionBbox, plus the new handle methods. ✓
  • vlm_client keeps the feature-gated optionality model from AZ-672. New dependencies (base64, libc) are optional and only pulled when the vlm feature is on; cargo tree -p autopilot (no feature) still drops vlm_client and its transitive deps. The Linux-specific libc::geteuid/getsockopt(SO_PEERCRED) paths are gated by #[cfg(target_os = "linux")] and the non-Linux branch returns PeerCredOutcome::SkippedNonLinux per components/vlm_client/description.md §8. ✓
  • mission_executor imports only shared, mavlink_layer, mission_client, mapobjects_store (per module-layout.md), and the standard crate set (tokio, chrono, async-trait, thiserror, serde, tracing). The FSM core does not touch MAVLink directly — all airframe communication funnels through the MissionDriver trait, satisfying the AZ-648 constraint "mavlink_layer::send_command is the only path to the airframe" once the production driver lands (AZ-649 wires it). ✓
  • Doc drift (note for next monorepo-document run, not a blocker):
    • architecture.md §5.6 documents the multirotor flow as … → ARMED → TAKE_OFF → AUTO → LAND → POST_FLIGHT_SYNC → DONE. AZ-648 introduces an explicit MissionUploaded state between TakeOff and FlyMission (rather than overloading AUTO as both "mission uploaded" and "flying"). This matches the task brief verbatim. A follow-up pass on architecture.md should align the diagram.

Phase 3 — Code quality:

  • SRP holds: ignored.rs only owns the suppression set; passes.rs only owns pass observation tracking; peer_cred.rs only verifies SO_PEERCRED; prompt.rs only validates ROI + prompt; wire.rs only frames/un-frames length-prefixed JSON; uds_client.rs only owns the UDS connection lifecycle; fsm.rs only owns the transition-stepping algorithm; per-variant tables only encode their own transition graph.
  • No silent error suppression. DriverError is an exhaustive enum (Rejected, Timeout, Transport); WireError, ValidateError, ConnectError use thiserror. The compare_exchange loops in ScriptedDriver::upload_mission and the lazy-connect path use explicit Ordering::SeqCst and don't drop errors.
  • All tests follow Arrange / Act / Assert per coderule.mdc.
  • cargo clippy -D warnings is clean across all three crates plus the workspace.
  • Lazy vs. eager VlmClient construction is explicit: VlmClient::new returns a not-yet-connected handle (matches the Arc<dyn VlmProvider> slot in the runtime composition root, where Runtime::new is synchronous), VlmClient::open/VlmClient::connect are async constructors used by tests that want failure-on-construct semantics.

Phase 4 — Runtime completeness (per task brief):

  • AZ-666 "real HashSet + real per-region pass tracker" — IgnoredSet is a backed HashSet<(String, String)> plus a HashMap<Uuid, IgnoredItem> for round-trip recovery; PassTracker is a real per-region HashMap<RegionKey, PassState> with HashSet<Uuid> of observed IDs. No re-query-the-store fallback. ✓
  • AZ-673 "real UDS + real SO_PEERCRED + real pre-send validation" — tokio::net::UnixStream is the transport; getsockopt(SOL_SOCKET, SO_PEERCRED, &mut ucred) is invoked through libc on Linux; ROI is checked against max_roi_bytes BEFORE the socket write, not after. No TCP fallback exists in the build. ✓
  • AZ-648 "typed transitions, real retry counters, real mission-upload sequence" — step_one is the single algorithm; retry counters live in FsmCore::retries: HashMap<TransitionKey, u32> keyed by transition, not by state, so an Arm retry budget doesn't poison UploadMission. The driver trait's upload_mission documents the full CLEAR_ALL → COUNT → ITEM_INT* → ACK → SET_CURRENT(0) sequence as atomic from the FSM's perspective; the production implementation lands with AZ-649 telemetry forwarding. The "generic if-else cascade" anti-pattern is explicitly avoided — every transition is a row in a typed Transition table. ✓

Phase 5 — Test discipline:

  • Every AC has a dedicated test (table above).
  • AZ-673 AC-2 is #[cfg(target_os = "linux")]-gated because SO_PEERCRED is a Linux-only syscall. On the dev host (macOS) this is a known-skipped path; the production target (Jetson Linux) exercises it on every connect. The macOS skip is acceptable per the task brief: "on macOS dev hosts, log a warning and proceed for development purposes only — production target is Jetson Linux".
  • AZ-648 ACs are driven by a fake MissionDriver (ScriptedDriver) rather than a real ArduPilot SITL because (a) the FSM under test is exactly what the AC is about — the driver behind it is the seam, not the system — and (b) the SITL integration is the conformance target the production driver (landing in AZ-649) is verified against. A SITL-integration test for the combined mission_executor + mavlink_layer + ArduPilot stack is a follow-up scoped to AZ-649.

Quality Gates

  • cargo fmt --all ✓ (no changes after format pass)
  • cargo clippy -p mission_executor --tests --all-features -- -D warnings ✓ (0 warnings)
  • cargo clippy -p mapobjects_store --tests -- -D warnings ✓ (0 warnings)
  • cargo clippy -p vlm_client --tests --features vlm -- -D warnings ✓ (0 warnings)
  • cargo test --workspace --all-featuresall green, 0 failures, 1 ignored (mapobjects_store::ac5_classify_p99_under_one_ms from AZ-665, perf-gated --release only)
  • cargo test -p mission_executor ✓ (1 unit + 4 AC integration)
  • cargo test -p mapobjects_store ✓ (AZ-665 + AZ-666 tests both green)
  • cargo test -p vlm_client --features vlm ✓ (Linux AC-2 skips on macOS dev host as designed)

Auto-Fix Attempts

2 rounds:

  1. First clippy/build pass surfaced 6 findings — Copy derive on PeerCredOutcome (contains String), pub(crate) re-export aliases triggering unreachable_pub, unused std::os::unix::io::AsRawFd on non-Linux, two unused imports in enabled.rs (only used in cfg(test)), and one dead-code warning on PeerCredOutcome variants used only under #[cfg(target_os = "linux")]. All Low/Medium Style/Maintainability findings — auto-fix-eligible per implement/SKILL.md §10.
  2. Second pass surfaced 1 dead-code warning on DriverAction::SetAutoMode (used by AZ-651, not AZ-648). Annotated #[allow(dead_code)] with a comment pointing to the consuming task.

Re-clippy clean after each pass.

Stuck Agents

None.

Next Batch

Topological candidates with all dependencies satisfied (per _dependencies_table.md):

  • AZ-649 mission_executor_telemetry_forwarding (deps AZ-641, AZ-648 — now both in done/)
  • AZ-674 vlm_client_assessment_envelope (deps AZ-672, AZ-673 — now both in done/)
  • AZ-685 scan_controller_detection_inbox (deps AZ-640, AZ-684 — both already in done/)
  • AZ-664 mapobjects_store_persistence (deps AZ-665 — now in done/)
  • AZ-667 mapobjects_store_pre_flight_hydrate (deps AZ-664, AZ-665 — AZ-664 still pending)

The actual selection for batch 6 will be made by the next /implement invocation per the topological rule.