Files
satellite-provider/_docs/03_implementation/reviews/batch_09_review.md
T
Oleksandr Bezdieniezhnykh 581dff206e
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
[AZ-357] Refactor C06: drop tile Version concept; cumulative review batches 7-9
AZ-357 — eliminate year-based tile cache expiry (LF-1):
- Migration 012: drop 5-col unique index, dedupe by (lat,lon,zoom,
  size) keeping max(updated_at), add new 4-col unique index, make
  version column nullable + drop default. Column itself preserved
  per coderule (column drops require explicit confirmation; tracked
  in AZ-373 / C20).
- TileEntity.Version, TileMetadata.Version, DownloadTileResponse.
  Version: int -> int? (HTTP shape preserved; field still in JSON).
- TileService.DownloadAndStoreTilesAsync: drop currentVersion year
  computation and the .Where(t => t.Version == currentVersion)
  cache filter. BuildTileEntity: drop year arg; write Version=null.
- TileRepository: ON CONFLICT now 4-col; lookup queries
  ORDER BY updated_at DESC instead of version DESC.
- Tests: replace inverted BT02b with positive AZ357_AC1
  (prior-year cached tile is reused). Add BuildTileEntity_
  DoesNotPopulateVersion_AZ357 to enforce the no-write contract.
- 69 unit + 5 smoke + 3 stub-contract integration tests pass.

Cumulative code review (batches 7-9, 7 tasks): VERDICT=PASS.
Report at _docs/03_implementation/reviews/batch_09_review.md.
Zero Critical/High/Medium/Low findings. Architecture baseline
remains clean.

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

10 KiB
Raw Blame History

Code Review Report — Cumulative (Batches 7+8+9)

Batch: 9 (cumulative; covers batches 7, 8, 9) Tasks reviewed: AZ-351, AZ-352, AZ-353, AZ-354, AZ-356, AZ-359, AZ-363 Date: 2026-05-10 Mode: Cumulative (Phases 17 on union of changed files since last review) Verdict: PASS Critical: 0 | High: 0 | Medium: 0 | Low: 0

Files in scope

File Tasks Change
SatelliteProvider.Api/Program.cs AZ-351, AZ-353, AZ-354, AZ-356 Modified (DI rewire, CORS validator, exception handler middleware, 501 stubs, removed per-endpoint try/catch)
SatelliteProvider.Api/GlobalExceptionHandler.cs AZ-353 New
SatelliteProvider.Api/CorsConfigurationValidator.cs AZ-354 New
SatelliteProvider.Services.RegionProcessing/RegionService.cs AZ-359 Modified (catch ladder collapsed)
SatelliteProvider.Services.RegionProcessing/RegionFailureClassifier.cs AZ-359 New
SatelliteProvider.Services.RegionProcessing/RegionRequestQueue.cs AZ-363 Modified (counters removed)
SatelliteProvider.Services.RegionProcessing/SatelliteProvider.Services.RegionProcessing.csproj AZ-359 Modified (InternalsVisibleTo)
SatelliteProvider.Services.RouteManagement/RouteProcessingService.cs AZ-352 Modified (empty catch removed; static→instance method)
SatelliteProvider.Services.RouteManagement/SatelliteProvider.Services.RouteManagement.csproj AZ-352 Modified (InternalsVisibleTo)
SatelliteProvider.Tests/CorsConfigurationValidatorTests.cs AZ-354 New (9 tests)
SatelliteProvider.Tests/GlobalExceptionHandlerTests.cs AZ-353 New (3 tests)
SatelliteProvider.Tests/RegionFailureClassifierTests.cs AZ-359 New (10 tests)
SatelliteProvider.Tests/RouteProcessingServiceTests.cs AZ-352 New (4 tests)
SatelliteProvider.Tests/SatelliteProvider.Tests.csproj AZ-353 Modified (added SatelliteProvider.Api ProjectReference for unit testing API-layer types)
SatelliteProvider.IntegrationTests/StubAndErrorContractTests.cs AZ-356, AZ-353 New (3 integration tests)
SatelliteProvider.IntegrationTests/Program.cs AZ-356 Modified (registers new test class in smoke + full suites)

Findings

