[AZ-812] Region API: rename Latitude/Longitude → Lat/Lon (OSM convention)

Mirror of AZ-794 (inventory z/x/y rename). RequestRegionRequest.cs renames C#
props Latitude→Lat / Longitude→Lon and adds [JsonPropertyName("lat"/"lon")] so
the wire format is unambiguous under the AZ-795 strict-parsing stack
(UnmappedMemberHandling.Disallow → legacy {"latitude":..,"longitude":..} now
returns HTTP 400 instead of silently coercing).

Updates all in-repo consumers: API handler (Program.cs), integration tests
(Models.cs, RegionTests.cs, IdempotentPostTests.cs, SecurityTests.cs), the
performance harness (run-performance-tests.sh PT-03/04/05/07), and module
docs (common_dtos.md, api_program.md; system-flows.md F2 already used
lat/lon). New RegionFieldRenameTests.cs covers AC-4 both directions (new
format → 200, legacy format → 400). Smoke green; no regressions.

region-request.md contract doc not bumped here — AZ-808 publishes v1.0.0
directly with the post-rename names per AZ-812 coordination clause.

Batch 01 of cycle 8. PASS_WITH_WARNINGS (one Low DRY finding for follow-up
test-helper consolidation; details in
_docs/03_implementation/reviews/batch_01_cycle8_review.md).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-22 15:54:53 +03:00
parent 0810a89ef1
commit fcd494f67e
14 changed files with 268 additions and 18 deletions
@@ -1,117 +0,0 @@
# 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`