# Deploy Report — Cycle 10 (AZ-1113) **Date**: 2026-06-25 **Cycle**: 10 **Scope**: REST 400 error message sanitization (AZ-1113). ## What is shipping ### Code changes | Area | Change | |------|--------| | `GlobalExceptionHandler.cs` | Static `JsonException` / `BadHttpRequestException` client messages | | `UavUploadValidationFilter.cs` | Static metadata parse error string | | `UavTileUploadHandler.cs` | Defense-in-depth metadata parse sanitization | | Unit + integration tests | Assertions for static strings; no `System.` in UAV 400 bodies | | `error-shape.md` | v1.0.0 → **v1.0.1** (Information Disclosure section) | | `docker-compose.perf.yml` | **New** — unsets postgres host port for perf/tests when 5433 is occupied | | `scripts/run-performance-tests.sh` | PT-07: 15s queue drain; pass on warm p95 < cold p95 **or** warm p50 < cold p50 | | `performance-tests.md` | PT-07 pass criterion aligned with AZ-492 AC-2 | ### Database migrations **None.** ### Configuration changes | Setting | Change | |---------|--------| | New env vars | **None** | | Container image | Rebuild only — same `aspnet:10.0` base; no Dockerfile changes | | Consumer contracts | `error-shape.md` patch bump — field paths unchanged; message content only | ### Contract changes (consumer-visible) | Contract | Change | Consumer action | |----------|--------|-----------------| | `error-shape.md` v1.0.1 | 400 deserializer/binding messages are static strings | Clients must not parse error message text (already documented in Inv-5 / Non-Goals); field paths unchanged | | REST / gRPC wire shapes | Unchanged | No action | ## Verification gates passed in this cycle | Gate | Result | Evidence | |------|--------|----------| | Step 11 — Functional tests | **PASS** | 450/450 unit + integration smoke EXIT:0 (~2.5m) | | Step 12 — Test-Spec Sync | **PASS** | BT-33, SEC-14..16, traceability AZ-1113 rows | | Step 13 — Update Docs | **PASS** | `api_program.md`, test module docs, ripple log | | Step 14 — Security Audit | **PASS** (delta) | `security_report_cycle10.md`; F-AZ795-1/2, F-AZ810-1 **resolved** | | Step 15 — Performance Test | **PASS** | `perf_2026-06-25_cycle10.md` — 8/8 after PT-07 harness fix | ## Security carry-overs (post-cycle-10) | ID | Status | |----|--------| | F-AZ795-1, F-AZ795-2, F-AZ810-1 | **Resolved** (AZ-1113) | | F-AZ810-2 | Open — `DateTime` vs `DateTimeOffset` on `capturedAt` | | D-AZ795-1 | Open — FluentValidation 12.0.0 → 12.1.1 | | D2-cy4 | Open — test SDK JWT advisory (test-runtime only) | ## Operator runbook 1. **Commit and push** cycle-10 changes to `origin/dev`; confirm CI green. 2. **No migration** — deploy new API image only. 3. **Smoke-test** after deploy: - POST malformed JSON to any validated endpoint → 400 with static message, no `System.` substring - POST `/api/satellite/upload` with bad `metadata` → `errors["metadata"]` static string - Existing happy paths unchanged (region, route, inventory, UAV upload) 4. **Perf harness** (optional): use `docker compose -f docker-compose.yml -f docker-compose.perf.yml up -d` when host port 5433 is taken by a sibling Postgres. ## Release note `/release` prerequisites (`scripts/deploy.sh`, `_docs/04_release/`) are **not present** in this repo — production promotion remains operator-driven (image build + compose on target host). Step 16.5 should be **skipped** unless release infrastructure is onboarded. **Verdict**: Cleared for retrospective (Step 17). Release (16.5) skipped — no release execution harness.