Commit 90f0ec77 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

feat: Update OEG and SRM interface contracts to clarify service specification...

feat: Update OEG and SRM interface contracts to clarify service specification IDs and response structures
parent f70bae85
Loading
Loading
Loading
Loading
+19 −3
Changes for oeg/interface-contract.md: 19 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -412,7 +412,7 @@ OEG can stay the public read entry point without becoming the catalog authority.
**External request**

```http
POST /api/device-location/v1/retrieve
POST /api/location-retrieval/v0.5/retrieve
Authorization: Bearer <JWT>
Content-Type: application/json
```
@@ -442,15 +442,31 @@ Content-Type: application/json
}
```

**Illustrative upstream response**
**Illustrative upstream response** — SRM answers in canonical names, never CAMARA's
([srm/interface-contract.md](/srm/interface-contract.md) §E.2):

```json
{
  "last_location_time": "2026-07-04T12:00:00Z",
  "area": { "area_type": "circle", "center": { "latitude": 52.52, "longitude": 13.405 }, "radius_m": 800 },
  "srm_resolved_identifier": "phone_number"
}
```

**External response** — OEG translates back into CAMARA shapes:

```json
{
  "lastLocationTime": "2026-07-04T12:00:00Z",
  "area": { "areaType": "CIRCLE", "center": { "latitude": 52.52, "longitude": 13.405 }, "radius": 800 }
  "area": { "areaType": "CIRCLE", "center": { "latitude": 52.52, "longitude": 13.405 }, "radius": 800 },
  "device": { "phoneNumber": "+1234567890" }
}
```

The `device` echo names the **one** identifier that produced this answer, as CAMARA requires
when the caller supplied any. It is copied from `srm_resolved_identifier` when SRM reports
one; otherwise OEG falls back to a fixed precedence order and the echo is a best guess.

**Key lesson**  
Some API families are query-like enough that the sync path is the right fit. They still go through OEG so auth, policy, and metering stay consistent. The synchronous contract covers Device Location and Device Status only; Number Verification is not yet contracted (see [srm/interface-contract.md](/srm/interface-contract.md) §E.2).

+62 −0
Changes for srm/interface-contract.md: 62 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -512,6 +512,68 @@ Call TF-SDK synchronously, return data directly, create **no** `service_order` /
Body: `correlation_id`, `app_provider_id`, `service_specification_id`, optional
`zone_id`/`domain_id`, `target`, optional `profile_ref`, `parameters`.

**`service_specification_id` — where the value comes from.** These families have no
registration step to resolve an id from, so each uses **one platform-seeded specification**
whose id is a well-known constant — the same problem and the same answer as QoD
([ADR-0035](/decisions/0035-qod-session-service-specification.md)). SRM's topology bootstrap
seeds it; OEG falls back to it when nothing is configured.

Both sides **derive** the value rather than copying a literal:

```
uuid5(NAMESPACE_URL, "https://etsi.org/sdg/oop/service-specification/{ref}/1")
```

`{ref}` is the specification's `ref` (the `capability_kind`, hyphenated) and the trailing `1`
its `version`. The string is a **name fed to UUIDv5**, not a resolvable address — nothing
fetches it. Deriving means either side can regenerate the id from the recipe instead of
trusting a pasted constant.

| Capability | `ref` | Well-known id |
|---|---|---|
| `qod_session` | `qod-session` | `7608e902-b927-559f-b448-e7e9061dfa5c` |
| `location_context` | `location-context` | `0129e7ce-8e02-5dfd-bae1-0303bcc7676e` |

This is a **two-sided contract**. Seeding a different id on one side without configuring the
other leaves `service_specification_id` pointing at no row — for async capabilities that is
`failed_before_start` on every activate (ADR-0035); for these sync queries the call simply
cannot resolve a control path.

**Location response.** `POST /network-queries/location` answers `200` with:

```json
{ "last_location_time": "2023-10-17T13:18:23.682Z",
  "area": { "area_type": "circle",
            "center": { "latitude": 45.754114, "longitude": 4.860374 },
            "radius_m": 800 },
  "srm_resolved_identifier": "phone_number" }
```

`area.area_type` is either `circle` (with `center` and `radius_m`) or `polygon` (with
`boundary`, a list of 3-15 points). `last_location_time` is RFC 3339 **with a time zone**.
Names are canonical, never CAMARA's — OEG owns that translation
([oeg/architecture.md](/oeg/architecture.md)).

**`srm_resolved_identifier` — which identifier the network actually used.** Optional; one of
`phone_number`, `ipv4`, `ipv6`, `network_access_id`.

The problem it solves, in order:

1. A caller may send **several** identifiers for one device, because different operators
   support different ones (CAMARA `Device`, NOTE1). OEG forwards all of them in `target`.
2. The network uses **whichever one it can resolve**. Only SRM's adapter knows which.
3. CAMARA then requires OEG to tell the caller **which single identifier produced this
   answer** (`DeviceResponse`, `maxProperties: 1`). That echo is the caller's only signal
   that the result describes the device they meant.

Without this field OEG has to guess, and it guesses by a fixed precedence order — which can
name a different identifier than the network used. Setting it is what makes the CAMARA echo
a fact instead of an approximation. It is named for its origin (`srm_`) because at the point
of use OEG holds both values, and only this one is authoritative.

Omit the field when the adapter cannot report a choice; OEG falls back to its precedence
order and stays functional.

Number Verification is **not** part of this contract; model separately.

### E.3 Diagnostics