# Test Specification — C12 Operator Pre-flight Orchestrator

Component-scoped. Suite-level coverage in `_docs/02_document/tests/*.md`. C12 sequences the F1 (C11 download → C10 build) and F10 (C11 upload trigger) operator-side flows.

## Acceptance Criteria Traceability

| AC ID | Acceptance Criterion (one-line) | Test IDs | Coverage |
|-------|---------------------------------|----------|----------|
| AC-3.4 | Operator-relocalization on visual loss | FT-N-03, **C12-IT-01** | Covered |
| AC-8.3 | Imagery pre-loaded onto companion before flight | FT-P-15, FT-P-16, **C12-IT-02** | Covered |
| AC-8.4 | Mid-flight tile upload trigger (post-landing) | FT-P-17, **C12-IT-03** | Covered |
| AC-NEW-1 | Cold-start TTFF (cache must be in place pre-flight) | NFT-PERF-03, **C12-IT-02** | Covered (pre-flight side) |

---

## Component-Internal Tests

### C12-IT-01: operator re-localization workflow returns SUT to satellite-anchored

**Summary**: when the SUT requests operator re-loc per AC-3.4, the operator workflow exposes the request, lets the operator confirm a candidate location, and returns the system to `satellite_anchored` within the configured budget.

**Traces to**: AC-3.4

**Description**: scripted scenario — SUT publishes a re-loc request via FDR + GCS STATUSTEXT; operator-side C12 catches it; an automated test "operator" confirms the candidate; assert (a) the system transitions back to `satellite_anchored` within 30 s, (b) the confirmation event lands in FDR.

**Input data**: scripted re-loc request fixture.

**Expected result**: per assertion.

**Max execution time**: 60 s.

---

### C12-IT-02: build-cache orchestrates C11 download then C10 build

**Summary**: `build_cache(area, sector_classification)` calls `C11.TileDownloader.fetch` first, then `C10.CacheProvisioner.build_artifacts`, and produces a `CacheBuildReport` wrapping both sub-reports.

**Traces to**: AC-8.3, AC-NEW-1

**Description**: with a fresh empty C6, call `build_cache` for a small Derkachi sub-area; assert (a) C11's `DownloadBatchReport` is in the result, (b) C10's `BuildReport` is in the result, (c) call ordering: C11 completes before C10 starts (verifiable via a test-side hook on each component), (d) on a download failure (mock 5xx), C10 is NOT invoked and the error surfaces in `CacheBuildReport`.

**Input data**: small Derkachi sub-area + scripted fetch + a controllable mock layer.

**Expected result**: per assertion.

**Max execution time**: 5 min.

---

### C12-IT-03: trigger_post_landing_upload invokes C11 TileUploader on confirmed clean-shutdown footer

**Summary**: `trigger_post_landing_upload` reads the post-flight FDR newest-segment-first looking for a `flight_footer` record (kind registered by C13 in AZ-292; emitted exactly once per flight on `close_flight()`); if found with `payload["clean_shutdown"] == True`, it invokes `C11.TileUploader.upload_pending_tiles(UploadRequest(flight_id=..., ...))`. If the footer is absent (truncation / crash) or carries `clean_shutdown == False`, it refuses with `FlightStateNotConfirmedError`.

**Traces to**: AC-8.4

**Description**: stage two flight FDR fixtures produced by C13's `FileFdrWriter` — one with a clean-shutdown footer (the writer's standard `close_flight()` path, which always sets `clean_shutdown=True` in the current AZ-292 implementation), one truncated (writer terminated before `close_flight()` ran, so no footer record). Call `trigger_post_landing_upload`; assert (a) first case invokes upload via the `TileUploaderCut` and returns the recorded `UploadBatchReport`, (b) second case refuses with `FlightStateNotConfirmedError(not_confirmed_reason="footer_missing")`.

**Input data**: 2 FDR fixtures generated by `FileFdrWriter` (one closed cleanly; one with the close skipped).

**Expected result**: per assertion. No 30-second ON_GROUND threshold is consulted — the footer's existence + `clean_shutdown` flag is the sole signal.

**Max execution time**: 60 s.

---

### C12-IT-04: CacheBuildReport surfaces operator-actionable failures

**Summary**: when C10 reports a `ManifestSignatureError` or C11 reports stale-tile rejections beyond a configurable threshold, `CacheBuildReport` flags the build as actionable and returns a non-zero exit code from the CLI.

**Traces to**: AC-8.2 + operator UX

**Description**: simulate (a) C10 manifest signature failure, (b) C11 stale-rejection rate > 30%; assert in each case the CLI exits non-zero and the report includes a clear next-action ("re-run fetch with --since=…" or "rotate signing key").

**Input data**: scripted failure injection.

**Expected result**: actionable failure messages + non-zero exit.

**Max execution time**: 60 s.

---

## Performance Tests

### C12-PT-01: end-to-end operator workflow wall-clock

**Traces to**: AC-NEW-1 (pre-flight side; post-landing side covered by C11-PT-02).

**Load scenario**: full Derkachi area; cold C6.

**Expected results**:

| Metric | Target | Failure Threshold |
|--------|--------|-------------------|
| `build_cache` wall-clock | ≤ 18 min on a developer laptop with NVIDIA GPU (10 min download + 8 min build with overlap) | 35 min |

---

## Security Tests

### C12-ST-01: CLI rejects writes to airborne images

**Summary**: the operator-orchestrator CLI has no command path that writes into the airborne `production-binary` image (defends against operator-side mistakes that would defeat ADR-004).

**Traces to**: ADR-004 R02 enforcement (C12 side)

**Test procedure**:
1. Enumerate every CLI subcommand.
2. For each, assert the implementation does not import `c11_tilemanager` into a context that gets packaged into the airborne image (this is structural — verified at build time by the SBOM diff and at code-review time).
3. Run a runtime smoke test: invoke each subcommand with `--help`; assert no warning about C11 being loaded.

**Pass criteria**: no command path crosses into the airborne package boundary.
**Fail criteria**: any cross-boundary import.

---

## Acceptance Tests

### C12-AT-01: full operator workflow on a fresh workstation

**Summary**: an operator with a fresh workstation can install the operator-tooling tarball and complete download → build → simulated-flight → upload in one session.

**Traces to**: AC-8.3, AC-8.4

**Preconditions**:
- Fresh workstation with Docker installed.
- Operator-tooling tarball present.
- Real `satellite-provider` reachable (for download); e2e-test mock fixture (for upload) bundled in the tarball.

**Steps**: see `C11-AT-01` (C12 is the orchestrator that AT-01 exercises).

---

## Test Data Management

| Data Set | Source | Size |
|----------|--------|------|
| Operator-tooling tarball | CI build artifact | varies |
| FDR fixtures (clean-shutdown footer present / footer absent) | generated by C13 `FileFdrWriter` | <100 MB each |
| Small Derkachi sub-area for C12-IT-02 | scripted | <500 MB |

**Setup**: extract operator-tooling tarball; bring up Docker compose.
**Teardown**: stop containers; clean per-test C6.
**Data isolation**: per-test workspace under `tests/tmp/c12/<test-id>/`.
