# Static Analysis (Cycle 13)

**Date**: 2026-06-26
**Mode**: Delta scan
**Scope**: AZ-1126 `capturedAt` → `DateTimeOffset` + `UtcOffsetRequiredDateTimeOffsetConverter`. Cycle-10 baseline remains authoritative elsewhere.

**Files in scope**:
- `SatelliteProvider.Common/DTO/UavTileMetadata.cs`
- `SatelliteProvider.Common/Json/UtcOffsetRequiredDateTimeOffsetConverter.cs`
- `SatelliteProvider.Api/Validators/UavTileMetadataValidator.cs`
- `SatelliteProvider.Api/Validators/UavUploadValidationFilter.cs`
- `SatelliteProvider.Services.TileDownloader/UavTileQualityGate.cs`
- `SatelliteProvider.Services.TileDownloader/UavTileUploadHandler.cs`
- Unit + integration tests for offset-less rejection

**Method**: Read changed call sites; verify offset-less ISO strings rejected before persistence; confirm no new `ex.Message` echoes; grep for remaining `DateTimeKind` branching on upload path.

## Resolved findings (AZ-1126)

### F-AZ810-2 — `UavTileMetadata.CapturedAt` typed `DateTime` not `DateTimeOffset` (Low / Informational) — **RESOLVED**

- **Location**: `UavTileMetadata.cs`, validators, quality gate, upload handler.
- **Resolution**: `CapturedAt` is `DateTimeOffset` with `UtcOffsetRequiredDateTimeOffsetConverter` rejecting offset-less strings at deserialization. Freshness rules compare via `UtcDateTime`. Integration test `ItemCapturedAtOffsetLess_Returns400` binds the rejection path.

## Pass areas (cycle-13 delta)

| Area | Result |
|------|--------|
| SQL injection | N/A — no SQL changes |
| Hardcoded secrets | None introduced |
| Information disclosure (400 paths) | Unchanged from AZ-1113 — static strings preserved |
| New attack surface | Narrower — ambiguous timestamps rejected earlier |
| Inventory read path | `TileInventoryEntry.CapturedAt` remains `DateTime?` — intentional, out of scope |

## Verdict

**PASS** (cycle-13 delta) — F-AZ810-2 closed; zero new findings.
