# FT-P-09-AP — ArduPilot Plane GPS_INPUT contract conformance + MAVLink 2.0 signing

**Task**: AZ-416_ft_p_09_ap_signing
**Name**: AP `GPS_INPUT` contract + MAVLink 2.0 signing handshake (AC-4.3 / D-C8-9 / AC-NEW-2 precondition)
**Description**: Implement FT-P-09-AP — start SUT with `ardupilot` adapter; signing handshake completes within 5 s; SUT emits signed `GPS_INPUT` at the configured rate during a 60 s Derkachi segment; AP `EK3_SRC1_POSXY=3` (GPS source); AP `GPS_RAW_INT` shows healthy fix.
**Complexity**: 5 points
**Dependencies**: AZ-406, AZ-407 (mavlink-passkey), AZ-408 (no — straight Derkachi 60 s segment)
**Component**: Blackbox Tests / Positive / FC contract / Security (epic AZ-262)
**Tracker**: AZ-416
**Epic**: AZ-262 (E-BBT)

## Problem

The ArduPilot wired channel is the highest-risk FC contract: signing handshake (D-C8-9 / Mode B Fact #109 mitigation), per-flight key handling, AP-side EKF source-set acceptance — all must be validated as one cohesive scenario before any production deployment.

## Outcome

- pytest scenario at `e2e/tests/positive/test_ft_p_09_ap_signing.py`.
- Forces `fc_adapter=ardupilot`; loads `mavlink-test-passkey.txt` as the Docker secret.
- Asserts: signing handshake completes within 5 s; signed-channel established; SUT emits signed `GPS_INPUT` at the configured rate during 60 s of Derkachi replay; `EK3_SRC1_POSXY` reads `3`; `GPS_RAW_INT` shows fix_type ≥ 3 with HDOP within nominal.

## Scope

### Included
- AP-only test method.
- Signing-handshake observation via mavproxy listener (handshake messages are public MAVLink).
- Param-read of `EK3_SRC1_POSXY` via mavproxy.
- `GPS_RAW_INT` parsing for fix-type + HDOP.

### Excluded
- iNav variant — owned by FT-P-09-iNav (AZ-417).
- Unsigned-message rejection (negative-path) — owned by NFT-SEC-03 (AZ-438).
- Spoofing-promotion latency — owned by NFT-PERF-04 (AZ-431).
- Source-set switch on spoof recovery — owned by FT-N-04 / NFT-RES-04.

## Acceptance Criteria

**AC-1: signing handshake completes**
Given SUT started with `ardupilot` + the test passkey
Then within ≤5 s, the signed channel is established (observable via `MAVLink2 SETUP_SIGNING` exchange OR by the absence of `BAD_SIGNATURE` STATUSTEXT during the handshake window).

**AC-2: signed `GPS_INPUT` flow**
Given the signed channel is up
When 60 s of Derkachi replays
Then `GPS_INPUT` messages reach AP SITL at the configured rate (≥4.5 Hz observed for a 5 Hz target — AC-4.3).

**AC-3: AP EKF source-set acceptance**
Given the SUT-emitted signed `GPS_INPUT` flow
Then `EK3_SRC1_POSXY` (read via mavproxy parameter request) returns `3` (GPS source).

**AC-4: AP-side GPS health**
Given the same flow
Then `GPS_RAW_INT.fix_type ≥ 3` AND `GPS_RAW_INT.eph` (HDOP × 100) within nominal (≤200 — i.e. HDOP ≤ 2.0) for ≥80 % of the 60 s window.

**AC-5: vio_strategy parameterization**
Given the conftest's `vio_strategy` parameterization
Then the scenario runs once per VIO strategy; `fc_adapter` is fixed to `ardupilot`.

## System Under Test Boundary

End-to-end through public boundaries with a real (SITL-simulated) FC.

- **Allowed**: AP SITL parameter reads via mavproxy, MAVLink message capture in `.tlog`.
- **Forbidden**: importing the SUT's signing key state, monkeypatching the handshake; if signing fails for any reason the scenario fails — it does NOT bypass to an unsigned channel.

## Constraints

- The test passkey is the fixture-level passkey; the production passkey path is `/run/secrets/mavlink_passkey` per `environment.md` and is never used in tests.
- Signing-handshake observation does NOT require parsing the encrypted contents — only the handshake message types and the rejection-vs-acceptance signal at AP.

## Document Dependencies

- `_docs/02_document/tests/blackbox-tests.md` § FT-P-09-AP
- `_docs/02_document/tests/test-data.md` § FC contract & startup (FT-P-09-AP row)
