[AZ-350] Close 03-code-quality-refactoring: Phase 6+7 + FINAL_report
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful

Phase 6 (Verification): smoke run green (format gate + 200/200
unit + integration smoke). verification_report.md captures
metric deltas vs Phase 0 baseline; all 5 ACs met, all 4
constraints honored, 0 regressions.

Phase 7 (Documentation):
- module-layout.md: corrected DataAccess->Common dependency
  (was mistakenly documented as "Imports from: (none)" by
  prior AZ-315 baseline; csproj reference + 7 import sites
  have actually been there since AZ-309).
- architecture_compliance_baseline.md: F5 entry revised to
  reflect the actual layering invariant (one-way: Common
  MUST NOT import from DataAccess, but DataAccess MAY
  import from Common).
- 00_discovery.md: added "Updates Since Baseline" section
  enumerating the AZ-309 split + AZ-350 27-change run +
  AZ-372 tooling additions; original tree kept as a
  2026-05-10 snapshot.

FINAL_report: complete run summary (10 batches, 27 tasks,
3 K=3 cumulative reviews, baseline->final metric table,
remaining items, lessons learned).

Autodev state: advance Step 8 -> Step 9 (New Task);
sub_step reset to phase 0 awaiting-invocation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 05:23:35 +03:00
parent 9a53bff92e
commit 08451df027
6 changed files with 255 additions and 15 deletions
+37
View File
@@ -206,3 +206,40 @@ No dependency cycles detected. The dependency graph is a clean DAG.
- **Woodpecker CI** pipelines in `.woodpecker/`:
- `01-test.yml`: runs `dotnet restore` + `dotnet test` on push/PR to dev/stage/main (ARM64)
- `02-build-push.yml`: builds Docker image and pushes to private registry (depends on 01-test, ARM64 matrix with AMD64 slot commented out)
## Updates Since Baseline
Treat the directory tree, dependency listing, and test-structure section above as a 2026-05-10 snapshot. Refer to `module-layout.md` for the current authoritative layout. Material changes since baseline:
**2026-05-10 — AZ-309 (02-coupling-refactoring)**
- `SatelliteProvider.Services/` was split into three csprojs: `SatelliteProvider.Services.TileDownloader`, `SatelliteProvider.Services.RegionProcessing`, `SatelliteProvider.Services.RouteManagement`. Cross-sibling calls now flow only through interfaces in `SatelliteProvider.Common.Interfaces`.
- `RateLimitException` moved from Services into `SatelliteProvider.Common.Exceptions`.
- Per-component DI extension methods (`AddTileDownloader`, `AddRegionProcessing`, `AddRouteManagement`) now own their registrations; `Program.cs` calls them.
**2026-05-11 — AZ-350 (03-code-quality-refactoring), 27 changes C01..C27**
- Format / static-analysis tooling added (AZ-372 / C19):
- `.editorconfig` at repo root: `indent_style=space`, `indent_size=4`, `end_of_line=lf`, `charset=utf-8` (no BOM), `trim_trailing_whitespace=true`, `insert_final_newline=true`, file-scoped namespaces.
- `Directory.Build.props` enables `Microsoft.CodeAnalysis.NetAnalyzers` repository-wide; CA1001, CA1051, CA1816, CA2227 elevated to warning.
- Coverlet (`coverlet.collector`) wired into `SatelliteProvider.Tests`; `dotnet test --collect:"XPlat Code Coverage"` writes `cobertura.xml` to `TestResults/`.
- `scripts/run-tests.sh` runs `dotnet format whitespace --verify-no-changes` as Step 0 (gating); `--unit-only`, `--smoke`, `--full` modes documented.
- HTTP / DI hardening:
- `IExceptionHandler`-based `GlobalExceptionHandler` sanitizes 5xx ProblemDetails (AZ-353 / C03).
- Permissive CORS replaced with strict-by-default policy (AZ-354 / C04); permissive policy is opt-in per `CorsConfig.AllowAnyOrigin` and warns in production.
- Stub endpoints `/api/satellite/tiles/mgrs` and `/api/satellite/upload` now return HTTP 501 instead of 500 (AZ-356 / C05).
- Idempotent POST contract for `/api/satellite/request` and `/api/satellite/route` returns the existing resource on duplicate id without re-enqueueing (AZ-362 / C09).
- Typed HttpClient `GoogleMapsTiles` registered in DI (AZ-374 / C21).
- Domain model cleanup:
- `RegionStatus` and `RoutePointType` enums replace string status fields end-to-end with case-insensitive parse + lowercase write (AZ-370 / C17).
- Tile `Version` and `MapsVersion` deprecated (AZ-357 / C06, AZ-373 / C20); migration 012 dedupes existing rows and reshapes the unique index to `(latitude, longitude, tile_zoom, tile_size_meters)`.
- Algorithmic / structural cleanup:
- `RouteProcessingService` god-class decomposed (AZ-364 / C11); `RouteService.CreateRouteAsync` decomposed (AZ-365 / C12); `IServiceProvider` lookups replaced with explicit dependencies (AZ-360 / C08); `RegionService` catch ladder consolidated (AZ-359 / C07).
- Shared helpers extracted: `TileCsvWriter` (AZ-368 / C15), `TileGridStitcher` (AZ-367 / C14), Haversine + filename parser (AZ-366 / C13).
- Inline DTOs moved out of `Program.cs` into `Common.DTO` (AZ-369 / C16).
- Repository `ColumnList` constants extracted (AZ-379 / C26); per-cell `FirstOrDefault` tile lookup replaced with `HashSet` membership (AZ-375 / C22); Earth + tile-pixel constants consolidated to `GeoUtils` and `MapConfig.DefaultTileSizePixels` (AZ-377 / C24).
- Dead code removed: `FindExistingTileAsync` (AZ-376 / C23), `CalculatePolygonDiagonalDistance` (AZ-380 / C27), unused write-only counters in `RegionRequestQueue` (AZ-363 / C10).
- Empty catch in `ExtractTileCoordinatesFromFilename` replaced with logging + sentinel return (AZ-352 / C02); null logger in `DatabaseMigrator` fixed (AZ-351 / C01).
- Magic numbers promoted to `ProcessingConfig` / `MapConfig` (AZ-371 / C18).
- Unused repo logger fields removed from `RegionRepository` and `RouteRepository`; `TileRepository` keeps its logger and emits slow-query warnings ≥ 500ms (AZ-378 / C25).
- Test growth: 37 unit tests → 200 unit tests (per AZ-37x batch test sweeps); smoke run extended with AZ-353/AZ-356/AZ-357/AZ-362/SEC-01..04/CORS scenarios.
For the authoritative current layout see `_docs/02_document/module-layout.md`. For the per-batch detail see `_docs/03_implementation/batch_*_report.md` and `_docs/03_implementation/reviews/`.
@@ -43,12 +43,12 @@
- Suggestion: Accept as-is for current scale; consider splitting into separate projects if the codebase grows significantly.
- **Resolution (AZ-312 + AZ-313 + AZ-314, commit `8b0ddae`)**: Project split into `SatelliteProvider.Services.TileDownloader`, `SatelliteProvider.Services.RegionProcessing`, `SatelliteProvider.Services.RouteManagement`. None of the three references another sibling — cross-sibling calls now flow exclusively through interfaces in `SatelliteProvider.Common.Interfaces`. `RateLimitException` relocated to `SatelliteProvider.Common.Exceptions` to keep the sibling boundary clean. Per-component DI extension methods (`AddTileDownloader`, `AddRegionProcessing`, `AddRouteManagement`) registered from `Program.cs`. Verified by 0 build errors, 40/40 unit tests, and full smoke integration suite passing post-split.
**F5: module-layout.md incorrect — DataAccess has no Common dependency** (Low / Architecture) — **RESOLVED**
**F5: module-layout.md vs DataAccessCommon dependency** (Low / Architecture) — **REVISED 2026-05-11**
- Location: `_docs/02_document/module-layout.md`
- Description: DataAccess was documented as "Imports from: Common" but `SatelliteProvider.DataAccess.csproj` has no ProjectReference to Common and no `using SatelliteProvider.Common` in any file.
- Impact: Documentation inaccuracy; no code impact.
- Suggestion: Correct module-layout.md.
- **Resolution (AZ-315)**: `module-layout.md` now lists DataAccess Imports from: (none); the §Verification section calls out the no-Common-dependency invariant explicitly.
- Original baseline claim: DataAccess was documented as "Imports from: Common" but the inspector concluded DataAccess had no ProjectReference to Common nor any `using SatelliteProvider.Common`.
- **Re-verified 2026-05-11** during 03-code-quality-refactoring (AZ-377): the original baseline scan was inaccurate. `SatelliteProvider.DataAccess.csproj` line 18 has a `<ProjectReference Include="..\SatelliteProvider.Common\SatelliteProvider.Common.csproj" />` that has been present since at least the AZ-309 split, and 5 DataAccess files import `SatelliteProvider.Common.Enums` (`RegionRepository.cs`, `IRegionRepository.cs`, `Models/RegionEntity.cs`, `Models/RoutePointEntity.cs`, `TypeHandlers/EnumStringTypeHandler.cs`).
- Impact: Documentation inaccuracy. Caused the AZ-315 doc-sync to "resolve" the finding by claiming DataAccess has no Common dep — that resolution itself was incorrect.
- **Resolution (AZ-377 + Phase 7 of 03-code-quality-refactoring run, commit 9a53bff)**: `module-layout.md` now correctly lists DataAccess `ProjectReferences: SatelliteProvider.Common` and enumerates the 7 import sites (5 enum + 1 `MapConfig.DefaultTileSizePixels` + 1 `GeoUtils.*`). The §Verification section now states the actual constraint: Common MUST NOT import from DataAccess (one-way leaf invariant). AZ-377 also widened the dependency surface from `Common.Enums` only to also include `Common.Configs` and `Common.Utils` — see batch 24 cumulative review F1.
## Summary
+6 -5
View File
@@ -5,7 +5,7 @@
**Language**: csharp
**Layout Convention**: custom (per-component .csproj per logical component)
**Root**: ./
**Last Updated**: 2026-05-10 (post AZ-309 coupling refactor)
**Last Updated**: 2026-05-11 (post AZ-350 03-code-quality-refactoring run; corrects DataAccess→Common dependency)
## Layout Rules
@@ -52,7 +52,8 @@
- `SatelliteProvider.DataAccess/DatabaseMigrator.cs`
- **Internal**: (none — all repository types are public for DI registration)
- **Owns**: `SatelliteProvider.DataAccess/**`
- **Imports from**: (none — fully self-contained, no project references)
- **ProjectReferences**: `SatelliteProvider.Common`
- **Imports from**: `SatelliteProvider.Common.Enums` (5 sites: `RegionRepository`, `IRegionRepository`, `Models/RegionEntity`, `Models/RoutePointEntity`, `TypeHandlers/EnumStringTypeHandler`); `SatelliteProvider.Common.Configs` (`MapConfig.DefaultTileSizePixels` in `TileRepository`); `SatelliteProvider.Common.Utils` (`GeoUtils.EarthEquatorialCircumferenceMeters`, `GeoUtils.MetersPerDegreeLatitude` in `TileRepository`).
- **Consumed by**: TileDownloader, RegionProcessing, RouteManagement, WebApi
### Component: TileDownloader
@@ -140,7 +141,7 @@
|-------|------------|--------------------------------------------------|
| 4. API / Entry | WebApi | Common, DataAccess, TileDownloader, RegionProcessing, RouteManagement |
| 3. Application | TileDownloader, RegionProcessing, RouteManagement | Common, DataAccess only — siblings communicate through interfaces in Common, never through direct ProjectReferences |
| 1. Foundation | Common, DataAccess | Common: (none); DataAccess: (none) |
| 1. Foundation | Common (leaf-most), DataAccess | Common: (none); DataAccess: Common only — Common MUST NOT import from DataAccess |
**Key constraint enforced by the AZ-309 split**: the three Layer-3 components are compile-time siblings. Any cross-sibling call (e.g. `RegionProcessing` invoking tile download) MUST go through an interface defined in `SatelliteProvider.Common.Interfaces` and resolved via DI — adding a `ProjectReference` between siblings is now structurally impossible without re-introducing the coupling the refactor removed.
@@ -148,5 +149,5 @@
- **No detected cycles**: The dependency graph is a clean DAG.
- **No cross-sibling ProjectReferences**: TileDownloader, RegionProcessing, and RouteManagement each reference only Common + DataAccess. Verified by inspecting all three csproj files.
- **DataAccess layer placement**: DataAccess sits at Layer 1 (Foundation) alongside Common because it is consumed uniformly by all service components. An alternative layering could place it at Layer 2, but the current code treats repositories as infrastructure, not domain logic.
- **DataAccess has no ProjectReference to Common**: confirmed by inspecting `SatelliteProvider.DataAccess.csproj`. DataAccess models and repositories are self-contained (do not use any types from Common). This contradicts an earlier baseline assumption (compliance baseline F5).
- **DataAccess layer placement**: DataAccess sits at Layer 1 (Foundation) alongside Common because it is consumed uniformly by all service components. It is one half-step above Common because it depends on Common for shared enums and a small number of constants/configs.
- **DataAccess→Common ProjectReference**: confirmed present in `SatelliteProvider.DataAccess.csproj` line 18 and used by 7 source sites (5 enum imports, 1 `MapConfig.DefaultTileSizePixels` site, 1 `GeoUtils.*` site). The earlier compliance baseline F5 entry that claimed "DataAccess has no Common dependency" was inaccurate — both `module-layout.md` and `architecture_compliance_baseline.md` were corrected during the 03-code-quality-refactoring run (2026-05-11). The actual constraint that holds is one-way: `Common` MUST NOT import from `DataAccess`.