Files
Oleksandr Bezdieniezhnykh 9a53bff92e
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
[AZ-375] [AZ-377] HashSet tile lookup + consolidate Earth constants
Batch 24 of 03-code-quality-refactoring run; closes the run.

AZ-375 (C22): GoogleMapsDownloaderV2.DownloadTilesGridAsync now
builds a HashSet<(int X, int Y, int Z)> once from existingTiles
and tests Contains((x, y, zoomLevel)) per cell. Removes the per-cell
FirstOrDefault tolerance scan and the unused _processingConfig
.LatLonTolerance reference at this site.

AZ-377 (C24): promote Earth + tile-pixel constants to a single
home. GeoUtils now exposes EarthRadiusMeters, EarthEquatorial
CircumferenceMeters, MetersPerDegreeLatitude as public const.
MapConfig adds DefaultTileSizePixels (const) wired as the
TileSizePixels property default. TileRepository and Google
MapsDownloaderV2 read those constants instead of duplicating
the literals 6378137, 40075016.686, 111000.0, and 256.

Tests: +6 new (DownloaderRefactorTests, extended GeoUtils
RefactorTests). 200/200 unit tests pass.

Cumulative K=3 review (batches 22-24): PASS_WITH_WARNINGS,
4 Low findings only — see
_docs/03_implementation/reviews/cumulative_review_22-24.md.

Tooling fix: scripts/run-tests.sh --unit-only path now restores
before testing (was failing on SixLabors resolution in clean
container). Stripped stray BOM from MapConfig.cs to satisfy the
.editorconfig charset gate.

Updates _dependencies_table.md to reflect all 27 03-code-quality-
refactoring tasks done; updates _autodev_state.md to refactor
phase 5 (test-sync).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-11 05:14:51 +03:00

11 KiB

Cumulative Code Review Report (K=3)

Batches: 22, 23, 24 Tasks covered:

  • B22: AZ-372 (C19 — dotnet format + analyzers + Coverlet)
  • B23: AZ-376 (C23), AZ-378 (C25), AZ-379 (C26), AZ-380 (C27)
  • B24: AZ-375 (C22), AZ-377 (C24) Date: 2026-05-11 Mode: Cumulative (all 7 phases on union of changed files since last cumulative review) Verdict: PASS_WITH_WARNINGS

Scope (changed files since cumulative review @ batch 21 close)

Production source:

  • SatelliteProvider.Common/Configs/MapConfig.cs
  • SatelliteProvider.Common/Utils/GeoUtils.cs
  • SatelliteProvider.DataAccess/Repositories/ITileRepository.cs
  • SatelliteProvider.DataAccess/Repositories/TileRepository.cs
  • SatelliteProvider.DataAccess/Repositories/RegionRepository.cs
  • SatelliteProvider.DataAccess/Repositories/RouteRepository.cs
  • SatelliteProvider.Services.TileDownloader/GoogleMapsDownloaderV2.cs
  • SatelliteProvider.Api/Program.cs

Tooling / config:

  • .editorconfig
  • Directory.Build.props
  • scripts/run-tests.sh

Tests added or extended:

  • SatelliteProvider.Tests/ToolingConfigurationTests.cs
  • SatelliteProvider.Tests/RepositoryRefactorTests.cs
  • SatelliteProvider.Tests/GeoUtilsRefactorTests.cs
  • SatelliteProvider.Tests/DownloaderRefactorTests.cs

Findings

# Severity Category File:Line Title
1 Low Architecture SatelliteProvider.DataAccess/SatelliteProvider.DataAccess.csproj + _docs/02_document/architecture_compliance_baseline.md (F5) DataAccess→Common dependency surface widened; baseline doc still claims "no Common dependency"
2 Low Maintainability SatelliteProvider.DataAccess/Repositories/RouteRepository.cs:38 route_points column list still inline (single use)
3 Low Spec-Gap _docs/02_tasks/done/AZ-37* task ACs Stale "37 unit + 5 smoke" test count in AC text
4 Low Maintainability SatelliteProvider.Common/Configs/MapConfig.cs TileSizePixels is now both a property default and a const; small surface duplication for compile-time consumers

Finding Details

