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>
13 KiB
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: connect → assess(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 2–4 precedent).
Phase 1 — Spec coverage:
- AZ-666:
IgnoredSet(HashSet keyed(mgrs, class_group)for O(1) lookup),PassTracker(per-region observed-id set withpass_start/note_observed/pass_end),RemovedCandidatetyped surface,Classification::Ignoreddiscriminator wired intoclassify,MapObjectsStoreHandle::{append_ignored, is_ignored, pass_start, end_of_pass, apply_decline}exposed. ✓ - AZ-673:
tokio::net::UnixStream-basedNanoLlmClientwithconnect/assess, LinuxSO_PEERCREDcheck returning typedPeerCredOutcome, pre-sendprompt::validatecovering 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
MissionStateenum, per-variant transition tables (multirotor::TABLE,fixed_wing::TABLE),MissionDrivertrait covering arm/takeoff/upload/set_auto/post_flight, retry budget keyed byTransitionKey, broadcastTransitionEventstream,MissionExecutorHandle::{state, health, subscribe, paused_reason, retry_count}. ✓
Phase 2 — Architecture compliance:
mapobjects_storecontinues to import onlyshared+h3o+ chrono/uuid. Newinternal::ignoredandinternal::passesmodules sit exactly where the file-ownership map allows. Public API additions:RemovedCandidate,IgnoredItem,RegionBbox, plus the new handle methods. ✓vlm_clientkeeps the feature-gated optionality model from AZ-672. New dependencies (base64,libc) are optional and only pulled when thevlmfeature is on;cargo tree -p autopilot(no feature) still dropsvlm_clientand its transitive deps. The Linux-specificlibc::geteuid/getsockopt(SO_PEERCRED)paths are gated by#[cfg(target_os = "linux")]and the non-Linux branch returnsPeerCredOutcome::SkippedNonLinuxpercomponents/vlm_client/description.md §8. ✓mission_executorimports onlyshared,mavlink_layer,mission_client,mapobjects_store(permodule-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 theMissionDrivertrait, satisfying the AZ-648 constraint "mavlink_layer::send_commandis 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.6documents the multirotor flow as… → ARMED → TAKE_OFF → AUTO → LAND → POST_FLIGHT_SYNC → DONE. AZ-648 introduces an explicitMissionUploadedstate betweenTakeOffandFlyMission(rather than overloadingAUTOas both "mission uploaded" and "flying"). This matches the task brief verbatim. A follow-up pass onarchitecture.mdshould align the diagram.
Phase 3 — Code quality:
- SRP holds:
ignored.rsonly owns the suppression set;passes.rsonly owns pass observation tracking;peer_cred.rsonly verifies SO_PEERCRED;prompt.rsonly validates ROI + prompt;wire.rsonly frames/un-frames length-prefixed JSON;uds_client.rsonly owns the UDS connection lifecycle;fsm.rsonly owns the transition-stepping algorithm; per-variant tables only encode their own transition graph. - No silent error suppression.
DriverErroris an exhaustive enum (Rejected,Timeout,Transport);WireError,ValidateError,ConnectErrorusethiserror. Thecompare_exchangeloops inScriptedDriver::upload_missionand the lazy-connect path use explicitOrdering::SeqCstand don't drop errors. - All tests follow
Arrange / Act / Assertpercoderule.mdc. cargo clippy -D warningsis clean across all three crates plus the workspace.- Lazy vs. eager
VlmClientconstruction is explicit:VlmClient::newreturns a not-yet-connected handle (matches theArc<dyn VlmProvider>slot in the runtime composition root, whereRuntime::newis synchronous),VlmClient::open/VlmClient::connectare 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" —
IgnoredSetis a backedHashSet<(String, String)>plus aHashMap<Uuid, IgnoredItem>for round-trip recovery;PassTrackeris a real per-regionHashMap<RegionKey, PassState>withHashSet<Uuid>of observed IDs. No re-query-the-store fallback. ✓ - AZ-673 "real UDS + real SO_PEERCRED + real pre-send validation" —
tokio::net::UnixStreamis the transport;getsockopt(SOL_SOCKET, SO_PEERCRED, &mut ucred)is invoked throughlibcon Linux; ROI is checked againstmax_roi_bytesBEFORE the socket write, not after. No TCP fallback exists in the build. ✓ - AZ-648 "typed transitions, real retry counters, real mission-upload sequence" —
step_oneis the single algorithm; retry counters live inFsmCore::retries: HashMap<TransitionKey, u32>keyed by transition, not by state, so anArmretry budget doesn't poisonUploadMission. The driver trait'supload_missiondocuments the fullCLEAR_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 typedTransitiontable. ✓
Phase 5 — Test discipline:
- Every AC has a dedicated test (table above).
- AZ-673 AC-2 is
#[cfg(target_os = "linux")]-gated becauseSO_PEERCREDis 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 combinedmission_executor + mavlink_layer + ArduPilotstack 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-features→ all green, 0 failures, 1 ignored (mapobjects_store::ac5_classify_p99_under_one_msfrom AZ-665, perf-gated--releaseonly)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:
- First clippy/build pass surfaced 6 findings —
Copyderive onPeerCredOutcome(containsString),pub(crate)re-export aliases triggeringunreachable_pub, unusedstd::os::unix::io::AsRawFdon non-Linux, two unused imports inenabled.rs(only used incfg(test)), and one dead-code warning onPeerCredOutcomevariants used only under#[cfg(target_os = "linux")]. All Low/Medium Style/Maintainability findings — auto-fix-eligible perimplement/SKILL.md §10. - 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 indone/) - AZ-674
vlm_client_assessment_envelope(deps AZ-672, AZ-673 — now both indone/) - AZ-685
scan_controller_detection_inbox(deps AZ-640, AZ-684 — both already indone/) - AZ-664
mapobjects_store_persistence(deps AZ-665 — now indone/) - 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.