Files
satellite-provider/_docs/06_metrics/structure_2026-05-23_cycle8.md
T
Oleksandr Bezdieniezhnykh 62d6b8310a
ci/woodpecker/push/01-test Pipeline was successful
ci/woodpecker/push/02-build-push Pipeline was successful
[AZ-808] [AZ-809] [AZ-810] [AZ-811] [AZ-812] Cycle 8 retro + close
Cycle 8 retrospective (cycle-end mode): 5 tickets shipped, 17 SP, 4
batches across 1 cycle theme (strict input validation for the 4
AZ-795 child endpoints + AZ-812 region API field rename).

Artifacts:
- _docs/06_metrics/retro_2026-05-23_cycle8.md
- _docs/06_metrics/structure_2026-05-23_cycle8.md (gap-filled; last
  structural snapshot was cycle 5)

Key cycle-8 findings (now in _docs/LESSONS.md ring buffer):
- Step-14 security-audit Medium findings under the small-fix
  threshold should be resolved in-cycle, not deferred (F-AZ809-1
  closed in commit 8fca6e0, ~30 min from discovery to fix).
- Retro recommendations ship end-to-end when they name concrete
  tickets/files + size as a coherent cycle theme (cycle 7 Action 3
  -> cycle 8 strict-validation slate, first end-to-end traceable
  cross-cycle improvement action in project history).
- Contract wire-format updates (new required field / rename) need a
  ripgrep probe across all consumer paths (perf script, probe
  scripts, README, deploy docs, OpenAPI examples) — partial syncs
  surface at Step 15 perf gate (PT-06 missed AZ-809 requestMaps +
  createTilesZip, fixed in commit 32bc5c1).

Carry-overs to cycle 9: track PT-07 cache-pollution false positive
(harness, not regression), reduce 3 cycles in a row of misleading
"PT-07 fails on warm/cold ratio" entries in the perf report.

Marks Step 17 completed; cycle 8 closed. Next /autodev invocation
starts cycle 9 from Step 0.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-23 17:17:03 +03:00

13 KiB

Structural Snapshot — 2026-05-23 (post-cycle 8, strict-validation sweep)

Cycle 8 delta against structure_2026-05-12_cycle5.md (the most recent snapshot — cycles 6 and 7 did not write snapshots; process gap carried forward as a cycle-8 follow-up). Source of truth: _docs/02_document/module-layout.md + on-disk *.csproj graph + _docs/02_document/contracts/.

Projects