F1: DataAccess→Common dependency surface widened (Low / Architecture)

  • Location: SatelliteProvider.DataAccess/SatelliteProvider.DataAccess.csproj (project reference); affects architecture_compliance_baseline.md Finding F5.
  • Description: AZ-377 introduces using SatelliteProvider.Common.Configs; and using SatelliteProvider.Common.Utils; in TileRepository.cs. The baseline doc (Resolved F5) and module-layout.md claim DataAccess has no Common dependency. In reality the <ProjectReference> to Common already exists in the csproj and 5 files in DataAccess (RegionRepository.cs, IRegionRepository.cs, Models/RegionEntity.cs, Models/RoutePointEntity.cs, TypeHandlers/EnumStringTypeHandler.cs) already import SatelliteProvider.Common.Enums. Batch 24 widens the surface to also include Common.Configs and Common.Utils.
  • Impact: Documentation drift only. The actual dependency graph has been DataAccess→Common since at least the AZ-309 cleanup; the baseline marked F5 "Resolved" prematurely. No new layering violation — Common stays at the leaf and DataAccess remains one level above it.
  • Suggestion: in the next documentation pass, update _docs/02_document/module-layout.md (DataAccess Imports from) and the baseline F5 entry to match reality (SatelliteProvider.Common.Enums, SatelliteProvider.Common.Configs, SatelliteProvider.Common.Utils). Do not invert the actual code dependency — the constants legitimately belong in Common and DataAccess legitimately needs them.
  • Task: AZ-377

F2: route_points column list still inline (Low / Maintainability) — carry-over from batch 23

  • Location: SatelliteProvider.DataAccess/Repositories/RouteRepository.cs:38-46
  • Description: GetRoutePointsAsync keeps its 8-column list inline; AZ-379's "extract once per repository" target is satisfied by the routes ColumnList.
  • Suggestion: extract only when a second SELECT against route_points arrives.
  • Task: AZ-379

F3: Stale "37 unit + 5 smoke" count in AC text (Low / Spec-Gap) — carry-over from batch 23

  • Location: AC-3 of AZ-375, AZ-376, AZ-377, AZ-378, AZ-379, AZ-380.
  • Description: Tasks were authored when the unit count was 37; suite now reports 200/200 passing after batch 24. The "scripts/run-tests.sh --smoke" command still gates correctly; only the literal count in the AC narrative is stale.
  • Suggestion: leave as-is — the gate is the script's exit code, not the printed number; rewriting historical AC text would create churn without changing what is verified.
  • Task: documentation/process

F4: MapConfig.TileSizePixels exists as both property and const (Low / Maintainability)

  • Location: SatelliteProvider.Common/Configs/MapConfig.cs:12-14
  • Description: AZ-377 introduces public const int DefaultTileSizePixels = 256; so DataAccess (which cannot inject IOptions<MapConfig> from a Repository constructor) can reference a single source. The property TileSizePixels keeps its setter for config binding and is now wired to the const as its default. Small surface duplication, deliberate.
  • Impact: Two access paths to the same value — MapConfig.DefaultTileSizePixels (compile-time) and IOptions<MapConfig>.Value.TileSizePixels (runtime). If a deployment ever overrides the property in appsettings.json, DataAccess will silently disagree with config-bound consumers because it reads the const.
  • Suggestion: accepted trade-off for now — appsettings.json does not currently override the value and DI in DataAccess is a separate refactor (would require pushing IOptions through the repository interface). Document the decision in MapConfig.cs (already added an XML-style comment in batch 24) and revisit if anyone overrides TileSizePixels in config.
  • Task: AZ-377

Phase results (summary)

Phase 2 — Spec compliance

  • AZ-372: format gate present (Step 0 in run-tests.sh), Directory.Build.props has analyzers + Coverlet, ToolingConfigurationTests pin them. ✓
  • AZ-376: FindExistingTileAsync removed from interface and impl (RepositoryRefactorTests AZ376_AC1 passes). ✓
  • AZ-378: RegionRepository, RouteRepository constructors take only the connection string; TileRepository keeps _logger and uses it for slow-query warnings (RepositoryRefactorTests AZ378_AC1, AC2 pass). ✓
  • AZ-379: All three repositories define exactly one private const string ColumnList; SELECTs use the const (RepositoryRefactorTests AZ379_AC1, AC2 pass). ✓
  • AZ-380: CalculatePolygonDiagonalDistance removed (GeoUtilsRefactorTests AZ380_AC1 passes). ✓
  • AZ-375: HashSet<(int, int, int)> built once and Contains((x, y, zoomLevel)) replaces the per-cell FirstOrDefault; _processingConfig.LatLonTolerance no longer referenced at this site (DownloaderRefactorTests AZ375_AC1 passes; grep confirms 0.0001 only remains in the unrelated ProcessingConfig default and tests). ✓
  • AZ-377: EarthRadiusMeters, EarthEquatorialCircumferenceMeters, MetersPerDegreeLatitude are public const double on GeoUtils; MapConfig.DefaultTileSizePixels is a public const int mirroring the property default; all source-code occurrences of 6378137, 40075016.686, 111000, and source-code occurrences of 256 are confined to those declarations (DownloaderRefactorTests + GeoUtilsRefactorTests AZ377_AC1, AC2 pass). ✓