No findings of any severity.

Phase Summaries

Phase 1 — Context loading

Read all 7 task specs from _docs/02_tasks/done/, _docs/02_document/architecture_compliance_baseline.md, _docs/02_document/module-layout.md, plus changed source files.

Phase 2 — Spec compliance

Task AC Evidence
AZ-351 (C01) Logger resolved via DI as ILogger<DatabaseMigrator> Program.cs:96app.Services.GetRequiredService<ILogger<DatabaseMigrator>>()
AZ-352 (C02) AC-1 Empty catch removed; warning logged with structured fields RouteProcessingService.cs:610-628_logger.LogWarning("...{FilePath}...", filePath)
AZ-352 (C02) AC-2 Null-guard on filePath RouteProcessingService.cs:612ArgumentNullException.ThrowIfNull(filePath)
AZ-352 unit tests 4 tests cover valid name, malformed, non-numeric coords, null path RouteProcessingServiceTests — 4 passing
AZ-353 (C03) AC-1 5xx → sanitized application/problem+json with correlationId GlobalExceptionHandler.cs:30-53 + unit test TryHandleAsync_WritesSanitizedProblemDetailsAndReturnsTrue_AC1
AZ-353 AC-2 Full exception logged server-side with correlation ID GlobalExceptionHandler.cs:30-35 + unit test ..._LogsFullExceptionWithCorrelationId_AC2
AZ-353 AC-3 4xx framework errors NOT promoted to 5xx GlobalExceptionHandler.cs:22-26 (BadHttpRequestException branch) + unit test ..._BadHttpRequestException_HonorsFrameworkStatusAndDoesNotErrorLog_AC3 + integration CreateRoute_InvalidPayload_Returns400_AZ353_AC3
AZ-354 (C04) AC-1 Production with empty origins + no opt-in → throw CorsConfigurationValidator.cs:14-28 + unit test ..._ProductionWithEmptyOriginsAndNoOptIn_Throws_AC1
AZ-354 AC-2 Non-Production with empty origins → no throw, warning emitted Program.cs:89-94 + unit tests for Dev/Staging/Local
AZ-354 AC-3 Explicit AllowAnyOrigin=true opt-in → no throw in Prod Unit test ..._ProductionWithExplicitAllowAnyOrigin_DoesNotThrow_AC3
AZ-356 (C05) AC-1 Stub endpoints return 501 ProblemDetails Program.cs:178-192 + integration tests StubMgrs_Returns501, StubUpload_Returns501
AZ-356 OpenAPI .ProducesProblem(501) declared on stub endpoints Program.cs:124, 129
AZ-359 (C07) AC-1 Same observable failure-path messages preserved RegionFailureClassifier.cs:30-69 — string assertions in 7 unit tests
AZ-359 AC-2 RegionTests still green (timeout + rate-limit covered) RegionServiceTests.ProcessRegionAsync_DownloaderFailure_* passing
AZ-359 AC-3 37+ unit + 5 smoke green 68 unit + 5 smoke + 3 stub-contract integration — all pass
AZ-363 (C10) Write-only counters removed RegionRequestQueue.cs — no _totalEnqueued/_totalDequeued fields remain

All ACs traced and demonstrably satisfied. No Spec-Gap findings.

Phase 3 — Code quality

  • SOLID: All three new types have a single, sharply-named responsibility. GlobalExceptionHandler handles 5xx sanitization; CorsConfigurationValidator validates CORS config; RegionFailureClassifier maps exceptions to a typed failure category. None depend on more than the minimum needed.
  • Error handling: AZ-352 fix is correct — the previously empty catch {} is gone; failures now log a warning with structured fields and return a sentinel (-1, -1). AZ-359 fix collapses 9 catches into 1; same exception types still caught (no broadening or narrowing). AZ-353 explicitly preserves the framework's 4xx status — addresses a subtle prior-art trap where naive IExceptionHandler would have promoted all errors to 500.
  • Naming: RegionFailureCategory, RegionFailureClassification, EnsureSafeForEnvironment, ShouldUsePermissivePolicy, ShouldWarnAboutPermissiveDefault all read clearly from caller perspective.
  • Complexity: RegionService.ProcessRegionAsync shrinks ~50 LOC of duplicated catch handling to ~10 LOC. No new method exceeds 50 lines; no new cyclomatic-complexity hotspot.
  • DRY: Three meaningful DRY wins — (a) catch ladder collapse, (b) CORS rule centralized as testable constants/methods, (c) per-endpoint try/catch in Program.cs removed in favor of the global handler.
  • Test quality: Tests assert on specific status codes, message substrings, log capture (via mock ILogger), and content type. Not "no error thrown" tests.
  • Dead code: AZ-363 removed _totalEnqueued/_totalDequeued. RegionRequestQueue is now lean.

