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 commit8fca6e0, ~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 commit32bc5c1). 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>
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.mdv1.0.0 (AZ-808 — published with post-AZ-812lat/lonwire format directly per the coordination clause)._docs/02_document/contracts/api/route-creation.mdv1.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.mdv1.0.0 (AZ-811).
- 1 contract MINOR bump:
uav-tile-upload.mdv1.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.md1.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 sharederror-shape.md. Endpoints without a dedicated contract: 2 read-onlyGET /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.mdper cycle-7 Action 1 recommendation; seeretro_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.polygonsDoS) — found in Step 14 security audit, fixed in commit8fca6e0with aMaxPolygons = 50cap + 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.Messageecho inUavUploadValidationFilter; F-AZ810-2DateTimevsDateTimeOffsetforCapturedAt— UTC-deployment-only impact). Open; carry to cycle 9. - 0 new Medium, 0 new High, 0 new Critical (after F-AZ809-1 resolution).
- 1 Medium resolved in-cycle: F-AZ809-1 (unbounded
- 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.