Phase 3 — Code quality

  • All edits under SRP — no method gained more than one responsibility; HashSet builder is a small, named, local computation in the same method; logger removal from RegionRepository/RouteRepository is purely subtractive.
  • No bare catches introduced. No new debug-noise logs. No obvious duplication.

Phase 4 — Security quick-scan

  • No new SQL string interpolation (Dapper named params throughout, ColumnList is a const string, not user input).
  • No new secrets, no new external inputs.
  • Slow-query warning logs query duration and SQL text, both safe.

Phase 5 — Performance scan

  • AZ-375 directly removes an O(N) per-cell scan inside an O(grid) loop: a region of NxN tiles previously did O(N² · existingTiles) work; now O(existingTiles) preprocessing + O(1) per cell.
  • No N+1 queries introduced; the existing-tiles query batch shape is unchanged.
  • No blocking I/O in async paths added.

Phase 6 — Cross-task consistency

  • Batch 23 + 24 collectively touch the same three repositories and GoogleMapsDownloaderV2; constants moved into Common are consumed by DataAccess and the downloader uniformly. No divergent patterns.
  • AZ-379's ColumnList convention applied identically across all three repos (private const string ColumnList = @"…", used via $@"… SELECT {ColumnList} …").

Phase 7 — Architecture compliance

  • Layer direction: Common (leaf) ← DataAccess ← Services.TileDownloader ← Api. All new imports respect the table.
  • Public API respect: GeoUtils, MapConfig, and their new constants are top-level public types in Common. No internal-file imports.
  • New cyclic deps: none introduced (DataAccess→Common is one-way; Common does not reference DataAccess).
  • Duplicate symbols: the previous duplicate Earth literals across GoogleMapsDownloaderV2.cs and TileRepository.cs are now collapsed to one declaration in GeoUtils.cs. The MapConfig.TileSizePixels property + MapConfig.DefaultTileSizePixels const live in the same class — see F4.

Baseline Delta

Status Severity Title Note
Carried over Low F5 — DataAccess Common dependency drift Documentation drift; widened by AZ-377 (see F1 above).
Resolved Low duplicate Earth literals across modules Cumulative review @ batch 21 had flagged the same literals in two files; AZ-377 collapses them to a single source in GeoUtils.
Newly introduced none No new Critical / High / Medium architectural findings.

Per-category counts (current scope):

Category Critical High Medium Low
Architecture 0 0 0 1
Maintainability 0 0 0 2
Spec-Gap 0 0 0 1
Security 0 0 0 0
Performance 0 0 0 0
Bug 0 0 0 0

Test posture

  • scripts/run-tests.sh --unit-only: 200/200 PASS (10 new tests added across batches 23-24).
  • Format gate (dotnet format whitespace --verify-no-changes): PASS.
  • Full smoke / integration suite: not re-run as part of this cumulative review (next session boundary will run it before commit if the engine requires).

Verdict logic

  • 0 Critical, 0 High, 0 Medium, 4 Low → PASS_WITH_WARNINGS.
  • No FAIL conditions; no auto-fix loop required.
  1. Refresh _docs/02_document/module-layout.md and the baseline F5 entry to reflect the actual DataAccess→Common dependency (Common.Enums, Common.Configs, Common.Utils).
  2. Decide whether MapConfig.DefaultTileSizePixels should remain a const or be threaded through IOptions into DataAccess; defer until someone overrides the value in config.
  3. Consider a future task to update the AC test-count narrative across the AZ-37x tickets if/when the project does a doc-sweep.