Files
autopilot/_docs/03_implementation/batch_04_cycle1_report.md
T
Oleksandr Bezdieniezhnykh 69c0629350
ci/woodpecker/push/build-arm Pipeline failed
[AZ-643] [AZ-665] [AZ-672] mavlink+mapobjects+vlm batch 4
AZ-643 mavlink_layer:
- ack demux on COMMAND_LONG/COMMAND_ACK with oneshot dispatch and
  configurable deadline; MavlinkHandle::send_command + SendCommandError
- MAVLink-2 signing: Signer/Verifier built on SHA-256, key + timestamp
  source, incompat-flag wiring in encoder, reject + counter in decoder
- new tests: tests/ack_demux.rs (3) + tests/signing.rs (5)

AZ-665 mapobjects_store:
- internal/h3_index.rs (h3o wrapper, cell_of, grid_disk, haversine)
- internal/store.rs (in-memory (cell -> Vec<MapObject>) hashmap with
  k-ring classify and class-group resolution)
- public API: MapObjectsStoreHandle::classify(ClassifyInput) ->
  Classification {New|Moved|Existing}
- AC1-4 in tests/classify.rs; AC5 perf gate (#[ignore], passes in
  --release)

AZ-672 vlm_client + autopilot:
- DisabledVlmProvider in shared::contracts; VlmProvider::name() for
  composition-root diagnostics
- vlm_client::VlmClient gated behind feature = "vlm"; placeholder
  until AZ-673 lands the real NanoLLM IPC
- autopilot: vlm_client is now optional = true under feature vlm;
  Runtime::select_vlm_provider picks DisabledVlmProvider when feature
  off OR config.vlm.enabled = false

Workspace deps: +sha2 (mavlink signing), +h3o (mapobjects index).
Batch report: _docs/03_implementation/batch_04_cycle1_report.md

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 13:31:42 +03:00

10 KiB
Raw Blame History

Batch Report

Batch: 4 Tasks: AZ-643 mavlink_ack_demux_and_signing, AZ-665 mapobjects_store_h3_classify, AZ-672 vlm_client_provider_trait Date: 2026-05-19 Cycle: 1 Selection context: Product implementation Implementer: autodev / .cursor/skills/implement/SKILL.md Total complexity points: 10 (3 + 5 + 2)

Task Results

Task Status Files Modified Tests AC Coverage Issues
AZ-643 Done crates/mavlink_layer/Cargo.toml, crates/mavlink_layer/src/internal/{ack_demux,mod}.rs, crates/mavlink_layer/src/internal/codec/{decoder,encoder,mod,parse_errors,signing}.rs, crates/mavlink_layer/src/lib.rs, integration tests crates/mavlink_layer/tests/{ack_demux,signing}.rs, workspace Cargo.toml (sha2, chrono) pass (28 unit + 3 ack_demux + 5 signing) 4/4 verified locally 0 blocking
AZ-665 Done crates/mapobjects_store/Cargo.toml, crates/mapobjects_store/src/{lib,internal/mod,internal/h3_index,internal/store}.rs, integration test crates/mapobjects_store/tests/classify.rs, workspace Cargo.toml (h3o) pass (11 unit + 6 AC + 1 perf ignored) 5/5 verified locally (AC-5 in --release) 0 blocking
AZ-672 Done crates/shared/src/contracts/mod.rs, crates/vlm_client/src/{lib,enabled}.rs, crates/autopilot/{Cargo.toml,src/runtime.rs} pass (1 shared AC + 2 autopilot AC + 1 vlm_client placeholder) 3/3 verified locally 0 blocking

AC Test Coverage

