AZ-794: rename inventory wire fields tileZoom/tileX/tileY -> z/x/y to match the slippy-map URL convention. Contract bumped to v2.0.0. AZ-795: shared validation infrastructure -- FluentValidation + ValidationEndpointFilter + GlobalValidatorConfig (camelCase paths). GlobalExceptionHandler now converts JsonException (UnmappedMember + JsonRequired) into RFC 7807 ValidationProblemDetails. JSON layer hardened with UnmappedMemberHandling.Disallow + camelCase naming policy. New error-shape.md contract. AZ-796: InventoryRequestValidator covers 9 rules (XOR tiles vs locationHashes, cap 1000, z 0..22, x/y in slippy bounds, hash length/charset). 16 unit tests + 16 integration tests + a manual curl probe script. Adjacent fixes uncovered by the new strict layer: - IdempotentPostTests RoutePoint payload corrected to lat/lon (the DTO has used JsonPropertyName for ages; previously silently ignored under PascalCase fallback). - TileInventoryTests slippy x/y reduced to fit z=18 bounds. - docker-compose.yml host port for Postgres moved 5432 -> 5433 to avoid sibling-project conflict; appsettings.Development + README + AGENTS + architecture + containerization docs aligned. New coderule (suite + repo): API consumer-facing OpenAPI descriptions must not contain task IDs, contract filenames, or version-bump history -- internal change tracking belongs in commits/contract docs/changelogs. Existing offending descriptions in Program.cs cleaned up. Co-authored-by: Cursor <cursoragent@cursor.com>
16 KiB
Task Dependencies
Dependency Graph
Step 6 — Implement Tests (AZ-285..AZ-290)
| Task | Depends On | Points | Status |
|---|---|---|---|
| AZ-285 Test Infrastructure | — | 3 | Done |
| AZ-286 TileService Tests | AZ-285 | 3 | Done |
| AZ-287 RegionService Tests | AZ-285 | 3 | Done |
| AZ-288 RouteService Tests | AZ-285 | 3 | Done |
| AZ-289 Integration Route Maps | AZ-285 | 2 | Done |
| AZ-290 Non-Functional Tests | AZ-285 | 3 | Done |
Step 8 — Refactor 02-coupling-refactoring (AZ-309 epic)
| Task | Depends On | Points | Status |
|---|---|---|---|
| AZ-310 ServeTile via ITileService | — | 3 | Done (In Testing) |
| AZ-311 GetTileByLatLon via ITileService | AZ-310 | 2 | Done (In Testing) |
| AZ-312 Split Services into 3 csprojs | AZ-311 | 5 | Done (In Testing) |
| AZ-313 Update consumers (Api/Tests) | AZ-312 | 3 | Done (In Testing) |
| AZ-314 DI registration split | AZ-313 | 2 | Done (In Testing) |
| AZ-315 Documentation sync | AZ-314 | 2 | In Progress |
Step 8 — Refactor 03-code-quality-refactoring (AZ-350 epic)
Roadmap: _docs/04_refactoring/03-code-quality-refactoring/analysis/refactoring_roadmap.md (4 execution phases).
| Task | C-ID | Title | Phase | Depends On | Points | Status |
|---|---|---|---|---|---|---|
| AZ-351 | C01 | Fix null logger to DatabaseMigrator | 1 | — | 2 | Done (In Testing) |
| AZ-352 | C02 | Replace empty catch in ExtractTileCoordinatesFromFilename | 1 | — | 2 | Done (In Testing) |
| AZ-363 | C10 | Delete write-only counters in RegionRequestQueue | 1 | — | 1 | Done (In Testing) |
| AZ-356 | C05 | Stub endpoints return 501 | 1 | — | 2 | Done (In Testing) |
| AZ-354 | C04 | Strict CORS by default | 1 | — | 2 | Done (In Testing) |
| AZ-353 | C03 | Sanitize 5xx responses via IExceptionHandler | 1 | — | 3 | Done (In Testing) |
| AZ-359 | C07 | Consolidate RegionService catch ladder | 2 | — | 3 | Done (In Testing) |
| AZ-357 | C06 | Drop tile Version concept; new migration | 2 | — | 5 | Done (In Testing) |
| AZ-362 | C09 | Idempotent POST contract | 2 | AZ-353 | 3 | Done (In Testing) |
| AZ-366 | C13 | Consolidate Haversine + filename parser | 3 | — | 2 | Done (In Testing) |
| AZ-377 | C24 | Consolidate Earth constants + 111000 | 3 | AZ-371 | 2 | Done (In Testing) |
| AZ-368 | C15 | Shared TileCsvWriter | 3 | — | 2 | Done (In Testing) |
| AZ-367 | C14 | Shared TileGridStitcher | 3 | AZ-364 | 3 | Done (In Testing) |
| AZ-369 | C16 | Move inline DTOs out of Program.cs | 3 | — | 2 | Done (In Testing) |
| AZ-365 | C12 | Decompose RouteService.CreateRouteAsync | 3 | — | 5 | Done (In Testing) |
| AZ-364 | C11 | Decompose RouteProcessingService god-class | 3 | AZ-366, AZ-367 (folds in AZ-360) | 5 | Done (In Testing) |
| AZ-360 | C08 | Replace IServiceProvider in RouteProcessingService | 3 | AZ-364 (folded) | 2 | Done (In Testing) |
| AZ-371 | C18 | Magic numbers → ProcessingConfig/MapConfig | 4 | — | 3 | Done (In Testing) |
| AZ-370 | C17 | Status / point-type enums + AC RT2 update | 4 | — | 3 | Done (In Testing) |
| AZ-373 | C20 | Clarify / drop MapsVersion | 4 | AZ-357 | 2 | Done (In Testing) |
| AZ-374 | C21 | Typed HttpClient for Google Maps | 4 | — | 2 | Done (In Testing) |
| AZ-375 | C22 | O(N) existing-tile lookup (HashSet) | 4 | AZ-371 | 2 | Done (In Testing) |
| AZ-376 | C23 | Delete unused FindExistingTileAsync | 4 | — | 1 | Done (In Testing) |
| AZ-378 | C25 | Repo _logger fields: delete or use |
4 | — | 1 | Done (In Testing) |
| AZ-379 | C26 | Extract repo SELECT column-list constants | 4 | — | 2 | Done (In Testing) |
| AZ-380 | C27 | Delete CalculatePolygonDiagonalDistance | 4 | — | 1 | Done (In Testing) |
| AZ-372 | C19 | dotnet format + NetAnalyzers + Coverlet | 4 | — | 3 | Done (In Testing) |
Step 9 cycle 1 — New Task: Multi-source tile storage + UAV upload (AZ-483 epic)
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-484 | Multi-source tile storage schema (source + captured_at) | — | 5 | Done (deployed cycle 1) |
Step 9 cycle 2 — New Task: JWT validation baseline + UAV upload completion
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-487 | JWT validation baseline (HS256, JWT_SECRET, all endpoints) | — (consumes suite-level contract suite/_docs/10_auth.md) |
2 | Done (In Testing) |
| AZ-488 | UAV tile upload endpoint with batch + 5-rule quality gate | AZ-487 (hard prereq), AZ-484 contract tile-storage.md v1.0.0 |
8 (over-cap, user-accepted) | Done (In Testing) |
Step 9 cycle 3 — New Task: Cycle-2 follow-ups (test infra + security hardening + process)
Source: cycle-2 retrospective top-3 improvement actions + carried-forward security and process items (_docs/06_metrics/retro_2026-05-11_cycle2.md).
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-491 | Consolidate JWT test-mint helpers | — (logically follows AZ-487 which introduced both copies) | 3 | To Do |
| AZ-492 | Perf harness: PT-07 + PT-08 + JWT-attach in run-performance-tests.sh | AZ-487 (hard — Bearer token); AZ-491 (soft — token-mint reuse) | 3 | In Testing |
| AZ-493 | Integration test DB-reset hook | — | 2 | To Do |
| AZ-494 | JWT iss/aud validation (enable + configure) | AZ-487 (extends AddSatelliteJwt); external: admin team confirms iss/aud values |
2 | In Testing (Option B: plumbing implemented; prod iss/aud values gated by fail-fast startup) |
| AZ-495 | Resolve doc-folder convention for WebApi component | — | 1 | To Do |
| AZ-496 | Bump Microsoft.AspNetCore.OpenApi + JwtBearer to 8.0.25 | — | 2 | To Do |
Step 9 cycle 4 — New Task: SDK migration
Source: cycle-3 perf-harness leftover replay surfaced the host SDK / project SDK mismatch; user directive at start of cycle 4 to migrate to .NET 10. Closes the cycle-3 leftover as a side effect (AC-5).
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-500 | .NET 8 → .NET 10 migration (TFM + SDK pin + Docker images + CI images + Microsoft.AspNetCore.* + Microsoft.Extensions.* + Serilog.AspNetCore) | — | 5 | Done (In Testing) |
Step 9 cycle 5 — New Task: Tile identity foundation + perf-harness fix (AZ-483 epic)
Source: cross-workspace handoff from gps-denied-onboard (tile-schema scenario analysis) for AZ-503; cycle-3 perf-harness leftover replay-obligation closure for AZ-504. Both attach to epic AZ-483 (Multi-source tile storage + UAV upload, Layer 2) — AZ-503 supersedes the AZ-484 UPSERT-conflict-key portion, AZ-504 unblocks PT-08 measurement.
Cycle 5 split (during /autodev Step 10 batch 2): AZ-503 was specced as 3 SP but reconciled at ~5 SP once the codebase was inspected (flight_id / voting_status columns + UavTileMetadata.FlightId field didn't exist). User picked Option C: split AZ-503 into AZ-503-foundation (this cycle) + AZ-505 (next cycle). AZ-505 is Blocks-linked to AZ-503 and waits for the columns to land.
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-503 | Tile identity → UUIDv5 + integer UPSERT (foundation half — split from original AZ-503) | AZ-484 (supersedes UPSERT-conflict-key portion of AZ-484 selection rule) | 3 | Done (In Testing, batch 2 cycle 5) |
| AZ-504 | Perf script: fix grep | wc -l pipefail crash in PT-08 | — (independent; references AZ-488 PT-08 threshold) | 1 | Done (In Testing, batch 1 cycle 5) |
| AZ-505 | Tile inventory endpoint + HTTP/2 + leaflet covering index | AZ-503 (HARD, Blocks-linked — needs location_hash + flight_id columns) |
3 | To Do (consumed by cycle 6 — see below) |
Step 9 cycle 6 — New Task: Tile inventory endpoint + HTTP/2 + Leaflet covering index (AZ-483 epic)
Source: cycle-5 retro Action 2 — AZ-505 is the deferred half of AZ-503 (inventory endpoint + HTTP/2 + Leaflet covering index). AZ-503-foundation (cycle 5) shipped the prerequisite columns (location_hash, flight_id, content_sha256, legacy_id); AZ-505 ships the user-facing payload that consumes them.
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-505 | Tile inventory endpoint + HTTP/2 + leaflet covering index | AZ-503 (HARD, Blocks-linked, satisfied by cycle 5) | 3 | To Do (cycle 6) |
Step 9 cycle 7 — New Task: API quality follow-up (cross-repo from gps-denied-onboard AZ-777)
Source: cycle-7 New Task adoption of three Jira tickets originally filed on 2026-05-22 by the gps-denied-onboard agent during AZ-777 Phase 1 Jetson probing of the parent-suite satellite-provider service. Two API-quality concerns about the inventory endpoint were surfaced:
- Field-name inconsistency — URL path uses OSM-standard
z/x/y; JSON body uses verbosetileZoom/tileX/tileYfor the same concept (AZ-794). - Permissive parsing — missing required fields silently coerce to
0; unknown fields silently drop. Real client typos masquerade as valid (0,0,0) requests with collision-pronelocationHash(AZ-795 epic + AZ-796 first child).
Adopted into satellite-provider cycle 7 with the recommended ordering: shared validation infra (AZ-795) → wire-format rename (AZ-794) → first per-endpoint validator child (AZ-796). AZ-795 is structured as an Epic that ALSO ships shared infrastructure (FluentValidation + global ProblemDetails filter + JsonSerializerOptions.UnmappedMemberHandling.Disallow); future per-endpoint child tasks under AZ-795 to be added by parent-suite team as the public-endpoint surface is enumerated.
| Task | Title | Depends On | Points | Status |
|---|---|---|---|---|
| AZ-794 | Inventory body fields: rename tileZoom/tileX/tileY → z/x/y (OSM convention) |
— (coordinate release with AZ-795 / AZ-796) | 3 | Done (cycle 7) |
| AZ-795 | Strict input validation across all public endpoints (FluentValidation + ProblemDetails) — Epic with shared-infra ship | — (children gated on shared infra landing first) | — (epic; shared-infra estimate 5–8 pts; per-endpoint children ~3 pts each) | Done — shared infra shipped (cycle 7); future per-endpoint child tasks open |
| AZ-796 | Strict validation for inventory endpoint (POST /api/satellite/tiles/inventory) | AZ-795 (HARD — shared infra); coordinate with AZ-794 | 3 | Done (cycle 7) |
Execution Order
Step 6
- AZ-285 (test infrastructure — all others depend on this)
- AZ-286, AZ-287, AZ-288 (unit tests — can run in parallel)
- AZ-289 (integration tests — depends on infra only)
- AZ-290 (non-functional tests — depends on infra only)
Step 8 (02-coupling-refactoring)
- AZ-310 → AZ-311 (Phase A: route tile endpoints through ITileService)
- AZ-312 → AZ-313 → AZ-314 (Phase B: physical split + consumer + DI rewire)
- AZ-315 (Phase C: docs sync, must be last)
Step 8 (03-code-quality-refactoring)
Phase 1 (Critical fixes): AZ-351 → AZ-352 → AZ-363 → AZ-356 → AZ-354 → AZ-353 Phase 2 (Correctness): AZ-359 → AZ-357 → AZ-362 (AZ-362 needs AZ-353) Phase 3 (Structural cleanup): AZ-366 → AZ-377 → AZ-368 → AZ-367 → AZ-369 → AZ-365 → AZ-364 (folds AZ-360) — AZ-377 needs AZ-371 Phase 4 (Typing/config/tooling/polish): AZ-371 → AZ-370 → AZ-373 → AZ-374 → AZ-375 → AZ-376 → AZ-378 → AZ-379 → AZ-380 → AZ-372
Step 9 cycle 1 (Multi-source tile storage epic AZ-483)
- AZ-484 — Multi-source tile storage schema (foundational)
Step 9 cycle 2
- AZ-487 — JWT validation baseline (must merge first; AZ-488 hard-depends on it)
- AZ-488 — UAV tile upload endpoint + 5-rule quality gate (consumer of both AZ-484 contract and AZ-487 auth)
Step 9 cycle 3
Independent tracks — most tasks can run in parallel; the only ordering constraint is the AZ-491 → AZ-492 soft dependency for token-mint reuse.
- AZ-495 (1 SP) — doc-folder convention. Cheapest unblocker; lands first to stop the F1 recurrence.
- AZ-491 (3 SP) — consolidate JWT test-mint helpers. Pre-stages AZ-492 if implementer picks Option B.
- AZ-493 (2 SP) — integration test DB-reset hook. Independent.
- AZ-496 (2 SP) — bump AspNetCore 8.0.25. Independent.
- AZ-492 (3 SP) — perf harness. After AZ-491 if Option B; else any time.
- AZ-494 (2 SP) — JWT iss/aud validation. Gated on cross-team input; not blocked by other cycle-3 tasks.
Step 9 cycle 4
Single task; coordinated cross-cutting bump.
- AZ-500 (5 SP) — .NET 8 → .NET 10 migration. Self-contained but touches every csproj, both Dockerfiles, run-tests.sh, .woodpecker/01-test.yml, global.json, and two docs files.
Step 9 cycle 5
Independent tracks — both can run in parallel; no ordering constraint between them. AZ-504 is a prerequisite for the cycle's Step 15 Performance Test to deliver a green PT-08 reading (and therefore for deleting the perf-cycle3 leftover); AZ-503 is the cycle's main feature (foundation half — see split note above).
- AZ-504 (1 SP) — cheapest unblocker; lands first to clear PT-08 reporting for the cycle.
- AZ-503 (3 SP, foundation half) — main feature; data-model + identity plumbing; cross-workspace alignment with
gps-denied-onboardAZ-304. - AZ-505 (3 SP) — deferred to cycle 6;
Blocks-linked to AZ-503.
Step 9 cycle 6
Single task; consumes the AZ-503-foundation columns landed in cycle 5.
- AZ-505 (3 SP) — Tile inventory endpoint + HTTP/2 + Leaflet covering index. Self-contained but produces TWO contract artifacts (new
contracts/api/tile-inventory.mdv1.0.0 + bumpcontracts/data-access/tile-storage.mdv1.0.0 → v2.0.0 per architecture.md).
Step 9 cycle 7 (AZ-794 / AZ-795 / AZ-796)
Adopted into cycle 7. Ordering:
- AZ-795 shared infrastructure (FluentValidation + global ProblemDetails filter +
JsonSerializerOptions.UnmappedMemberHandling.Disallow) — gates every per-endpoint child. - AZ-794 (rename) — lands the final wire-format names so AZ-796 validators can use them from day one.
- AZ-796 (inventory validator) — first per-endpoint child; serves as reference implementation for sibling per-endpoint child tasks.
- Sibling per-endpoint child tasks under AZ-795 — added by parent-suite team as they enumerate the surface from
/swagger/v1/swagger.json(out of cycle 7 scope; future cycles).
Total Effort
Step 6: 6 tasks, 17 story points Step 8 (02-coupling-refactoring): 6 tasks, 17 story points Step 8 (03-code-quality-refactoring): 27 tasks, ~66 story points Step 9 cycle 1: 1 task created (AZ-484, 5 pts) Step 9 cycle 2: 2 tasks created (AZ-487 = 2 pts, AZ-488 = 8 pts over-cap user-accepted) — total 10 pts Step 9 cycle 3: 6 tasks created (AZ-491 = 3 pts, AZ-492 = 3 pts, AZ-493 = 2 pts, AZ-494 = 2 pts, AZ-495 = 1 pt, AZ-496 = 2 pts) — total 13 pts Step 9 cycle 4: 1 task created (AZ-500 = 5 pts) Step 9 cycle 5: 3 tasks tracked (AZ-503 = 3 pts foundation-half, AZ-504 = 1 pt, AZ-505 = 3 pts split-off-deferred) — 4 pts committed to cycle 5, 3 pts deferred to cycle 6 Step 9 cycle 6: 1 task scheduled (AZ-505 = 3 pts) — consumed from cycle-5 deferral Step 9 cycle 7: 3 tasks adopted (AZ-794 = 3 pts rename, AZ-795 = epic with 5–8 pts shared-infra ship, AZ-796 = 3 pts first per-endpoint child) — total ~11–14 pts (over the 2–5 pts/cycle preference; AZ-795's shared-infra ship is the heavy item). Origin: gps-denied-onboard AZ-777 Phase 1 Jetson probe (2026-05-22). Sibling per-endpoint child tasks under AZ-795 to be added in future cycles as the parent-suite team enumerates the endpoint surface.
Coverage Verification
| Test Spec Category | Covered By |
|---|---|
| blackbox-tests.md (BT-01..BT-12, BT-N01..BT-N05) | AZ-286, AZ-287, AZ-288, AZ-289 |
| performance-tests.md (PT-01..PT-06) | AZ-290 |
| resilience-tests.md (RS-01..RS-06) | AZ-290 |
| security-tests.md (SEC-01..SEC-04) | AZ-290 |
| resource-limit-tests.md (RL-01..RL-04) | AZ-290 |
| traceability-matrix.md (100% AC coverage) | All tasks combined |