Layer csproj Cycle 6+7+8 delta vs cycle-5 snapshot
1 (Foundation) SatelliteProvider.Common +5 DTO files modified (cycle 8 only): DTO/RequestRegionRequest.cs (Lat/Lon rename + [JsonRequired]), DTO/CreateRouteRequest.cs + DTO/RoutePoint.cs + DTO/GeofencePolygon.cs + DTO/GeoPoint.cs ([JsonRequired]), DTO/UavTileMetadata.cs ([JsonRequired] + Items on the batch envelope). Plus cycle-6: AZ-505 inventory DTOs. Plus cycle-7: AZ-794 tileZoom/tileX/tileY → z/x/y rename.
1 (Foundation) SatelliteProvider.DataAccess +1 migration in cycle 6 (015_*.sql — AZ-505 leaflet covering index); 0 migrations in cycle 7 + cycle 8. Cycle 8 has zero schema touch — first 2-cycle stretch without schema change since cycle 3-4 (cycle 7 was the first migration-free cycle).
1 (Foundation, shared DTO) SatelliteProvider.Common (DTO sub-folder) No new DTO files this cycle; cycle 8 added [JsonRequired] annotations to 5 existing files.
3 (Application) SatelliteProvider.Services.{TileDownloader, RegionProcessing, RouteManagement} unchanged (zero service-layer changes in cycle 8 — the entire cycle landed in SatelliteProvider.Api/Validators/ + Common/DTO)
4 (API / Entry) SatelliteProvider.Api +9 validator files in cycle 8 (Validators/CreateRouteRequestValidator.cs, Validators/GeofencePolygonValidator.cs, Validators/GetTileByLatLonQueryValidator.cs, Validators/RegionRequestValidator.cs, Validators/RejectUnknownQueryParamsEndpointFilter.cs, Validators/RoutePointValidator.cs, Validators/UavTileBatchMetadataPayloadValidator.cs, Validators/UavTileMetadataValidator.cs, Validators/UavUploadValidationFilter.cs); +1 DTO file (DTOs/GetTileByLatLonQuery.cs, nullable record). Plus cycle-6 + cycle-7 adds: Validators/ValidationEndpointFilter.cs, Validators/ValidationEndpointFilterExtensions.cs, Validators/InventoryRequestValidator.cs, Validators/GlobalValidatorConfig.cs (cycle 7 foundations). Program.cs extended by every batch (.WithValidation<T>(), endpoint filters, .Accepts<> / .Produces<> / .ProducesProblem(400) chains, transient registrations).
5 (Test-Support) SatelliteProvider.TestSupport unchanged
6 (Tests) SatelliteProvider.Tests +8 test files in cycle 8 under Tests/Validators/ (RegionRequestValidatorTests + GetTileByLatLonQueryValidatorTests + RejectUnknownQueryParamsEndpointFilterTests + CreateRouteRequestValidatorTests + RoutePointValidatorTests + GeofencePolygonValidatorTests + UavTileBatchMetadataPayloadValidatorTests + UavTileMetadataValidatorTests); +63 unit-test methods total.
6 (Tests) SatelliteProvider.IntegrationTests +5 test files in cycle 8 (RegionFieldRenameTests + RegionRequestValidationTests + GetTileByLatLonValidationTests + CreateRouteValidationTests + UavUploadValidationTests); +52 integration-test methods total. Program.cs updated by every batch to wire the new entry points into both RunSmokeSuite and RunFullSuite. ProblemDetailsAssertions.cs extended with AssertErrorsContainsMention shared helper.

