# Batch Report

**Batch**: 24
**Tasks**: AZ-375 (C22 — HashSet existing-tile lookup), AZ-377 (C24 — consolidate Earth + tile-pixel constants)
**Date**: 2026-05-11
**Run**: `03-code-quality-refactoring`
**Cycle**: 1

## Task Results

| Task | Status | Files Modified | Tests | AC Coverage | Issues |
|------|--------|----------------|-------|-------------|--------|
| AZ-375_refactor_on_existing_tile_lookup | Done | 1 (`GoogleMapsDownloaderV2.cs`) | 1 new (DownloaderRefactorTests AZ375_AC1) | 3/3 | None |
| AZ-377_refactor_consolidate_earth_constants | Done | 4 (`GeoUtils.cs`, `MapConfig.cs`, `TileRepository.cs`, `GoogleMapsDownloaderV2.cs`) | 5 new (DownloaderRefactorTests + GeoUtilsRefactorTests AZ377_AC1/AC2) | 3/3 | F1 in cumulative review (Low / Architecture documentation drift, non-blocking) |

Total: 4 source files modified + 1 new test file (`DownloaderRefactorTests.cs`) + 1 extended test file (`GeoUtilsRefactorTests.cs`) + 6 new test cases (5 for AZ-377 across both files, 1 for AZ-375).

## Changes

### AZ-375 — O(N) existing-tile lookup via HashSet
- `SatelliteProvider.Services.TileDownloader/GoogleMapsDownloaderV2.cs`:
  - Removed the per-cell `existingTiles.FirstOrDefault(t => Math.Abs(...) < tolerance && ... )` linear scan.
  - Added a one-time `HashSet<(int X, int Y, int Z)>` build keyed on the integer `(TileX, TileY, Zoom)` derived via the same `GeoUtils.WorldToTilePos` formula used to write the tiles.
  - Inner loop now does `existingTileKeys.Contains((x, y, zoomLevel))` — O(1) per cell.
  - `_processingConfig.LatLonTolerance` is no longer referenced at this site (tolerance was redundant since tile coordinates at a fixed zoom are integers).
- The other tolerance use site (`RouteService.cs:154` geofence polygon check) is untouched.

### AZ-377 — consolidate Earth-geometry + tile-pixel constants
- `SatelliteProvider.Common/Utils/GeoUtils.cs`:
  - Promoted `EARTH_RADIUS = 6378137` to `public const double EarthRadiusMeters = 6378137d`.
  - Added `public const double EarthEquatorialCircumferenceMeters = 40075016.686d`.
  - Added `public const double MetersPerDegreeLatitude = 111000d`.
  - Updated all internal usages in `GeoUtils` (Haversine, GoDirection, GetBoundingBox).
- `SatelliteProvider.Common/Configs/MapConfig.cs`:
  - Added `public const int DefaultTileSizePixels = 256`.
  - `TileSizePixels` property default now references the const.
  - Added inline doc comment explaining why both surfaces exist (DataAccess cannot inject `IOptions<MapConfig>` from a Repository ctor).
- `SatelliteProvider.Services.TileDownloader/GoogleMapsDownloaderV2.cs`:
  - `CalculateTileSizeInMeters` now reads `GeoUtils.EarthEquatorialCircumferenceMeters` instead of a local `EARTH_CIRCUMFERENCE_METERS` const.
- `SatelliteProvider.DataAccess/Repositories/TileRepository.cs`:
  - Added `using SatelliteProvider.Common.Configs;` and `using SatelliteProvider.Common.Utils;`.
  - `GetTilesByRegionAsync` now uses `GeoUtils.EarthEquatorialCircumferenceMeters`, `GeoUtils.MetersPerDegreeLatitude`, and `MapConfig.DefaultTileSizePixels` — all local literals (`EARTH_CIRCUMFERENCE_METERS`, `TILE_SIZE_PIXELS`, two `111000.0` occurrences) removed.

