mirror of
https://github.com/azaion/satellite-provider.git
synced 2026-06-21 10:51:15 +00:00
1802d32107
Replaces the 501 stub at POST /api/satellite/upload with a multipart
batch endpoint that ingests UAV-captured tiles, runs each item through
a 5-rule quality gate, and persists accepted tiles via the AZ-484
multi-source storage path with source='uav'.
Quality gate (in fixed order, first failure wins): JPEG format
(content-type + magic), size band 5 KiB-5 MiB, exact 256x256
dimensions, captured-at age (no future >30 s skew, no older than
7 days), luminance variance on 32x32 downsample. Closed reject-reason
enumeration in v1.0.0 contract.
Authorization: custom PermissionsRequirement / PermissionsAuthorization
Handler that reads the JWT `permissions` claim (tolerates both
repeated-string and JSON-array shapes). Endpoint protected by
RequiresGpsPermission policy; 401 without token, 403 without GPS perm.
Persistence: file-first to ./tiles/uav/{z}/{x}/{y}.jpg, then
ITileRepository.InsertAsync UPSERT (per-source UPSERT contract from
AZ-484). Per-item failures reported in response without aborting the
batch. Kestrel MaxRequestBodySize and FormOptions limits set to
MaxBatchSize x MaxBytes (default 100 x 5 MiB = 500 MiB).
New frozen contract: _docs/02_document/contracts/api/uav-tile-upload.md
v1.0.0. PT-08 NFR added to performance-tests.md as Deferred (harness
work tracked in PT-07 leftover, per AZ-488 § Risk 4).
Tests: 11 quality-gate unit tests, 5 handler unit tests, 3 file-path
unit tests, 12 permission-handler unit tests, 7 integration tests
(AC-1..AC-6, AC-8). All 253 unit tests + smoke integration suite
green.
Co-authored-by: Cursor <cursoragent@cursor.com>
8.2 KiB
8.2 KiB
Batch Report — Batch 02 cycle 2
Batch: 02 (cycle 2) Tasks: AZ-488 (UAV tile upload endpoint + 5-rule quality gate) Date: 2026-05-11
Task Results
| Task | Status | Files Modified | Tests | AC Coverage | Issues |
|---|---|---|---|---|---|
| AZ-488_uav_tile_upload | Done | 9 modified + 13 added (UavTileBatchUploadRequest.cs, UavQualityConfig.cs, UavTileMetadata.cs, UavTileBatchUploadResponse.cs, PermissionsRequirement.cs, UavTileQualityGate.cs, UavTileUploadHandler.cs, UavTileImageFactory.cs, UavTileQualityGateTests.cs, UavTileUploadHandlerTests.cs, UavTileFilePathTests.cs, PermissionsRequirementTests.cs, UavUploadTests.cs, contract doc uav-tile-upload.md); SatelliteProvider.Api/DTOs/UploadImageRequest.cs deleted |
All green (unit 253/253 + smoke integration including UavUploadTests) |
10/10 ACs covered | 0 blockers; 4 Low findings (see review) |
AC Test Coverage: All covered (10 of 10)
Code Review Verdict: PASS_WITH_WARNINGS
Auto-Fix Attempts: 1 (in-flight build fix: removed unused using Microsoft.AspNetCore.Http; in UavTileUploadHandler.cs after first --unit-only revealed it broke Service-layer build)
Stuck Agents: None
What was implemented
- New batch DTOs replacing the old stub:
UavTileBatchUploadRequest(multipart envelope with JSONmetadata+IFormFileCollection) inApi/DTOs;UavTileMetadata,UavTileBatchMetadataPayload,UavTileBatchUploadResponse,UavTileUploadResultItem,UavTileUploadStatus, and the closedUavTileRejectReasonsenumeration inCommon/DTO(placed in Common so Layer 3 services can reference them without a Service → API back-edge). LegacyUploadImageRequestdeleted. - New config:
Common/Configs/UavQualityConfig.cs(MinBytes/MaxBytes/MaxAgeDays/CapturedAtFutureSkewSeconds/MinLuminanceVariance/MaxBatchSize/LuminanceSampleSize).appsettings.jsonships defaults underUavQuality. - New service
Services.TileDownloader.UavTileQualityGate(implsIUavTileQualityGate) running the 5 rules in fixed order (Format → Size → Dimensions → Captured-at → Uniformity). Welford's online variance on a 32×32 ImageSharp downsample keeps the heuristic ~< 50 ms / item.TimeProviderinjected for deterministic age tests. - New service
Services.TileDownloader.UavTileUploadHandler(implsIUavTileUploadHandler) orchestrating envelope validation (batch size / mismatch / malformed JSON), per-item gate run, file-first-then-row persistence (./tiles/uav/{z}/{x}/{y}.jpg), and per-item result construction. UsesTileSourceConverter.ToWireValue(TileSource.Uav)per L-001. - New authorization:
Api/Authentication/PermissionsRequirement.cs+PermissionsAuthorizationHandlerreading thepermissionsclaim — tolerates both repeated-string and JSON-array shapes.SatellitePermissions.UavUploadPolicy("RequiresGpsPermission") wires theGPSpermission requirement. Program.cswires:UavQualityConfigbinding, KestrelMaxRequestBodySize = MaxBatchSize × MaxBytes = 500 MiB,FormOptions.MultipartBodyLengthLimit+ValueLengthLimit,IUavTileQualityGate+IUavTileUploadHandler+PermissionsAuthorizationHandlerDI registrations,AddAuthorization(RequiresGpsPermission policy), SwaggerMapType<UavTileBatchUploadRequest>so the multipart shape renders correctly, and the newUploadUavTileBatchendpoint replacing the 501 stub.- Tests:
- Unit:
UavTileQualityGateTests(11 — every rule happy + reject + ordering),UavTileUploadHandlerTests(5 — happy/mixed/oversize/mismatch/invalid JSON),UavTileFilePathTests(3 — path shape + invariants),PermissionsRequirementTests(12 — claim shape coverage),UavTileImageFactorytest utility. - Integration:
UavUploadTests.RunAll(AC-1 happy, AC-2 mixed-batch, AC-3 multi-source coexistence with pre-seededgoogle_mapsrow, AC-4 same-source UPSERT with file overwrite + db refresh, AC-5 401 no-token, AC-6 403 wrong perm, AC-8 oversized 400).StubAndErrorContractTestsupdated to drop the old 501-stub assertion.
- Unit:
- Docs:
- New frozen contract
_docs/02_document/contracts/api/uav-tile-upload.mdv1.0.0 — endpoint shape, request/response, 5-rule quality gate, closed reject-reason enum, file-path layout, concurrency model, versioning rules, test cases. architecture.md: UAV ingestion is live; permission-handler description; ADR-004 updated for the per-source file-path split (UAV under./tiles/uav/, google_maps grandfathered at bare./tiles/).glossary.md:UAV Tile Upload,Quality Gate, and all 7 reject-reason constants.modules/api_program.md: new endpoint row, new local DTOs section, DI registration steps including the body-size cap math, security policy description, configuration section addsUavQuality.components/03_tile_downloader/description.md: documents the two new public types, their dependencies, and the file-path divergence vs. legacy Google Maps tiles.data_model.md:file_pathsemantics now per-source (UAV vs google_maps).tests/performance-tests.md: PT-08 (UAV upload latency NFR) added with StatusDeferred — harness work tracked in PT-07 leftover._docs/_process_leftovers/2026-05-11_perf-pt07-harness.mdupdated with the PT-08 follow-on instruction so PT-08 lands when PT-07 lands.
- New frozen contract
Test results (Step 10 verification)
- Unit: 253/253 passed (single docker container,
dotnet/sdk:8.0, ~3.2 s test time after restore). - Integration (smoke): all green including the new
UavUploadTestssuite (which runs before the smoke/full branching). - Pre-existing AZ-487 test bugs surfaced and fixed in separate
fix:commits (see below) — were masked by a CS0104 build error.
Pre-existing fixes shipped alongside this batch
Three small fix: commits were made on dev BEFORE the AZ-488 batch commit because they were blocking the test gate for AZ-488:
753be43 [AZ-487] fix: resolve CS0104 ambiguity in AuthN tests—Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensionscollided with our same-named class inSatelliteProvider.Api.Authentication. Resolved viausingalias.f64d0d7 [AZ-487] fix: JWT factory + tests now pass on net8.0—JwtTokenFactory.Createwith a negative lifetime producedExpires < NotBefore, whichJwtSecurityTokenrejects at construction. ShiftednotBeforebehindexpiresfor non-positive lifetimes. Also disabledMapInboundClaimsinJwtTokenFactoryTestsso assertions read the factory's actual claim names ("sub", "email", "permissions") rather than.NET-defaultClaimTypes.*aliases.11b7074 [AZ-487] fix: integration-test JWT factory handles negative lifetime— sameExpires < NotBeforeissue in the integration-test side's own copy atSatelliteProvider.IntegrationTests/JwtTestHelpers.cs.
All three are AZ-487 test-side hygiene that became observable only after the CS0104 build error was lifted. They are independent of the AZ-488 feature commit; user implicitly approved option B during the autodev pause.
Open follow-ups (non-blocking)
- Doc-folder choice (F1, carried over from batch 01):
_docs/02_document/components/01_web_api/description.mdreferenced by the spec doesn't exist; updates went intomodules/api_program.mdinstead. Needs an operator decision on whether to add a stub01_web_apifolder or formalize the convention. File.WriteAllBytesAsync(byte[])allocation (F4 in review): up to 5 MiB array copy per accepted tile. Replace withFileStream.WriteAsync(ReadOnlyMemory<byte>, ct)when PT-08 measurement begins. Not blocking — Rule 5 decode + downsample dominates the gate cost target.- PT-08 runner-script scenario: deferred to land with the PT-07 harness expansion (per cycle 1 retro Action 2 / AZ-488 § Risk 4). Tracked in
_docs/_process_leftovers/2026-05-11_perf-pt07-harness.md. - Coordinate external consumers for AZ-488:
gps-denied-onboardand any mission-planner client that posts to/api/satellite/uploadmust attach a Bearer token withpermissions: ["GPS"](or the JSON-array shape"[\"GPS\"]"— handler accepts both). Coordination is the operator's at Step 16 (Deploy).
Next: Step 11 (Run Functional Tests) — autodev auto-chain
Cycle 2 batches all closed. Next autodev step is test-run → deploy (per flows/existing-code.md auto-chain rules).