# Baseline Metrics — Run 02-az507-routespec-relocation **Date**: 2026-05-23 **Run**: `_docs/04_refactoring/02-az507-routespec-relocation/` **Mode**: guided **Source**: cycle-3 cumulative review (`_docs/03_implementation/cumulative_review_batches_104-109_cycle3_report.md`) — F1, F2, F3 **Scope**: mechanical relocation of cross-component DTO + module-layout doc refresh + AZ-270 lint scope expansion ## Why a minimal baseline is appropriate for this run The standard Phase-0 baseline metric grid (overall coverage, complexity, code smells, performance, dependencies, build time) is **not the right instrument** for this refactoring run. The work is a structural relocation of one frozen dataclass + a documentation refresh + a lint widening. Behaviour does not change; performance does not change; coverage does not change; dependency count does not change. A LOC-and-cyclomatic-complexity baseline would record near-zero deltas and would obscure the actual signal — whether the architectural rule (`module-layout.md` rule 9) is satisfied after the run. What matters here, and is captured below, is: 1. The **structural baseline**: one rule-9 violation today (F1). 2. The **test baseline**: which tests cover the affected import paths and that they pass at HEAD (the safety net for Phase 4). 3. The **doc baseline**: which artifacts are stale (F2) and what "complete" looks like. 4. The **lint baseline**: what AZ-270 currently catches vs. what rule 9 says it should catch (F3). Phases 5/6 verify that (a) the structural baseline goes from 1 → 0 rule-9 violations, (b) every test still passes, (c) the doc baseline is reconciled, and (d) the lint baseline is widened. ## 1. Structural baseline (rule-9 violations) Source of truth: `_docs/02_document/module-layout.md` rule 9 (AZ-507 cross-component contract surface). | # | File | Importer (Component) | Imported (Module) | Allow-listed for importer? | |---|------|----------------------|-------------------|----------------------------| | 1 | `src/gps_denied_onboard/components/c11_tile_manager/route_client.py:56` | `c11_tile_manager` | `gps_denied_onboard.replay_input.tlog_route` (`RouteSpec`) | **NO** — `replay_input` not in c11's allow-list | Search method: `rg "^from gps_denied_onboard\." src/gps_denied_onboard/components` filtered against the allow-list (`_types/*`, `_types.inference_errors`, `helpers/*`, `config`, `logging`, `fdr_client`, `clock`, `frame_source`). **Target post-run**: 0 violations. ## 2. Test baseline (safety net for Phase 4) Files that import `RouteSpec`, `SatelliteProviderRouteClient`, or `RouteSeedResult` (i.e. the symbols the relocation touches): **Production source** (must be updated): - `src/gps_denied_onboard/components/c11_tile_manager/route_client.py` — defines the import to be re-pointed - `src/gps_denied_onboard/components/c11_tile_manager/__init__.py` — public API re-exports (no import path change) - `src/gps_denied_onboard/replay_input/tlog_route.py` — defines `RouteSpec` today (will lose the local definition, gain an import + alias) - `src/gps_denied_onboard/replay_input/__init__.py` — public API re-exports (will re-export from `_types.route` instead of `tlog_route`) **Tests** (verify still pass; update imports only if they reach into the pre-relocation internal path `replay_input.tlog_route` directly): - `tests/unit/replay_input/test_tlog_route.py` (14 tests; producer-side) - `tests/unit/c11_tile_manager/test_route_client.py` (consumer-side unit tests) - `tests/integration/c11_tile_manager/test_route_client_e2e.py` (integration) - `tests/e2e/replay/conftest.py` - `tests/e2e/replay/_operator_pre_flight.py` - `tests/e2e/replay/test_operator_pre_flight_driver.py` - `tests/e2e/replay/test_operator_pre_flight_integration.py` - `tests/e2e/replay/_e2e_orchestrator.py` - `tests/e2e/replay/test_e2e_orchestrator_unit.py` - `tests/fixtures/derkachi_c6/seed_route.py` **HEAD test status (asserted, not measured here)**: per cycle-3 batch reports 104, 106, 107, 108, 108b, 109, every committed batch ended with passing tests at the per-batch full run. The cumulative review (FAIL on F1) is a static-analysis verdict, not a test-run verdict — no test failures are attributable to F1 today. Phase 4 will run the affected test files first; Phase 6 runs the project's full test gate per the existing-code flow's test policy. ## 3. Doc baseline (F2 surface area) `_docs/02_document/module-layout.md` is stale relative to on-disk reality. The following entries diverge today: **c11_tile_manager — Internal list** lists 2 files (`satellite_provider_downloader.py`, `satellite_provider_uploader.py`); on-disk has 8 internal files plus `route_client.py` (cycle-3 NEW). Missing entries: `_types.py`, `config.py`, `errors.py`, `idempotent_retry.py`, `signing_key.py`, `tile_downloader.py`, `tile_uploader.py`, `route_client.py`. **shared/replay_input file list** lists `__init__.py`, `interface.py`, `tlog_video_adapter.py`, `auto_sync.py`, `tests/`; on-disk adds `errors.py` (cycle-2 carry), `tlog_ground_truth.py` (cycle-2 carry), `tlog_route.py` (cycle-3 NEW). After the relocation, `tlog_route.py` stays (it still owns `extract_route_from_tlog`); `_types/route.py` is added. **Cycle-2 carry-overs** still unaddressed (out of this run's scope unless the user expands it; surfaced in F2 of the cumulative review): - `replay_api/` package (7 files; needs Per-Component Mapping entry). - `cli/render_map.py`, `cli/replay_api_entrypoint.py` (need Shared section entries). - `helpers/gps_compare.py`, `helpers/accuracy_report.py` (need Shared section entries). **Target post-run** (in-scope): c11_tile_manager Internal list refreshed (route_client + the 7 long-standing internals); shared/replay_input file list refreshed (tlog_route + tlog_ground_truth + errors); new `_types/route.py` registered. Cycle-2 carry-overs are deferred to a separate doc-only task unless user expands scope. ## 4. Lint baseline (F3) `tests/unit/test_az270_compose_root.py:194-219` (`test_ac6_only_compose_root_imports_concrete_strategies`) walks `src/gps_denied_onboard/components/**/*.py` and flags only edges whose `node.module` starts with `gps_denied_onboard.components.` AND whose leaf-component is not the importer's component. The full rule-9 allow-list (8 prefixes plus `frame_source` interface-only restriction) is NOT enforced. **Concrete miss demonstrated by F1**: the c11 → replay_input edge passes this lint silently because `replay_input` is not under `components/`. **Target post-run** (in-scope): expand the lint to enforce rule 9's full allow-list. Remaining design choices (whether to allow `frame_source` non-interface modules, whether to treat `runtime_root` exception case-sensitively) are addressed in C03's task spec. ## 5. Functionality inventory This run touches no public-feature surfaces. The DTO `RouteSpec` continues to be re-exported from `gps_denied_onboard.replay_input` (the public package), so consumers using `from gps_denied_onboard.replay_input import RouteSpec` see no change. Consumers reaching into `replay_input.tlog_route` directly (an internal-module path) will need their imports updated — this set is small and lives entirely under `tests/`. There is no operator-facing CLI / endpoint / config schema change. ## Self-verification - [x] RUN_DIR created with auto-incremented prefix (`02-az507-routespec-relocation`; previous: `01-testability-refactoring`) - [x] All metric categories reasoned about — standard categories noted N/A with reason; relevant baselines (structural, test, doc, lint) captured - [x] Functionality inventory complete (no functionality change in scope) - [x] Measurements are reproducible (rg + glob commands documented) ## BLOCKING — Phase 0 gate Awaiting user confirmation of: 1. The minimal-baseline rationale (no LOC/coverage/perf metrics for a mechanical relocation). 2. The structural / test / doc / lint baseline above as the "before" state Phase 6 will compare against. 3. The scope decision: cycle-2 doc carry-overs are **OUT** of this run unless explicitly expanded. If confirmed, Phase 1 produces `RUN_DIR/list-of-changes.md` (already drafted alongside this file as the guided-mode input).