### Test additions
- `SatelliteProvider.Tests/DownloaderRefactorTests.cs` (new):
  - `GoogleMapsDownloaderV2_UsesHashSetForExistingTileLookup_AZ375_AC1` — file-content assertion that the FirstOrDefault scan and `_processingConfig.LatLonTolerance` are gone and replaced by a typed HashSet + `Contains` call.
  - `GoogleMapsDownloaderV2_UsesGeoUtilsCircumferenceConstant_AZ377_AC1` — verifies the downloader routes through `GeoUtils.EarthEquatorialCircumferenceMeters`.
  - `TileRepository_UsesGeoUtilsAndMapConfigConstants_AZ377_AC1` — verifies the repository uses the `Common` constants and no local Earth literals remain.
  - `GeoUtils_IsTheSoleHolderOfRawEarthLiterals_AZ377_AC1` — pins `GeoUtils.cs` as the single declaration site.
  - `HaversineDistance_WithTinyDelta_UsesEarthRadiusConstantConsistently_AZ377_AC2` — numerical equivalence check (recomputes the expected value from the same constant and asserts byte-level identity).
- `SatelliteProvider.Tests/GeoUtilsRefactorTests.cs` (extended):
  - `GeoUtils_ExposesEarthConstantsAsPublicConst_AZ377_AC1` — `[Theory]` with three inline data rows; reflection check for `IsLiteral`, type, and value.
  - `MapConfig_ExposesDefaultTileSizePixelsConst_AZ377_AC1` — verifies the const exists and the property default still resolves to it.
  - `GeoUtils_HaversineProducesIdenticalResultAfterConstantRename_AZ377_AC2` — quick value-pin sanity check.

### Tooling fix discovered during batch
- `scripts/run-tests.sh` `--unit-only` path was running `dotnet test --no-restore` without an explicit `dotnet restore` first; this caused `SixLabors.ImageSharp` resolution to fail in a clean container. Wrapped the command with `sh -c "dotnet restore ... && dotnet test --no-restore ..."` to mirror the `--full` path. Pure infrastructure fix — not a refactor task.
- Stripped a stray UTF-8 BOM from `MapConfig.cs` introduced during the AZ-377 edits, to satisfy the `dotnet format whitespace --verify-no-changes` gate (`charset = utf-8` in `.editorconfig`).

## Test Results

`scripts/run-tests.sh --unit-only`:
- Format gate: PASS
- Unit tests: 200/200 PASS (190 prior + 10 new)
- Coverage: written to `./TestResults/`

## Cumulative Review (K=3, batches 22-24)

Triggered after batch 24. Verdict: **PASS_WITH_WARNINGS**.

- 0 Critical, 0 High, 0 Medium, 4 Low findings.
- Report: `_docs/03_implementation/reviews/cumulative_review_22-24.md`.
- One Low / Architecture finding (F1) flags a pre-existing documentation drift around DataAccess→Common dependency (the project reference was already there; AZ-377 widens the surface from `Common.Enums` to also include `Common.Configs` and `Common.Utils`). Recommended follow-up: refresh `module-layout.md` and the architecture baseline F5 entry. Not blocking.

## Files Modified

Production:
- `SatelliteProvider.Services.TileDownloader/GoogleMapsDownloaderV2.cs`
- `SatelliteProvider.Common/Utils/GeoUtils.cs`
- `SatelliteProvider.Common/Configs/MapConfig.cs`
- `SatelliteProvider.DataAccess/Repositories/TileRepository.cs`

Tests:
- `SatelliteProvider.Tests/DownloaderRefactorTests.cs` (new)
- `SatelliteProvider.Tests/GeoUtilsRefactorTests.cs` (extended)

Tooling:
- `scripts/run-tests.sh` (unit-only path now restores before testing)

Docs / state:
- `_docs/02_tasks/done/AZ-375_refactor_on_existing_tile_lookup.md` (moved from todo)
- `_docs/02_tasks/done/AZ-377_refactor_consolidate_earth_constants.md` (moved from todo)
- `_docs/03_implementation/batch_24_report.md` (this file)
- `_docs/03_implementation/reviews/cumulative_review_22-24.md`
- `_docs/_autodev_state.md`

## Status

- Both batch-24 tasks DONE.
- Batches 22-24 cumulative review COMPLETE; verdict PASS_WITH_WARNINGS.
- 03-code-quality-refactoring run: 6/6 tasks done (AZ-372, AZ-375, AZ-376, AZ-377, AZ-378, AZ-379, AZ-380 — note: 7 tracker IDs because AZ-372 covers tooling C19 separately from the C-prefixed change items).
- Refactoring epic (AZ-309 / AZ-350) progress: see traceability table.
