# Acceptance Criteria Assessment — UAV Batch Upload

**Date**: 2026-05-11
**Mode**: Research Phase 1 (AC & Restrictions Assessment)
**Result**: No changes required — user explicitly validated all 5 critical assumptions in the new-task Step 2 BLOCKING gate immediately preceding this research run.

## Acceptance Criteria

| Criterion | Our Values | Researched Values | Cost/Timeline Impact | Status |
|-----------|------------|-------------------|----------------------|--------|
| Per-tile minimum metadata | lat, lon, tile_zoom, tile_size_meters, captured_at, image bytes | Industry-standard for tile uploads (TMS / OGC Tile API) defines x/y/zoom + time + payload as the minimum viable set | None — matches industry norms | Confirmed |
| Sync 200 + per-tile mixed array response | 200 OK with `[{tileId, status, reason?}]`; 4xx for batch-level failures only | Common pattern in batch APIs; alternative HTTP 207 Multi-Status (RFC 4918) is more correct semantically but rarely used outside WebDAV ecosystems and adds caller complexity for no real gain | None — sync 200 chosen, no change | Confirmed |
| JWT HS256 with `sub` + `exp` only | minimum claims model | NIST SP 800-204A and OAuth 2.0 BCP recommend `iss` + `aud` + `exp` + `sub` for federated; for an internal service with shared HS256 secret, `sub` + `exp` is the documented "trusted-network" minimum (microsoft-jwt-bearer docs) | None | Confirmed |
| Quality gate verdict response-only (not persisted) | string in response, no DB column | Avoids triggering L-001 (Dapper enum bypass); reject reasons are inherently transient — re-uploading should re-run the gate | None — saves a DB column | Confirmed |
| File storage = same `./tiles/{z}/{x}/{y}.jpg` layout as Google Maps | reuse existing layout | The 5-col unique index `(lat, lon, tile_zoom, tile_size_meters, source)` already keeps UAV and GMaps rows separate at the DB level; the file path can collide BUT the per-source UPSERT will overwrite the file owner deterministically (most-recent wins). Single-file-per-cell layout is acceptable IF we agree that the reader gets the most-recently-uploaded JPEG regardless of source. | Acceptable; flagged as a Risk in the eventual task spec — the user may want UAV files in `./tiles/uav/{z}/{x}/{y}.jpg` to keep both bytes addressable for forensics | **Recommend re-confirm in Step 5 Validate Assumptions** |

## Restrictions Assessment

| Restriction | Our Values | Researched Values | Cost/Timeline Impact | Status |
|-------------|------------|-------------------|----------------------|--------|
| .NET 8.0 only | constraint | LTS until November 2026; all libraries researched (`Microsoft.AspNetCore.Authentication.JwtBearer 8.x`, `SixLabors.ImageSharp 3.1.x`) support .NET 8 | None | Confirmed |
| ImageSharp 3.1.11 (existing pin) | constraint | 3.1.11 is current stable in the 3.1 LTS line; APIs for `Image.Identify`, `Image<TPixel>` enumeration are stable since 3.0 | None | Confirmed |
| Npgsql 9.0.2, Dapper 2.1.35 | constraint | No version-specific concerns for the per-source UPSERT path already in `TileRepository` | None | Confirmed |
| No secret manager today | constraint | Forces JWT signing key into env var or appsettings (not Key Vault). User must accept this trade-off; flagged in Security Audit too | None for this cycle | Confirmed |
| Existing `GeofencePolygon` DTO is bbox not polygon | implicit constraint discovered during pre-research grep | Reusing the bbox shape for AZ-488 is consistent with current code; introducing true polygons is a bigger change | Could push AZ-488 from 2 SP to 4-5 SP if true polygons chosen | **Material to AZ-488 sizing — see Q4 in the eventual draft** |

## Key Findings

1. **One genuine open assumption to re-confirm** in new-task Step 5: file storage layout. Same-path-as-GMaps lets the latest source win at the file level too (consistent with the DB read rule), but loses bytes-level forensics for the loser. A separate `./tiles/uav/...` path keeps both — at the cost of a divergent storage convention. The user said "yes, as google maps tiles" in Step 1 so the default is the same path; flagging it once for the spec author.

2. **AZ-488 may be larger than 2 SP** if user wants real polygons. The AZ-485 family research pass should present both options with sizing impact so the user can decide once at spec time, not later during implementation.

3. **No additional AC needed** — the 5 assumptions cover the deliverable surface for this task family. No regulatory / compliance dimension surfaced (this is an internal API — not a public consumer-facing endpoint subject to data-handling regs).

4. **No restrictions to relax** — every constraint listed is forced by either project state (existing libs, no auth, no secret manager) or user decision (sync 200, minimum metadata).

## Sources

- IETF RFC 4918 (HTTP 207 Multi-Status) — read for the response-shape decision; concluded not applicable
- NIST SP 800-204A § 3.4 (Microservice JWT validation) — confirms minimum-claims pattern is acceptable for internal trusted-network services
- `Microsoft.AspNetCore.Authentication.JwtBearer` Microsoft Learn page (verified to be the active 8.x line)
- `SixLabors.ImageSharp` 3.1 release notes on `Image.Identify` stability
- Codebase grep for existing geofence implementation (read locally — no external source)

## BLOCKING decision

**Phase 1 closes without re-blocking the user.** All 5 user-confirmed assumptions stand. The single re-confirmation item (file storage path) will surface naturally at new-task Step 5 (Validate Assumptions); the research draft will pre-fill both options with their trade-offs so the user can decide in one click.

Proceeding to Phase 2 (Problem Research & Solution Draft).
