# sitl_observer FDR-replay surfaces + scenario probe cleanup

**Task**: AZ-595_sitl_observer_fdr_replay
**Name**: Implement all 11 sitl_observer surfaces with an FDR-replay strategy + refactor scenario probes
**Description**: Replace `NotImplementedError` and stub patterns across `sitl_observer.py` with file-backed JSON readers. Refactor the brittle `_harness_helpers_implemented` probes in 8 scenarios to use an explicit `E2E_SITL_REPLAY_DIR` env-var check.
**Complexity**: 5 points
**Dependencies**: AZ-406, AZ-594
**Component**: Blackbox Tests / Test Infrastructure (epic AZ-262)
**Tracker**: AZ-595
**Epic**: AZ-262 (E-BBT)

## Problem

The `sitl_observer` module reserved 11 surfaces in AZ-406 and never
came back to fill them. Scenarios in batches 71-73 work around it
with a `_harness_helpers_implemented` probe that passes a fake path
to each helper and inspects the exception type — fragile and
misleading post-fix once underlying helpers stop raising
`NotImplementedError` (as they now do after batch 74).

## Outcome

- `sitl_observer.py` implements all 11 surfaces using an FDR-replay
  strategy: each surface reads its fixture from
  `${E2E_SITL_REPLAY_DIR}/<surface_name>.json` and returns a typed
  result. Missing env var or missing file → empty result for `read_*`
  surfaces; explicit `RuntimeError` for surfaces that require live
  data.
- Scenario probes refactored to use a single `_e2e_sitl_replay_dir_available`
  fixture that returns True iff env var is set + directory exists.
  No more fake-path exception-introspection.

## Scope

### Included
- `sitl_observer.get_observer` + 10 free-function surfaces.
- Typed dataclasses for the read_* / capture_* / observe_* / query_*
  return types.
- Comprehensive unit tests.
- Probe refactor across the 8 affected scenarios.

### Excluded
- `fc_proxy_runtime` driver (separate ticket).
- Live pymavlink / yamspy / TCP plumbing.
- Per-scenario fixture builders (the JSON files that go in
  `E2E_SITL_REPLAY_DIR` for each scenario).

## Acceptance Criteria

**AC-1**: Each surface returns its typed result by parsing JSON at
`${E2E_SITL_REPLAY_DIR}/<surface_name>.json`. Missing env var →
returns empty list / vacuous result (for `read_*`) OR raises
`RuntimeError` (for surfaces requiring non-empty fixtures).

**AC-2**: Probe pattern in the 8 affected scenarios replaced with
`_e2e_sitl_replay_dir_available` fixture (True only when env var set
AND directory exists).

**AC-3**: ≥5 unit tests per surface category.

**AC-4**: Full e2e unit-test suite passes (regression gate).

## System Under Test Boundary

None — runner-side helper that parses runner-produced fixture files.
No `src/gps_denied_onboard` imports.

## Constraints

- Same `time.sleep` injection / `realtime` pattern as
  `frame_source_replay` and `imu_replay` where pacing applies (e.g.
  `capture_ap_tlog(duration_s)` should not block real wall-clock in
  tests).
- File-not-found surfaces with clear `RuntimeError` messages that
  point at the env var.
- All public dataclasses immutable (`frozen=True`).

## Document Dependencies

- `_docs/02_document/tests/blackbox-tests.md` § Test infrastructure
- `_docs/02_tasks/done/AZ-594_harness_stubs_core_three.md`
