# Test Specification — C4 Pose Estimator

Component-scoped. Suite-level coverage in `_docs/02_document/tests/*.md`.

## Acceptance Criteria Traceability

| AC ID | Acceptance Criterion (one-line) | Test IDs | Coverage |
|-------|---------------------------------|----------|----------|
| AC-1.1 | Frame-center GPS within 50 m for ≥80% of normal-flight photos | FT-P-01, **C4-IT-01** | Covered |
| AC-1.2 | Frame-center GPS within 20 m for ≥50% | FT-P-01, **C4-IT-01** | Covered |
| AC-1.4 | Estimate reports 95% covariance + source label | FT-P-03, **C4-IT-02** | Covered |
| AC-4.1 | E2E latency <400 ms p95 (incl. Marginals) | NFT-PERF-01, **C4-PT-01** | Covered |
| AC-NEW-5 | Operating envelope; thermal-throttle-driven covariance degradation hybrid | NFT-LIM-04, **C4-IT-03** | Covered (workstation portion) |

---

## Component-Internal Tests

### C4-IT-01: PnP convergence + WGS84 accuracy on Derkachi

**Summary**: for the Derkachi normal segment, p80 of frame-center positions land within 50 m of ground truth, p50 within 20 m.

**Traces to**: AC-1.1, AC-1.2

**Description**: feed `MatchResult` from C3 (Derkachi normal-segment fixture) into `estimate`; convert `position_wgs84` to local frame; compute distance to recorded GPS ground truth; assert p80 ≤ 50 m and p50 ≤ 20 m.

**Input data**: `flight_derkachi/normal_segment_60_stills/` (with recorded GPS ground truth) + corresponding C3 `MatchResult` outputs (replayed from a recorded fixture so the test is C4-isolated).

**Expected result**: p80 ≤ 50 m, p50 ≤ 20 m.

**Max execution time**: 60 s.

---

### C4-IT-02: 6×6 covariance is SPD and honest under match degradation

**Summary**: every emitted `PoseEstimate` carries an SPD `covariance_6x6`; under inlier degradation (synthetically reduced inlier count), the covariance norm rises monotonically.

**Traces to**: AC-1.4

**Description**: replay 100 frames; for each, assert (a) covariance is symmetric and positive-definite, (b) when a fixture-injected inlier-degradation event occurs at frame 50, the cov norm rises and stays elevated for ≥10 frames. Also assert `source_label` reflects the gate state — `satellite_anchored` only when C5's gate confirms; `visual_propagated` otherwise.

**Input data**: `synthetic_matcher/inlier_degradation_at_f50/`.

**Expected result**: 100/100 frames pass SPD invariant; cov norm rises ≥1.5× steady-state for the degradation interval.

**Max execution time**: 60 s.

---

### C4-IT-03: D-CROSS-LATENCY-1 hybrid auto-degrade switch

**Summary**: when `ThermalState.throttle == true`, `current_covariance_mode()` returns `JACOBIAN`; when false, returns `MARGINALS`. The switch is per-frame.

**Traces to**: AC-NEW-5 (workstation-baseline portion; hot-soak chamber deferred)

**Description**: drive a 60 s replay alternating thermal flag every 5 s; assert `covariance_mode` in each emitted `PoseEstimate` matches the input thermal flag for that frame; assert no jitter or hysteresis (the spec calls for per-frame decision).

**Input data**: synthetic frames + a `ThermalState` injection harness.

**Expected result**: 100% match between thermal input and `covariance_mode` output.

**Max execution time**: 90 s.

---

### C4-IT-04: shared-graph integration with C5

**Summary**: factors added by C4 to C5's iSAM2 graph survive an `update`/`marginalCovariance` cycle without corrupting prior keyframes.

**Traces to**: AC-1.4 (defensive — backstops the C4↔C5 shared-substrate co-dependency per ADR-003)

**Description**: in a single test process, instantiate C5 with a 10-keyframe synthetic prior; have C4 add a `GenericProjectionFactorCal3DS2` for keyframe 11; trigger iSAM2 update; assert (a) the previously-known keyframe poses change by less than configurable tolerance (10 cm position, 0.5° rotation), (b) marginals on every keyframe remain SPD.

**Input data**: synthetic 10-keyframe iSAM2 prior + a known correspondence set.

**Expected result**: prior-keyframe perturbations within tolerance; SPD invariant holds.

**Max execution time**: 60 s.

---

## Performance Tests

### C4-PT-01: Marginals vs Jacobian path latency on Tier-2

**Traces to**: AC-4.1

**Load scenario**: 3 Hz, 10 min replay; thermal flag toggled every 30 s to exercise both modes.

**Expected results**:

| Metric | Target | Failure Threshold |
|--------|--------|-------------------|
| `estimate` p95 (MARGINALS, K=15) | ≤ 90 ms | 130 ms |
| `estimate` p95 (JACOBIAN) | ≤ 15 ms | 25 ms |
| Mode-switch latency | < 1 frame (i.e., next-frame switch) | > 1 frame |

---

## Security Tests

C4 has no externally-reachable surface.

---

## Acceptance Tests

Covered transitively via FT-P-01 / FT-P-03 / FT-P-09-AP / FT-P-09-iNav.

---

## Test Data Management

| Data Set | Source | Size |
|----------|--------|------|
| Replayed C3 `MatchResult` for Derkachi | recorded once via fixture-build script | ~30 MB |
| `synthetic_matcher/inlier_degradation_at_f50/` | generated | ~10 MB |
| Synthetic 10-keyframe iSAM2 prior | scripted | <1 MB |

**Setup**: replay fixture must be re-recorded if C3's output schema changes (versioned in `tests/fixtures/c4_inputs/<schema-version>/`).
**Teardown**: read-only.
**Data isolation**: per-test temp dirs.
