# Region API: rename Latitude/Longitude → Lat/Lon (OSM convention)

**Task**: AZ-812_region_field_rename_to_osm
**Name**: Rename `RequestRegionRequest.{Latitude, Longitude}` → `{Lat, Lon}` for OSM consistency
**Description**: Rename the JSON wire-format fields on `RequestRegionRequest` from verbose `latitude`/`longitude` to OSM-standard short `lat`/`lon`. Mirror of AZ-794 (which did the same for the inventory endpoint's `tileZoom/tileX/tileY` → `z/x/y`). Breaking wire-format change.
**Complexity**: 3 points (same scope as AZ-794: DTO rename + downstream code + docs + manual probe; no new behavior)
**Dependencies**: — (coordinate ordering with AZ-808 — see *Coordination*)
**Component**: SatelliteProvider.Common (RequestRegionRequest DTO) + SatelliteProvider.Services (RegionService consumers) + SatelliteProvider.IntegrationTests + producer docs
**Tracker**: AZ-812 (https://denyspopov.atlassian.net/browse/AZ-812)
**Originating ticket**: gps-denied-onboard AZ-777 Phase 2 (cross-repo, 2026-05-22) — black-box probe revealed Region is the lone hold-out using verbose `latitude`/`longitude` while every other coord field across the API uses OSM-standard `lat`/`lon` / `z/x/y`

## Scope

Rename the JSON wire-format fields on `RequestRegionRequest` from verbose `latitude`/`longitude` to OSM-standard short `lat`/`lon`. Mirror of **AZ-794** (which did the same for the inventory endpoint's `tileZoom/tileX/tileY` → `z/x/y`). This is a **breaking wire-format change**.

Originating discovery: gps-denied-onboard AZ-777 Phase 2 black-box probe (2026-05-22). The consumer probed `POST /api/satellite/request` with `{"lat":49.94,"lon":36.31,...}` (OSM convention, matching the slippy-map URL `/tiles/{z}/{x}/{y}` and the Route endpoint's `RoutePoint`/`GeoPoint` DTOs which already use `lat`/`lon`). The producer rejected with HTTP 400 — the Region endpoint is the lone hold-out using verbose `latitude`/`longitude`.

Jira AZ-812 is the authoritative spec; this file mirrors the in-workspace-only sections.

## Why this matters

Current state — satellite-provider's coord-naming surface is **internally inconsistent**:

| Endpoint / DTO | Field names | Source |
|---|---|---|
| `GET /tiles/{z}/{x}/{y}` | `z`, `x`, `y` | URL path — OSM slippy-map standard |
| `POST /api/satellite/tiles/inventory` body | `z`, `x`, `y` | AZ-794 (cycle 7) |
| `POST /api/satellite/route` → `RoutePoint` | `lat`, `lon` | `[JsonPropertyName("lat")]` already in DTO |
| `POST /api/satellite/route` → `GeoPoint` | `lat`, `lon` | `[JsonPropertyName("lat")]` already in DTO |
| `POST /api/satellite/request` body | `latitude`, `longitude` | **← the outlier this ticket fixes** |

After this rename, every coord field in every satellite-provider request body uses the OSM short form. Consumers can rely on one naming convention end-to-end.

A secondary issue surfaced by the same probe — the Route endpoint's **response** echoes points as `latitude`/`longitude` even though the request shape uses `lat`/`lon` (input/output asymmetry on the same DTO round-trip). This task **does not** fix that (it's the Route DTO's response shape, not the Region request). Surfaced as AZ-809 AC-10 advisory for a separate follow-up if parent-suite team confirms it's a bug.

## Endpoint surface

`POST /api/satellite/request`

Before (current):

```json
{
  "id": "<guid>",
  "latitude": 49.94,
  "longitude": 36.31,
  "sizeMeters": 200,
  "zoomLevel": 18,
  "stitchTiles": false
}
```

After:

```json
{
  "id": "<guid>",
  "lat": 49.94,
  "lon": 36.31,
  "sizeMeters": 200,
  "zoomLevel": 18,
  "stitchTiles": false
}
```

## Implementation

1. Modify `SatelliteProvider.Common/DTO/RequestRegionRequest.cs`:
   - Rename C# properties: `Latitude` → `Lat`, `Longitude` → `Lon`.
   - Add `[JsonPropertyName("lat")]` / `[JsonPropertyName("lon")]` so the wire format is unambiguous even if anyone later reads the camelCase defaults.
2. Find all references via `git grep -w 'Latitude\|Longitude' SatelliteProvider.*/` — update C# usages in:
   - `SatelliteProvider.Services/RegionService.cs` (or wherever the handler unpacks the DTO).
   - `SatelliteProvider.IntegrationTests/RegionTests.cs` + `SatelliteProvider.IntegrationTests/Models.cs`.
   - Any other test fixtures / mocks.
3. Update the OpenAPI spec snapshot test (if one exists).
4. Update producer documentation:
   - `_docs/02_document/modules/common_dtos.md::RegionRequest` — update field-name listing.
   - `_docs/02_document/modules/api_program.md::RequestRegion Handler` — update example body.
   - `_docs/02_document/system-flows.md::F2 Region Request Flow` — update example body.
5. The new `_docs/02_document/contracts/api/region-request.md` (to be created by AZ-808) MUST use the post-rename field names. Coordinate with AZ-808 implementer: if AZ-808 lands first, the contract starts at v1.0.0 with `latitude/longitude`, then this task bumps to v2.0.0 with `lat/lon`. If this task lands first, AZ-808's contract starts at v1.0.0 with `lat/lon` directly.

## Acceptance criteria

**AC-1**: `RequestRegionRequest` DTO uses `Lat` / `Lon` (C#) + `[JsonPropertyName("lat")]` / `[JsonPropertyName("lon")]`.

**AC-2**: Wire format is `{"lat":..,"lon":..}` end-to-end (request body, OpenAPI schema, docs, all integration tests).

**AC-3**: `RegionTests.cs` happy-path tests pass against the new wire format.

**AC-4**: Manual `curl` probe with `{"id":"<guid>","lat":49.94,"lon":36.31,"sizeMeters":200,"zoomLevel":18,"stitchTiles":false}` returns HTTP 200 + valid regionId; old `{"latitude":..,"longitude":..}` returns HTTP 400 with `UnmappedMemberHandling.Disallow` rejecting the unknown fields.

**AC-5**: Docs updated: `common_dtos.md`, `api_program.md`, `system-flows.md` (F2).

**AC-6**: If `region-request.md` contract doc exists at the time this task lands (AZ-808 already shipped), bump v1.0.0 → v2.0.0 with a change-log entry naming AZ-812. If `region-request.md` does NOT yet exist (AZ-808 still in flight), coordinate so AZ-808 publishes v1.0.0 directly with the new names — then this task only needs to land the code + non-contract docs.

## Coordination with sibling tickets

- **AZ-794** (inventory rename): same pattern, same justification. Recommended to follow the same hard-switch rollout strategy AZ-794 used.
- **AZ-808** (region validation): hard coordination point. Pick the ordering during planning — either ship this first so AZ-808 writes validators against the final names, or ship together as a coordinated release.
- **AZ-777 Phase 2** (gps-denied-onboard consumer): the consumer adapter for Region API will be written against the final names — prefer this ticket lands first or co-ships with AZ-808 so the consumer doesn't have to migrate twice.
- **Follow-up (not in scope)**: the Route endpoint's input/output point-shape asymmetry (input `lat`/`lon`, output `latitude`/`longitude`). Tracked as AZ-809 AC-10 advisory; file separately if parent-suite team confirms.

## Constraints

- **Breaking wire-format change** — same risk profile as AZ-794. Known consumer set: gps-denied-onboard (AZ-777 Phase 2 — will adapt before first integration). Other consumers TBD.
- Coordinate with AZ-808 to avoid validator code being written against the wrong names.
- No regression in `RegionTests.cs` happy-path coverage.

## References

- Jira AZ-812: https://denyspopov.atlassian.net/browse/AZ-812
- Mirror of: AZ-794 (inventory body-field rename)
- Hard coordination with: AZ-808 (region validator)
- Parent epic context: AZ-795 (validation epic provides the `UnmappedMemberHandling.Disallow` infra that makes this rename safely diagnosable on the consumer side)
- Originating probe: gps-denied-onboard AZ-777 Phase 2 black-box probe of Region API (2026-05-22)
- Current DTO: `SatelliteProvider.Common/DTO/RequestRegionRequest.cs`
- Sibling DTOs already using lat/lon: `SatelliteProvider.Common/DTO/RoutePoint.cs`, `SatelliteProvider.Common/DTO/GeoPoint.cs`