Task AC Description Verified locally Notes
AZ-643 AC-1 send_command round-trip: MavlinkLayer emits COMMAND_LONG, demuxes matching COMMAND_ACK, returns Ok(ack) YES ack_demux::ac1_send_command_happy_path (loopback UDP heartbeat → spoofed ACK)
AZ-643 AC-2 send_command deadline elapses → Err(SendCommandError::Timeout) and demux slot freed YES ack_demux::ac2_send_command_timeout_returns_explicit_error
AZ-643 AC-3 Decoder with Verifier rejects signed frames whose signature does not match YES signing::ac3_decoder_rejects_bad_signature + signing::ac3_signed_frame_with_matching_key_passes
AZ-643 AC-4 Decoder without Verifier ignores the signature trailer YES signing::ac4_signing_disabled_ignores_signature_field + defensive unsigned_frame_rejected_when_verifier_present
AZ-665 AC-1 Empty store classify → Classification::New YES classify::ac1_first_detection_returns_new
AZ-665 AC-2 Detection 5 m from a stored object, distance_threshold=30Existing YES classify::ac2_within_distance_threshold_returns_existing
AZ-665 AC-3 Detection 60 m from a stored object, move_threshold=50Moved YES classify::ac3_beyond_move_threshold_returns_moved
AZ-665 AC-4 k-ring (k=2) lookup catches a match in a neighbouring H3 cell YES classify::ac4_k_ring_finds_match_in_neighbour_cell
AZ-665 AC-5 10 000-row warm store, 1 000 classifies, p99 ≤ 1 ms YES (release-only) classify::ac5_classify_p99_under_one_ms — gated #[ignore], runs with cargo test --release -p mapobjects_store -- --ignored; verified ≤ 1 ms on local run
AZ-672 AC-1 DisabledVlmProvider::assess returns status=Disabled ≤ 1 ms YES shared::contracts::tests::ac1_disabled_provider_returns_disabled_status
AZ-672 AC-2 Binary builds without vlm feature; vlm_client is NOT a build dependency YES cargo check -p autopilot (no feature) compiles; cargo tree -p autopilot --edges normal shows zero matches for vlm_client; cargo tree -p autopilot --features vlm shows the dep
AZ-672 AC-3 Feature on + vlm_enabled=false → composition root installs DisabledVlmProvider YES autopilot::runtime::tests::ac3_runtime_vlm_disabled_installs_disabled_provider; bonus inverse covered by runtime_vlm_enabled_installs_vlm_client

Coverage: 12/12 ACs verified locally (4 AZ-643, 5 AZ-665, 3 AZ-672).

Code Review Verdict

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

Phase 1 — Spec coverage:

  • AZ-643: signing Signer/Verifier types + key + timestamp source + decoder integration + encoder integration + parse-error counter (SigningMismatch); ack demux with oneshot dispatch + deadline + send_command API surface on MavlinkHandle + commands_in_flight() exposed in health. ✓
  • AZ-665: H3Index::cell_of(lat, lon, res), grid_disk(cell, k), haversine metres, in-memory (H3 cell → Vec<MapObject>), similar-classes group resolution, configurable thresholds, MapObjectsStoreHandle::classify(ClassifyInput) -> Classification. ✓
  • AZ-672: VlmProvider::name() diagnostic method; DisabledVlmProvider in shared::contracts; feature-gated vlm_client::VlmClient (placeholder until AZ-673); autopilot has vlm_client as optional = true dep gated by vlm feature; Runtime::select_vlm_provider picks based on feature + runtime flag. ✓

Phase 2 — Architecture compliance:

  • mavlink_layer continues to import only shared; new modules live under internal::ack_demux and internal::codec::signing. Public API additions: Signer, SigningKey, Verifier, SigningReject, SendCommandError, CommandAck, MavlinkHandle::send_command. Layer constraint preserved.
  • mapobjects_store imports only shared + h3o + chrono/uuid (all permitted by module-layout.md §5). New internal/h3_index.rs and internal/store.rs placed exactly where module-layout.md says. Public API exports ClassifyInput, Classification, MapObjectsStoreConfig, MapObjectsStoreHandle::classify.
  • vlm_client is now genuinely optional in the autopilot binary (dep:vlm_client under [features].vlm). The DisabledVlmProvider lives in shared::contracts — i.e., available regardless of feature, exactly as description.md §9 Optionality Model requires. scan_controller (AZ-684 dependency target) will receive Arc<dyn VlmProvider> and never link to vlm_client directly.
  • Doc drift (note for next monorepo-document run, not a blocker for AZ-665):
    • module-layout.md line 157 documents the public API as classify(Detection) -> Classification. AZ-665 introduces ClassifyInput instead because the shared Detection type carries no geolocation (no GPS / no MGRS) and extending it was out of scope. system-flows.md §F7 already describes the payload as "detection (gps, class, conf, size)" — ClassifyInput is the typed expression of that flow-level concept. Update module-layout.md to classify(ClassifyInput) -> Classification in a follow-up.

