# Batch 09 Report — Refactor 03 Phase 2 (start)

Date: 2026-05-10
Epic: AZ-350 (03-code-quality-refactoring)
Status: ✅ Complete, pushed

## Scope (1 task / 3 SP)

| ID | C-ID | Title | Points | Component |
|----|------|-------|--------|-----------|
| AZ-359 | C07 | Consolidate 9-way catch ladder in `RegionService.ProcessRegionAsync` | 3 | Services.RegionProcessing |

Batch intentionally scoped to 1 task to (a) keep the turn manageable, (b) align with the K=3 cumulative review trigger that fires after batch 9.

## Changes

### Production
- **NEW** `SatelliteProvider.Services.RegionProcessing/RegionFailureClassifier.cs`
  - `RegionFailureCategory` enum (Timeout, ExternalCancellation, TaskCanceledOther, OperationCanceledOther, RateLimit, Network, Unexpected)
  - `RegionFailureClassification` record (Category, ErrorMessage)
  - Static pure-function `Classify(ex, timeoutCts, externalCt)` — preserves all original error-message wording so downstream summary files do not change.
  - `internal` visibility; exposed to `SatelliteProvider.Tests` via `InternalsVisibleTo`.
- **MODIFIED** `SatelliteProvider.Services.RegionProcessing/RegionService.cs`
  - Replaced 9 `catch` blocks (~50 LOC) with a single `catch (Exception ex)` (~10 LOC) that delegates to `RegionFailureClassifier.Classify` and logs a single structured warning with `category` and `errorMessage` properties. Failure-path call into `HandleProcessingFailureAsync` unchanged.
  - Net file delta: −38 lines.
- **MODIFIED** `SatelliteProvider.Services.RegionProcessing.csproj`
  - Added `<InternalsVisibleTo Include="SatelliteProvider.Tests" />` for unit-test access.

### Tests
- **NEW** `SatelliteProvider.Tests/RegionFailureClassifierTests.cs` (10 tests)
  - One per category (7) + precedence test (timeout > external cancel) + null-guard + status-code propagation in network case.
  - All ACs from `AZ-359_refactor_consolidate_region_catch_ladder.md` covered:
    - AC-1: each original case maps to the same human message — verified by string assertions on `ErrorMessage`.
    - AC-2: timeout precedence preserved — `Classify_TimeoutTakesPrecedenceOverExternalCancellation`.
    - AC-3: HTTP status code surfaced — `Classify_HttpRequestException_ReturnsNetwork_WithStatusCode`.
    - AC-4: unknown exception falls through to `Unexpected` — `Classify_UnknownException_ReturnsUnexpected`.

## Verification

- Unit tests: **68 passing** (was 58 → +10 new).
- Integration suite: full Docker run (api + db + integration-tests) → all green, container exits 0.
- API container builds clean → no compile errors in modified service.

## Behavior preservation

Observable failure path is identical:
- Same error messages stored in `region.SummaryFilePath`.
- Same `region.Status = "failed"` transition via `HandleProcessingFailureAsync`.
- Same exception types caught (no new swallowing, no narrowed coverage).
- Logging changes: 9 different log strings replaced with 1 structured log carrying `Category` as a property — net richer for log-aggregator queries while reducing source-level duplication.

## Commit

`[AZ-359] Refactor C07: collapse RegionService catch ladder via RegionFailureClassifier` — pushed to `dev`.

## Up next

- **Batch 10**: AZ-357 (drop tile Version + migration, 5 SP) — DB migration + DataAccess + TileService + tests.
- **Batch 11**: AZ-362 (idempotent POST contract, 3 SP) — Api + RegionProcessing + RouteManagement.
- **Cumulative review fires after this batch (K=3 trigger: batches 7, 8, 9 complete)** — should be the next non-implementation step.