Project count: 9 (unchanged from cycle 5 — cycle 8 adds files to existing projects, doesn't add a new csproj).

Cross-Project Import Edges (compile-time ProjectReference)

Edge Count Cycle-6+7+8 delta
Api → {Common, DataAccess, TileDownloader, RegionProcessing, RouteManagement} 5 unchanged
TileDownloader → {Common, DataAccess} 2 unchanged
DataAccess → {Common} 1 unchanged
RegionProcessing → {Common, DataAccess} 2 unchanged
RouteManagement → {Common, DataAccess} 2 unchanged
Tests → {Api, TileDownloader, RegionProcessing, RouteManagement, Common, DataAccess, TestSupport} 7 unchanged
IntegrationTests → {TestSupport, Common} 2 unchanged (the cycle-5 +1 edge has held)

Total ProjectReference edges: 21 (cycle 5: 21). Net delta across cycles 6 + 7 + 8: 0 — three consecutive cycles with zero new compile-time edges. This is the longest stretch of edge stability in the project's history.

Source-import sites — cycle 8 delta

Importer Imports from Cycle 8 delta
SatelliteProvider.Api/Validators/{Create,Get,Region,Route,Uav}*Validator.cs (9 new files) FluentValidation (12.0.0, cycle-7 dep) + SatelliteProvider.Common.DTO NEW (every cycle-8 validator imports from Common.DTO; no new third-party imports).
SatelliteProvider.Api/Validators/RejectUnknownQueryParamsEndpointFilter.cs (NEW) Microsoft.AspNetCore.Http (framework) NEW (reusable query-param allow-listing filter).
SatelliteProvider.Api/Validators/UavUploadValidationFilter.cs (NEW) FluentValidation + Microsoft.AspNetCore.Http + System.Text.Json + SatelliteProvider.Common.DTO NEW (bespoke IEndpointFilter for the multipart endpoint).
SatelliteProvider.Tests/Validators/* (8 new files) FluentValidation.TestHelper + SatelliteProvider.Common.DTO + Xunit NEW (each test file scoped to one validator).
SatelliteProvider.IntegrationTests/*ValidationTests.cs (5 new files) existing IntegrationTests infrastructure (ProblemDetailsAssertions, TestRunMode, JwtTokenFactory) + SatelliteProvider.Common.DTO NEW (each file scoped to one endpoint's validation surface).
All other source files unchanged

~25 new source-level import lines across the new files; all internal or framework. Zero new third-party imports. FluentValidation 12.0.0 was added by cycle 7 (it's the foundation that AZ-795 epic builds on); cycle 8 expands its consumer set within the Api project but doesn't introduce a new dependency line.

Graph properties

  • Cycles in project import graph: 0 (clean DAG — unchanged for 5 consecutive cycles).
  • Average ProjectReferences per component: 21 / 9 = ~2.3 (unchanged).
  • Max in-degree: Common (still highest — 7 incoming edges: Api, TileDownloader, DataAccess, RegionProcessing, RouteManagement, Tests, IntegrationTests). Unchanged.
  • Max out-degree: Tests (7 — unchanged).
  • TestSupport position: leaf-of-test-subgraph; no production-layer importers (unchanged).

NuGet dependency hygiene (cycle 8)

Package Cycle-7 version Cycle-8 version Status
FluentValidation 12.0.0 (cycle 7 add) unchanged The cycle-7 retro Action 1 recommended a 12.0.0 → 12.1.1 bump (D-AZ795-1). Cycle 8 did NOT take the bump — the security audit re-confirmed Low / Hardening severity, and the cycle-8 scope (per-endpoint child tasks) explicitly excluded NuGet hygiene per coderule.mdc scope discipline. Still OPEN, carried forward.
All other NuGet packages across all 9 csproj files unchanged unchanged Zero NuGet bumps this cycle. Three consecutive zero-bump cycles (cycle 6 closed AZ-505's only NuGet bump; cycle 7 added FluentValidation 12.0.0 + extensions; cycle 8 used FluentValidation entirely against cycle-7's foundation).
Carry-overs (still OPEN) Cycle-3 D2-cy4 (Microsoft.NET.Test.Sdk 17.8.0 transitive NuGet.Frameworks flag — Medium); cycle-4 D4 (Microsoft.IdentityModel.Tokens / System.IdentityModel.Tokens.Jwt 7.0.3 NU1902 — Low); Serilog.AspNetCore 8.0.3 fallback (Low) unchanged All three remain explicitly out of cycle-8 scope (scope discipline). Re-listed in _docs/05_security/dependency_scan_cycle8.md carry-over table.

Database schema surface (cycle 8 delta)

Object Change Source
(no schema changes this cycle)

Zero schema changes in cycle 8 — second consecutive migration-free cycle (cycle 7 was the first). Cycle 8's strict-validation work lives entirely above the persistence layer (deserializer + FluentValidation + endpoint filters); no field validation requires a column change because all rules are application-level enforced (the database still accepts any well-formed value the validator lets through).

Architecture / contract surface (cycle 8 delta)

  • 3 NEW contracts published:
    • _docs/02_document/contracts/api/region-request.md v1.0.0 (AZ-808 — published with post-AZ-812 lat/lon wire format directly per the coordination clause).
    • _docs/02_document/contracts/api/route-creation.md v1.0.0 → v1.0.1 (AZ-809 v1.0.0 + an in-cycle PATCH bump for the F-AZ809-1 50-polygon cap added during the Step-14 security-audit follow-up).
    • _docs/02_document/contracts/api/tile-latlon.md v1.0.0 (AZ-811).
  • 1 contract MINOR bump: uav-tile-upload.md v1.1.0 → v1.2.0 (AZ-810 — additive: new "Metadata validation" section).
  • No contract MAJOR bumps this cycle (cycle 7 shipped the only MAJOR bump in project history — tile-inventory.md 1.0.0 → 2.0.0; cycle 8 produced only new contracts + minor + patch).
  • Public-API contract coverage: now 5 contracts across 5 documented endpoints (region-request, route-creation, tile-latlon, tile-inventory, uav-tile-upload) + the shared error-shape.md. Endpoints without a dedicated contract: 2 read-only GET /api/satellite/{region,route}/{id} (path-Guid only — no strict-validation surface, per cycle-8 implementation report).
  • Contract-per-endpoint ratio: 5 / 7 = 71% (cycle 7: 2 / 7 = 29%, cycle 6: 1 / 7 = 14%). Cycle 8 more than doubled the documented-endpoint coverage in a single cycle.
  • Architecture findings carry-over from cycle 7: 0 new architecture-layer findings; 0 architecture-layer carry-overs resolved (cycle 7's open recommendations on implement-skill ↔ downstream-skill artifact contract were partially addressed — cycle 8 produced both the per-batch reports AND the consolidated implementation_report_strict_validation_cycle8.md per cycle-7 Action 1 recommendation; see retro_2026-05-23_cycle8.md § Pattern 1).

Net Architecture delta vs cycle 7

  • Resolved (closed by this cycle): 1 — cycle-7 Pattern 1 (missing implementation report) is closed by implementation_report_strict_validation_cycle8.md + implementation_completeness_cycle8_report.md + cumulative_review_batches_01-04_cycle8_report.md (three artifact types where cycle 7 had none).
  • Newly introduced:
    • 1 Medium resolved in-cycle: F-AZ809-1 (unbounded geofences.polygons DoS) — found in Step 14 security audit, fixed in commit 8fca6e0 with a MaxPolygons = 50 cap + unit + integration test + contract v1.0.1 + traceability row AZ-809 AC-1b before Step 14 closure. Net contribution: 0 (resolved before retrospective).
    • 2 Low (F-AZ810-1 JsonException.Message echo in UavUploadValidationFilter; F-AZ810-2 DateTime vs DateTimeOffset for CapturedAt — UTC-deployment-only impact). Open; carry to cycle 9.
    • 0 new Medium, 0 new High, 0 new Critical (after F-AZ809-1 resolution).
  • 0 cross-project edges added, 0 import-graph cycles introduced, 0 NuGet additions, 0 migrations.
  • Net Architecture delta: -1 (Pattern 1 closed; only Low informational findings introduced, both carried forward). First negative net architecture delta since cycle 4.

What this snapshot says about cycle 8's shape

Cycle 8 is the project's largest single-cycle code volume to date (5 tasks shipped in 4 batches; 17 SP delivered vs cycle 7's 8 SP; ~115 new test methods; 9 new validator files; 3 new contracts + 1 MINOR + 1 PATCH bump). It is also the lowest structural-impact cycle of that size: zero new csproj, zero new NuGet, zero new cross-project edges, zero schema changes, zero new architecture violations. The entire cycle stays inside the SatelliteProvider.Api/Validators/ namespace + Common/DTO annotations + Tests/Validators/ test directory + 4 probe scripts + 4 new docs — a clean layered addition on top of the cycle-7 foundation (UnmappedMemberHandling.Disallow, GlobalExceptionHandler, error-shape.md v1.0.0, FluentValidation 12.0.0).

Cycle 8 also closes Pattern 1 from cycle 7: the implement skill produced both per-batch reports AND a consolidated implementation report AND a completeness report AND a cumulative cross-batch review — four artifact types where cycle 7 had two (per-batch reports + per-batch reviews only). This is the directly visible execution of cycle 7's Action 1 ("formalise the implement-skill ↔ downstream-skill artifact contract") — done implicitly by the implement skill itself this cycle, rather than via the rule-file change cycle 7 recommended.

The DAG remains acyclic with the same 9 projects; max-in-degree is still Common at 7; the project's architectural shape has held stable across cycles 6 + 7 + 8 despite the steady delivery cadence.