Phase 3 — Code quality:

  • SRP holds: ack_demux.rs only routes acks; signing.rs only does HMAC + replay-detection; h3_index.rs only wraps h3o; store.rs only owns the in-memory map. Each has one reason to change.
  • No silent error suppression. SendCommandError is an exhaustive enum (Duplicate, Timeout, LinkDown, Other); signing errors funnel into ParseErrors::signing_mismatch and surface in the public counter snapshot; haversine + cell_of return typed AutopilotError::Validation.
  • All tests follow Arrange / Act / Assert per coderule.mdc.
  • MapObjectsStoreHandle::len()'s clippy-required is_empty() companion is implemented and consistent.

Phase 4 — Runtime completeness (per task brief):

  • AZ-643 "real signing with secret-key validation" — Signer::sign_into computes SHA-256 over the canonical signed-payload bytes and appends the 13-byte trailer; Verifier::verify recomputes and compares in constant time; timestamps validated against the per-link source. ✓
  • AZ-665 "real H3 + k-ring" — h3o 0.7 is used (no naive Euclidean fallback). ✓
  • AZ-672 "real disabled impl + feature flag" — DisabledVlmProvider is a concrete trait impl (not a panicking unimplemented!), and the binary genuinely drops vlm_client from its dep graph when the feature is off (verified via cargo tree). ✓

Phase 5 — Test discipline:

  • Every AC has a dedicated test (table above).
  • Performance AC (AZ-665 AC-5) uses #[ignore] because debug builds run 310× slower than release; explicit --ignored invocation runs it and asserts ≤ 1 ms. This is the established project pattern for perf gates.
  • AZ-672 AC-2's structural-build check is expressed as a build invariant (cargo tree + cargo check --no-default-features) rather than a runtime test, because that is what the AC actually asks for. The fact that cargo test --workspace succeeds without the vlm feature is itself a positive confirmation.

Quality Gates

  • cargo fmt --all ✓ (no changes)
  • cargo clippy -p shared -p vlm_client -p mapobjects_store -p autopilot --tests --no-deps ✓ (0 warnings after fixes)
  • cargo check -p mavlink_layer --tests
  • cargo test --workspace (default features) → all green, 0 failures, 1 ignored (ac5_classify_p99_under_one_ms)
  • cargo test -p autopilot --features vlm ✓ (3 tests including AZ-672 AC-3 + bonus inverse)
  • cargo test -p vlm_client --features vlm ✓ (1 test)
  • cargo test --release -p mapobjects_store -- --ignored ac5_classify_p99 ✓ (perf gate passes)
  • cargo tree -p autopilot (no vlm) shows zero vlm_client matches ✓ — AZ-672 AC-2 structural proof

Auto-Fix Attempts

1 round — clippy surfaced three warnings on the first pass (len_without_is_empty, field_reassign_with_default, unnecessary_map_or); all three are Low-severity Style/Maintainability findings, auto-fix-eligible per the matrix in implement/SKILL.md §10. Fixes applied, re-clippy clean.

Stuck Agents

None.

Next Batch

Pending. Topological candidates with all dependencies satisfied:

  • AZ-648 mission_executor_state_machine (deps AZ-640, AZ-641, AZ-642, AZ-643 — now all in done/)
  • AZ-666 mapobjects_store_ignored_and_pass_sweep (deps AZ-640, AZ-665 — now all in done/)
  • AZ-673 vlm_client_nanollm_ipc (deps AZ-640, AZ-672 — now all in done/)

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