# Refactoring Roadmap — Run 02-az507-routespec-relocation

**Date**: 2026-05-23
**Run**: `_docs/04_refactoring/02-az507-routespec-relocation/`

## Weak Points Assessment

| # | Location | Description | Impact | Proposed Solution |
|---|----------|-------------|--------|------------------|
| W1 | `src/gps_denied_onboard/components/c11_tile_manager/route_client.py:56` | Imports `RouteSpec` from `gps_denied_onboard.replay_input.tlog_route`, violating module-layout.md rule 9 (AZ-507 cross-component contract surface). | High — the next task that imports a similarly-placed DTO compounds the drift; current AZ-270 lint cannot catch it (W3). | C01: relocate the DTO to `_types/route.py`. |
| W2 | `_docs/02_document/module-layout.md` (c11_tile_manager Internal list, shared/replay_input file list) | Stale relative to on-disk reality — cycle-3 additions (`route_client.py`, `tlog_route.py`) and 7 cycle-2-era cycle-internal files are unregistered in their respective sections. | Medium — `/implement` Step 4 ownership check would BLOCK any future task touching unregistered areas. Severity escalates to High if a fourth consecutive cycle leaves it stale. | C02: refresh the c11_tile_manager Internal list, the shared/replay_input file list, and add `_types/route.py`. Defer cycle-2 carry-overs outside these sections. |
| W3 | `tests/unit/test_az270_compose_root.py:194-219` | The AC-6 lint walks `components/**/*.py` and only flags `components.<X> → components.<Y>` edges, not the full rule-9 allow-list. | Medium — rule-9 enforcement is partially honor-system; F1 is the concrete consequence. | C03: widen the AST walker to enforce the full allow-list. |

## Gap Analysis

| AC of this run | Current state | Target state |
|---|---|---|
| Rule-9 violations resolved | 1 (route_client → replay_input) | 0 |
| `module-layout.md` cycle-3 entries registered | Missing: `route_client.py`, `tlog_route.py`, plus 7 cycle-2-era omissions in two sections | All cycle-3 entries registered; 9 omissions in the c11 + replay_input sections fixed; new `_types/route.py` registered |
| AZ-270 lint scope = rule-9 scope | Narrow (one prefix only) | Full allow-list enforced |

## Phased Roadmap

This run is a single phase by intent — three small structural fixes that share the same root cause (rule-9 enforcement gap). Sequencing within the phase:

1. **C01 → first** (the structural fix). Lands `_types/route.py`, retires the violating import, keeps producer-side back-compat via re-export.
2. **C02 → second** (depends on C01 because the new `_types/route.py` entry needs the file to exist). Documentation refresh; no code touch.
3. **C03 → third** (depends on C01 because the widened lint must see a clean codebase). The new lint becomes a gate for any future PR.

| Phase | Items | Rationale |
|-------|-------|-----------|
| Phase 1 (this run) | C01, C02, C03 | All three resolve the same cumulative-review FAIL surface; bundling them ensures rule-9 enforcement is consistent across code, doc, and lint after the run. |

No Phase 2 or Phase 3. The cumulative review's "out of scope" items (cycle-2 doc carry-overs, the shared_types/route.md contract doc, `architecture_compliance_baseline.md`) belong to other tasks and are explicitly deferred — not folded into this roadmap.

## Hardening tracks

| Track | Recommendation | Rationale |
|-------|----------------|-----------|
| A — Technical Debt | Skip | The run *is* technical-debt remediation (closing a rule-9 enforcement gap). Adding a separate track would expand scope artificially. |
| B — Performance Optimization | Skip | No performance concern in scope. Relocation is identity-preserving; tests do not measure perf deltas. |
| C — Security Review | Skip | No security surface affected. `RouteSpec` carries waypoint coordinates only (already shipped to operator's tlog input); the move does not change any auth, transport, or input-validation path. |
| D — All of the above | Skip | See A/B/C. |
| E — None | **Selected (default for this run)** | All three changes are themselves the structural fix; orthogonal hardening would dilute scope. The cycle-3 retrospective list captures the broader debt items (cycle-2 carry-overs, baseline doc) for separate runs. |

This default is recorded explicitly so the user can override at the Phase 2 BLOCKING gate. If the user wants Track C (security audit on the route-extraction path) or Track A (folding the cycle-2 carry-overs into this run), the roadmap and task list will be regenerated.

## Selected items

All `Selected`:

- C01 — Relocate `RouteSpec` to `_types/route.py` (2 SP, low risk).
- C02 — Refresh `module-layout.md` cycle-3 entries (2 SP, low risk).
- C03 — Widen `test_az270_compose_root` lint to full rule-9 allow-list (2 SP, medium risk).

**Total**: 6 SP across 3 tasks. Each task is within the user-rule cap (≤ 5 SP per task; recommended 2-3).

## Applicability gate

| Recommendation | Status | Notes |
|---|---|---|
| C01 | Selected | No constraint mismatches; identity-preserving move; backward compat via re-export. |
| C02 | Selected | Doc-only; no test impact; scope-disciplined (cycle-2 carry-overs explicitly deferred). |
| C03 | Selected | Risk-flagged: widening may expose unrelated rule-9 violation. STOP-and-surface protocol applies if encountered. |

No `Rejected`, no `Experimental only`, no `Needs user decision`. The Phase 2 applicability gate passes for task creation.

## ADR-supersede gate

`No ADRs in scope` — see `adr_impact.md`. Gate satisfied; no Violation/Drift/Aligned rows.