Phase 4 — Security

  • Sanitized 5xx: Detail = "An unexpected error occurred. Use the correlationId to look up the server log entry." — does not leak exception type, message, or stack trace to client. ✓
  • Correlation ID: httpContext.TraceIdentifier — connection-scoped string, not a sensitive value. Adequate for log correlation.
  • BadHttpRequestException Detail echoes framework message (e.g., "Failed to bind parameter "double Latitude" from "' OR 1=1 --"."). The echoed text is the user's own input, which they already possess; no server-side info is leaked. This is also standard ASP.NET behavior. Not a finding.
  • CORS: Hard-fail in Production for empty AllowedOrigins + missing opt-in. Closes the most common CORS misconfiguration in prod deployments.
  • 501 stubs: ProblemDetails contain only the literal "not implemented" message; no internal info.
  • No SQL injection / command injection / hardcoded secrets introduced.

Phase 5 — Performance

  • All new code is pure, allocation-light computation in non-hot paths (validator runs once at startup; classifier runs once per failure; handler runs once per unhandled exception).
  • No new N+1 queries, no blocking I/O in async contexts, no O(n²) algorithms.

Phase 6 — Cross-task consistency

  • AZ-353, AZ-354, AZ-356 all touch Program.cs; their interactions are coherent: validator runs first (may throw), then DI registers handler + ProblemDetails, then app.UseExceptionHandler() activates the pipeline. No conflicting wiring.
  • All new ProblemDetails responses use "application/problem+json" content type consistently.
  • Logging style consistent across changes: structured fields with {PascalCase} placeholders, _logger.LogError/LogWarning with explicit exception when relevant.
  • Test conventions consistent: // Arrange / // Act / // Assert per project rule; FluentAssertions throughout.

Phase 7 — Architecture

Check Result
Layer direction All cross-component imports go Layer-3 → Layer-1 (Common/DataAccess) or Layer-4 → Layer-3/1. No upward imports.
Public API respect New types under each component live in the component's root namespace and are exposed as appropriate (public sealed, public static). No internal-of-other-component imports.
New cyclic dependencies None. The split (per module-layout.md) prevents cross-sibling project references; the new files all sit within their owning component.
Duplicate symbols across components None. RegionFailureClassifier is unique to RegionProcessing; GlobalExceptionHandler and CorsConfigurationValidator are unique to Api.
Cross-cutting concerns mis-placed None. CORS validation belongs in Api (depends on env name); 5xx handler belongs in Api (depends on ASP.NET); region failure classification belongs in RegionProcessing (region-specific business semantics).

Baseline delta

architecture_compliance_baseline.md lists 5 findings, all Resolved as of epic AZ-309. This cumulative review introduces 0 new architecture findings.

Status Count
Carried over 0
Resolved 5 (already by AZ-309)
Newly introduced 0

Test results referenced

  • Unit: 68 / 68 passing (was 35 pre-Phase 1; +10 RegionFailureClassifier, +9 CorsConfigurationValidator, +3 GlobalExceptionHandler, +4 RouteProcessingService, +7 carried from prior baseline migrations across batches 7+8 — TileService internals + others).
  • Integration smoke: 5 / 5 passing.
  • Stub-contract integration: 3 / 3 passing.
  • Full integration suite: green; container exits 0.

Conclusion

Verdict: PASS. Phase 1 (Critical) closed cleanly. Phase 2 (Correctness) opened with AZ-359 also clean. Architecture baseline still at zero findings.

The implement skill may proceed to batch 10 without an auto-fix loop or user gate.