# CI / CD Pipeline

**Status**: forward-looking design (Rust). Final pipeline file lands during build-system bring-up. The shape below describes the intent.

## 1. Goals

The pipeline must:

- Build the autopilot Rust binary cross-compiled for `aarch64-unknown-linux-gnu`.
- Run the full Rust test suite (unit + integration + replay-based) on every commit.
- Run a hardware-in-loop conformance gate against an ArduPilot SITL instance (covers `mavlink_layer` + `mission_executor`).
- Run a benchmark gate on representative target hardware (covers Tier 1 / Tier 2 / VLM / gimbal latency budgets — see `architecture.md §7.6 Benchmark gate`).
- Sign and publish artefacts (binary + container image) on tagged releases.
- Never auto-deploy to the airframe. Deployment is a human-driven operation tied to the suite's flight-gate convention (`/run/azaion/in-flight`).

## 2. Pipeline stages

Single Woodpecker pipeline, multi-stage. Stages run sequentially; a failed stage stops the run.

| Stage | Purpose | Notes |
|---|---|---|
| **fetch** | Clone, restore Cargo cache | `cargo fetch` with a remote cache key. |
| **lint** | `cargo fmt --check`, `cargo clippy --all-targets --all-features -- -D warnings` | Hard fail on any warning. |
| **unit-test** | `cargo test --workspace` (host-arch) | Most logic is platform-independent; runs in parallel on host. |
| **build-arm64** | Cross-compile for `aarch64-unknown-linux-gnu` | `cross` or `cargo zigbuild` depending on Rust toolchain. Produces the production binary + a debug symbol artefact. |
| **integration-test** | Replay-based integration tests under emulation | Fixtures: pre-recorded RTSP clip, MAVLink replay, synthetic telemetry. No hardware required. |
| **sitl-conformance** | ArduPilot SITL conformance gate | Spins up ArduPilot SITL + autopilot binary in a container; runs a fixed mission script; asserts MAVLink command surface (per `architecture.md §7.7`) and geofence enforcement. |
| **benchmark-gate** *(opt-in, manual / nightly)* | Tier 1 / 2 / VLM / gimbal latency on real Jetson | Runs on a self-hosted Jetson Orin Nano runner. Asserts `architecture.md §6 NFR` budgets. Slow; not on every PR. |
| **package** | Build container image (Option B from `containerization.md`) | Multi-arch tag: `azaion/autopilot:<branch>-arm64`. |
| **sign** | Sign binary + image | Cosign for the image; OS-vendor signing flow for the binary if used in native deployment. |
| **publish** | Push image + binary to internal registry | Tagged builds only. |

## 3. Artefacts

| Artefact | Where | Retention |
|---|---|---|
| `autopilot` binary (aarch64) | internal artefact store | last 10 builds per branch; tagged builds kept indefinitely |
| Debug symbols (`.dwp`) | internal artefact store, separate path | matched to binary lifetime |
| Container image | internal Docker registry | last 10 dev builds; tagged builds kept indefinitely |
| Cosign signature | next to image | matched to image lifetime |
| Test logs | CI run | per Woodpecker retention |
| Benchmark gate report | internal artefact store (Markdown + JSON) | per-tag retention |

## 4. Build matrix

Single matrix entry today:

| Toolchain | Target | Tier-1 dep | VLM feature |
|---|---|---|---|
| Rust stable | `aarch64-unknown-linux-gnu` | `../detections` (Cython service consumed via gRPC; not built here) | `cargo --features vlm` (also `cargo` without — both must build) |

The `--features vlm` and the no-feature path are both built and tested to enforce the optionality contract from `architecture.md §7.6 Local VLM confirmation`.

## 5. SITL conformance gate (in detail)

Stage runs in CI; produces a pass/fail signal that gates merge to `dev`.

**Setup:**

1. Start ArduPilot SITL in a container, listening on `udp://0.0.0.0:14550`.
2. Start autopilot binary configured for SITL endpoint.
3. Pre-load a fixture mission via the missions API mock (`mission_client` HTTP target).
4. Pre-load a fixture RTSP source (looped clip).
5. Mock the `../detections` service with deterministic detections.

**Assertions:**

- All MAVLink message kinds in `architecture.md §7.7` succeed at least once.
- Mission upload + start completes within the configured retry budget.
- INCLUSION geofence violation triggers RTL.
- EXCLUSION geofence violation triggers RTL (regression gate against the earlier silent-ignore behaviour).
- Middle-waypoint POST + re-upload succeeds within ≤2 s.
- Health endpoint returns `green` once steady state is reached.

## 6. Branch policy

| Branch | Triggers | Required gates |
|---|---|---|
| feature branches (PR) | on push | fetch → lint → unit-test → build-arm64 → integration-test → sitl-conformance |
| `dev` | on merge | all PR gates + package |
| tagged release (`v*`) | on tag | all `dev` gates + sign + publish + benchmark-gate (manual approval) |

`main` and `dev` are protected. Force-push is forbidden. Merges require a green pipeline.

## 7. Out of scope here

- Airframe deployment automation (manual; tied to flight-gate).
- Ground Station and `../detections` pipelines (each owns its own).
- AI training pipeline — `../_docs/12_ai_training.md`.
- Model-sync to the airframe (`model-sync.service`, suite-level — `../_docs/00_top_level_architecture.md`).
