# Refactor 02-coupling-refactoring — FINAL Report

**Mode**: automatic (user-confirmed scope at Phase 0)
**Input mode**: list-of-changes derived from architecture compliance baseline (F3 + F4)
**Date completed**: 2026-05-10
**Phases executed**: 0 (Baseline) → 1 (List of Changes) → 2 (Analysis & Decomposition) → 3 (Safety Net) → 4 (Execution) → 5 (Test Sync, inline) → 6 (Verification) → 7 (Documentation)

## Goal Achievement

| Goal (Phase 0 §Goals) | Status |
|-----------------------|--------|
| 1. `Program.cs` tile endpoints route only through `ITileService` (no direct downloader/repository/cache injections) | Done — Batch 4 (AZ-310 + AZ-311) |
| 2. Three Services csprojs with explicit ProjectReference boundaries | Done — Batch 5 (AZ-312) |
| 3. Old `SatelliteProvider.Services.csproj` deleted | Done — Batch 5 |
| 4. Unit suite: 35/35 pass | Exceeded — 40/40 pass (5 new unit tests added in Batch 4) |
| 5. Integration smoke: passing <120s | Pass — full smoke suite green post-refactor |
| 6. Baseline F3 + F4 marked Resolved | Done — Batch 6 (AZ-315), `architecture_compliance_baseline.md` shows 0 findings |
| 7. `module-layout.md` updated | Done — Batch 6 (AZ-315) |

## Baseline → Final Metrics

| Metric | Baseline (Phase 0) | Final | Delta |
|--------|--------------------|-------|-------|
| Unit tests passing | 35/35 | 40/40 | +5 (AZ-310 cache hit, repo hit, downloader fallback; AZ-311 happy path, downloader-throws) |
| Integration smoke | 5 scenarios green in 111.86s | 5 scenarios green in ~118s | Within target |
| Build time (cold) | ~30s | ~48s (Release, sln, all projects) | +18s expected — three new csprojs each restore |
| Architecture findings (compliance baseline) | F1/F2/F3/F4/F5 (2 High, 2 Medium, 1 Low) | 0 | All five Resolved |
| Project count (.csproj total) | 6 | 8 (added Services.TileDownloader / .RegionProcessing / .RouteManagement, removed Services) | Net +2 |
| Coupling indicator: Layer-3 → Layer-3 ProjectReferences | implicit (single shared project) | 0 | Compiler-enforced sibling boundary |

## Changes Summary

| Batch | Phase | Tasks | Commit | Headline outcome |
|-------|-------|-------|--------|------------------|
| 4 | A — endpoint routing | AZ-310, AZ-311 | (parent of `8b0ddae`) | F3 resolved; tile endpoints thinned to `ITileService` calls; `TileBytes` DTO added; `IMemoryCache` ownership consolidated inside `TileService`. |
| 5 | B — project split | AZ-312, AZ-313, AZ-314 | `8b0ddae` | F4 resolved; `SatelliteProvider.Services` split into three per-component csprojs; `RateLimitException` relocated to `SatelliteProvider.Common.Exceptions` to keep sibling boundary clean; per-component DI extension methods. |
| 6 | C — docs | AZ-315 | `6b37308` | F5 resolved; module-layout.md / architecture.md / compliance baseline / per-component docs synced to the post-split layout. |

Total: 6 tasks, 17 story points, 3 batches, all PASS verdicts in code review.

## Remaining Items

None for the original scope (F3, F4, F5 all resolved).

Identified but explicitly out-of-scope (deferred to future cycles):
- Coverage tooling (Coverlet) is not yet wired into the project — Phase 0 noted this as a tooling gap, not a refactor blocker.
- F1 / F2 (originally High) were already resolved before this run (testability refactor).

## Lessons Learned

1. **Cross-component exceptions need a home in Common, not in the producer.** Defining `RateLimitException` in `GoogleMapsDownloaderV2.cs` was acceptable while everything lived in one csproj. The moment we split, the consumer (`RegionService` catching it) would have needed a `ProjectReference` back to TileDownloader — defeating the purpose of the split. Lesson: any exception type that crosses component boundaries must live in `SatelliteProvider.Common.Exceptions` from day one.
2. **DI extension methods scale better than inline `Program.cs` registration.** Once each csproj owns its `Add<Component>(this IServiceCollection)`, adding a new component becomes "register the project + call one method" instead of "find the right block in `Program.cs`, copy-paste a registration".
3. **Sibling components communicate through interfaces in the foundation layer, not through ProjectReferences to each other.** The split made this structural; before, it was a convention easily violated.
4. **Smoke integration is the right safety net for a structural refactor.** Unit tests caught the obvious (constructor signature mismatches, namespace renames). Smoke tests caught the non-obvious (DI graph wiring, hosted-service registration order, Dockerfile COPY paths). Running both at every batch boundary kept the regressions to zero.
5. **One in-batch surprise is normal; budget for it.** The `RateLimitException` discovery during Batch 5's build verification was unplanned but resolvable in <30 minutes. The phased approach (Phase A endpoint routing first, Phase B split second) made the surprise small instead of compound.

## Phase 7 — Documentation Cross-References

- `_docs/02_document/architecture.md` — components list + internal communication updated.
- `_docs/02_document/module-layout.md` — three Layer-3 sections rewritten; allowed-dependencies table simplified; F5 invariant documented.
- `_docs/02_document/architecture_compliance_baseline.md` — F1..F5 statuses → Resolved; summary table now 0 findings post AZ-309.
- `_docs/02_document/diagrams/components.md` — component summary table updated; clarifying note on logical-vs-compile-time arrows.
- `_docs/02_document/components/03_tile_downloader/description.md` — csproj path + new ITileService methods.
- `_docs/02_document/modules/{common_interfaces, services_tile_service, services_google_maps_downloader, tests_unit}.md` — synced to new layout.

## Verdict

**Refactor 02-coupling-refactoring is complete.** All goals met or exceeded. No carry-over findings. No new findings introduced. Architecture compliance baseline closed.
