Commit 96437536 authored by Sergio Gimenez's avatar Sergio Gimenez
Browse files

docs: renumber the SRM->FM hand-off record to ADR-0053

parent 33841b7f
Loading
Loading
Loading
Loading
+6 −5
Changes for decisions/0053-srm-fm-federated-deploy-handoff-split-request-and-result.md: 6 added lines, 5 removed lines.
Original line number Diff line number Diff line
---
type: Decision Record
title: "ADR-0052: The SRM→FM federated lifecycle hand-off is a synchronous internal HTTP request plus an asynchronous DataBus result event"
title: "ADR-0053: The SRM→FM federated lifecycle hand-off is a synchronous internal HTTP request plus an asynchronous DataBus result event"
description: "The SRM→FM federated lifecycle hand-off is a synchronous internal HTTP request plus an asynchronous DataBus result event"
tags: [adr]
timestamp: 2026-09-22T00:00:00Z
status: "proposed"
---

# ADR-0052: The SRM→FM federated lifecycle hand-off is a synchronous internal HTTP request plus an asynchronous DataBus result event
# ADR-0053: The SRM→FM federated lifecycle hand-off is a synchronous internal HTTP request plus an asynchronous DataBus result event

**Status:** proposed
**Date:** 2026-09-22
**Affects:** [fm/overview-and-architecture.md](/fm/overview-and-architecture.md) (§G4 open item, UC-FM-07), [fm/requirements-and-design.md](/fm/requirements-and-design.md) (§L.3a, the SRM→FM internal HTTP surface), [srm/interface-contract.md](/srm/interface-contract.md) (§C.4 events, §F.4a the federated hand-off flow), [platform/architecture.md](/platform/architecture.md) (Component Boundary Matrix)

> **Numbering note.** `0052` is the next free number given `0045`/`0047` on `develop`,
> `0046`/`0049`/`0050`/`0051` on the `oeg-fm` branch, and `0048` on `docs/platform-roles`. Confirm
> at MR time — `oeg-fm` has already renumbered once (`0047`/`0048` → `0050`/`0051`).
> **Numbering note.** `0053` clears the whole range in flight on the `oeg-fm` branch
> (`0046`, `0049`, `0050`, `0051`) and `0048` on `docs/platform-roles`, deliberately skipping
> `0052` so a further renumber on either branch cannot collide with this record. `oeg-fm` has
> already renumbered once (`0047`/`0048` → `0050`/`0051`). Re-check at MR time.

## Context

+1 −1
Changes for decisions/index.md: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -52,4 +52,4 @@ the reasoning lives here. Never renumber; supersede instead (see the record-deci
* [ADR-0049](0049-terminal-record-read-follows-camara-schema.md) - terminal-record read behaviour follows each family's own vendored CAMARA schema: Traffic Influence returns 200 with `state: deleted`, QoD stays 404 (amends ADR-0034's blanket 404 rule and its 204 delete code)
* [ADR-0050](0050-oeg-federation-lifecycle-proxy-errors-are-gsma-problem-json.md) - OEG's federation-lifecycle proxy endpoints (§N.7, ADR-0046) return OPG.04 `application/problem+json` `ProblemDetails` for every error - FM's errors relayed unchanged, OEG's own 400/401/403/502/503 from a fixed template; ADR-0030's `ErrorInfo` rule is scoped to OEG's CAMARA northbound surface
* [ADR-0051](0051-oeg-fronts-federation-lifecycle-ewbi-byte-for-byte.md) - OEG fronts eight GSMA federation-lifecycle operations on its own platform namespace, `/platform/v1/federation/partners/{partnerOpId}/federations/...`, scoped by a registered `partnerOpId` (create/read/update/delete federation, fed-context-id lookup, zone list/subscribe/details/unsubscribe), forwarding the raw GSMA request/response byte-for-byte to FM including the query string, pinned to GSMA OPG.04 v6.0 / artifact v1.4.0; operator-triggered outbound only, separated from inbound EWBI at the ingress; keeps ADR-0046's sync-HTTP/stateless/no-DataBus transport and ADR-0050's error model (amends this ADR's own first version, which used the bare canonical OPG.04 paths and lost the partner addressing GSMA gets for free from the URL)
* [ADR-0052](0052-srm-fm-federated-deploy-handoff-split-request-and-result.md) - the SRM→FM federated lifecycle hand-off splits by hop: a synchronous internal HTTP `POST` (`/internal/federation/deploy`, `/internal/federation/terminate`) answered `202`, then `event.fm.operation.completed` on OOP_EVENTS for the outcome, because OPG.04 returns no result on the request and SRM exposes no HTTP lifecycle mutation endpoint; covers terminate as well as deploy, restores SRM's `service_order` row as the idempotency anchor while keeping no `service_instance` rows, sets a 30-minute default deploy-callback deadline (resolves §G4)
* [ADR-0053](0053-srm-fm-federated-deploy-handoff-split-request-and-result.md) - the SRM→FM federated lifecycle hand-off splits by hop: a synchronous internal HTTP `POST` (`/internal/federation/deploy`, `/internal/federation/terminate`) answered `202`, then `event.fm.operation.completed` on OOP_EVENTS for the outcome, because OPG.04 returns no result on the request and SRM exposes no HTTP lifecycle mutation endpoint; covers terminate as well as deploy, restores SRM's `service_order` row as the idempotency anchor while keeping no `service_instance` rows, sets a 30-minute default deploy-callback deadline (resolves §G4)
+3 −3
Changes for fm/overview-and-architecture.md: 3 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -430,7 +430,7 @@ A locally connected App Provider deploys to an Edge Cloud Zone that turns out to
  1. OEG publishes `command.srm.service.deploy` unconditionally, as it does for every deploy (no locality check in OEG).
  2. SRM checks its own zone inventory; not found locally, so it queries FM for federated zone/capability data.
  3. FM returns the matching federated zone entry (from `shared_resource_catalogues`).
  4. SRM forwards the deploy to FM using FM's internal schema (not raw GSMA/OPG.04) via a synchronous `POST /internal/federation/deploy` answered `202`; the outcome returns later on `event.fm.operation.completed` (ADR-0052, §G4).
  4. SRM forwards the deploy to FM using FM's internal schema (not raw GSMA/OPG.04) via a synchronous `POST /internal/federation/deploy` answered `202`; the outcome returns later on `event.fm.operation.completed` (ADR-0053, §G4).
  5. FM maps the request to OPG.04 `InstallApp` and executes the outbound EWBI call to the partner's FM, through the same code path used for inbound federation-originated deploys (UC-FM-01's fulfillment pipeline).
  6. FM reports the result back to SRM, which resumes its normal `event.srm.operation.completed` lifecycle for the original command.
- **Why this exists:** Keeps placement (local-vs-federated) a single SRM-owned decision instead of splitting it between OEG and FM; see ADR-0044.
@@ -554,11 +554,11 @@ goes through OEG at all — see G4.

**Recommendation:** Internal HTTP from OEG to FM for all outbound federation hand-offs (synchronous queries). OEG calls FM with the routing identifiers and original request context; FM resolves the partner, forwards over EWBI, and returns the result to OEG. This keeps EWBI protocol knowledge inside FM and avoids a second async hop on the developer-facing latency path. Initially, OEG rejects non-local requests with a 400/404 (federation not yet available). The OEG spec already anticipates this pattern in UC-OEG-05.

### G4. SRM → FM Hand-off for Federated Deployment (resolved by ADR-0052)
### G4. SRM → FM Hand-off for Federated Deployment (resolved by ADR-0053)

**The question was:** When SRM determines a deploy target zone is federated (UC-FM-07), what is the exact hand-off contract to FM — synchronous internal HTTP or a new async DataBus command?

**Status: resolved (ADR-0052).** Both, split by hop, and extended to cover termination as well as deployment. The request hop is a synchronous internal HTTP `POST` to FM (`/internal/federation/deploy`, `/internal/federation/terminate`) answered `202`; the result hop is `event.fm.operation.completed` on `OOP_EVENTS`, which SRM consumes and republishes as `event.srm.operation.completed`. A second channel is unavoidable because OPG.04 `InstallApp` returns only `202` plus a later callback, and `RemoveApp` returns `200` with no callback at all; and FM cannot call back into SRM over HTTP because SRM exposes no HTTP lifecycle mutation endpoints. ADR-0052 also amends the SRM hand-off flow so SRM writes a `service_order` row (the idempotency anchor) while still writing no `service_instance` rows, and sets FM's deploy-callback deadline at a 30-minute default. See [srm/interface-contract.md §F.4a](/srm/interface-contract.md) and [fm/requirements-and-design.md §L.3a](/fm/requirements-and-design.md).
**Status: resolved (ADR-0053).** Both, split by hop, and extended to cover termination as well as deployment. The request hop is a synchronous internal HTTP `POST` to FM (`/internal/federation/deploy`, `/internal/federation/terminate`) answered `202`; the result hop is `event.fm.operation.completed` on `OOP_EVENTS`, which SRM consumes and republishes as `event.srm.operation.completed`. A second channel is unavoidable because OPG.04 `InstallApp` returns only `202` plus a later callback, and `RemoveApp` returns `200` with no callback at all; and FM cannot call back into SRM over HTTP because SRM exposes no HTTP lifecycle mutation endpoints. ADR-0053 also amends the SRM hand-off flow so SRM writes a `service_order` row (the idempotency anchor) while still writing no `service_instance` rows, and sets FM's deploy-callback deadline at a 30-minute default. See [srm/interface-contract.md §F.4a](/srm/interface-contract.md) and [fm/requirements-and-design.md §L.3a](/fm/requirements-and-design.md).

---

+5 −5
Changes for fm/requirements-and-design.md: 5 added lines, 5 removed lines.
Original line number Diff line number Diff line
@@ -503,10 +503,10 @@ from L.5, plus:
|---|---|---|
| `no-route` | 404 | No routing rule matches `identifier_value`; no partner could be resolved |

### L.3a SRM → FM Internal HTTP (Federated Lifecycle Hand-off, ADR-0044, ADR-0052)
### L.3a SRM → FM Internal HTTP (Federated Lifecycle Hand-off, ADR-0044, ADR-0053)

For zone-based deployment targeting, SRM — not OEG — determines locality and hands off to FM when
the work belongs to a partner. ADR-0044 established the ownership; ADR-0052 fixes the transport:
the work belongs to a partner. ADR-0044 established the ownership; ADR-0053 fixes the transport:
a synchronous internal HTTP request here, and an asynchronous `event.fm.operation.completed` on
`OOP_EVENTS` for the result (§M.1). The two hops exist because OPG.04 returns no outcome on the
request: `InstallApp` answers `202` and reports later via callback, and `RemoveApp` answers `200`
@@ -558,7 +558,7 @@ troubleshooting only — SRM stores it opaquely and never interprets it.
**Idempotency.** `operation_id` is the key. A repeat carrying an `operation_id` FM has already
accepted returns `202` with the original body and starts no second EWBI exchange. SRM may therefore
retry freely; retry ownership for this hop is SRM's, inside its own async `command.srm.*` handling
(ADR-0052).
(ADR-0053).

**Instance resolution on terminate.** SRM does not look the instance up first. It finds the
`service_instance_id` absent from its local inventory, posts the terminate, and FM resolves the
@@ -727,7 +727,7 @@ contract comparison silently.
| `command.srm.service.terminate` | OOP_TASKS | `SrmServiceTerminateV1` | OPG.04 `RemoveApp` authenticated and agreement-checked |
| `command.srm.network.capability.activate` | OOP_TASKS | `SrmNetworkCapabilityActivateV1` | Inbound EWBI network capability request |
| `command.srm.network.capability.deactivate` | OOP_TASKS | `SrmNetworkCapabilityDeactivateV1` | Inbound EWBI network capability release |
| `event.fm.operation.completed` | OOP_EVENTS | `FmOperationCompletedV1` | Terminal outcome of an **outbound** federated deploy or terminate handed off by SRM (§L.3a, ADR-0052) |
| `event.fm.operation.completed` | OOP_EVENTS | `FmOperationCompletedV1` | Terminal outcome of an **outbound** federated deploy or terminate handed off by SRM (§L.3a, ADR-0053) |

`event.fm.operation.completed` is the result hop of the SRM→FM hand-off. It exists because OPG.04
returns no outcome on the request itself, and because SRM exposes no HTTP lifecycle mutation
@@ -762,7 +762,7 @@ operations different guarantees:
| `deadline_expired` | deploy | No callback arrived within FM's configured wait (default 30 minutes); `status` is `failed` |

Consumers must not treat `partner_accepted` as proof of removal. Detecting a termination a partner
accepted but never performed belongs to reconciliation (ADR-0052).
accepted but never performed belongs to reconciliation (ADR-0053).

**Topology hiding applies to this event** (REQ-FED-13). `external_ref` is a partner-issued handle
and is safe; partner zone identifiers, endpoints and internal references are not carried.
+4 −4
Changes for srm/interface-contract.md: 4 added lines, 4 removed lines.
Original line number Diff line number Diff line
@@ -513,7 +513,7 @@ Stream `OOP_TASKS`; Filter mutating `command.srm.*`; Deliver All; Ack **Explicit
| `event.srm.catalog.updated` | v1 | SRM | OEG, FM | Durable, at-least-once | Catalog cache invalidation; FM partner catalog re-sync |
| `event.srm.inventory.drift_detected` | v1 | SRM | OEG, portal | Durable, at-least-once | Drift alert |
| `event.srm.inventory.drift_resolved` | v1 | SRM | OEG, portal | Durable, at-least-once | Drift cleared |
| `event.fm.operation.completed` | `FmOperationCompletedV1` | FM | SRM | Durable, at-least-once | Terminal outcome of an outbound federated deploy/terminate (§F.4a, ADR-0052) |
| `event.fm.operation.completed` | `FmOperationCompletedV1` | FM | SRM | Durable, at-least-once | Terminal outcome of an outbound federated deploy/terminate (§F.4a, ADR-0053) |

FM does not publish `command.srm.service.scale` or `command.srm.network.capability.update`: no
OPG.04 v1.4.0 EWBI operation maps to the former, and the latter needs an explicit OPG.04
@@ -848,10 +848,10 @@ Same as F.1; FM publishes with `source=federation` and `federation_partner_ref`,
events, strips operator-internal topology before returning upstream. This is the **inbound** case
— a partner OP's request that already targets our own infrastructure.

### F.4a Federated lifecycle hand-off (SRM → FM, ADR-0044, ADR-0052)
### F.4a Federated lifecycle hand-off (SRM → FM, ADR-0044, ADR-0053)

The **outbound** case: OEG publishes `command.srm.service.deploy` or `.terminate` as in F.1, with no
locality information — SRM decides. ADR-0044 gave SRM that decision; ADR-0052 fixes the hand-off as
locality information — SRM decides. ADR-0044 gave SRM that decision; ADR-0053 fixes the hand-off as
a synchronous internal HTTP request plus an asynchronous result event, because OPG.04 returns no
outcome on the request itself.

@@ -887,7 +887,7 @@ instance running), `partner_accepted` (the partner accepted a termination — OP
callback for `RemoveApp` and no `TERMINATED` state, so removal is *not* confirmed), or
`deadline_expired` (no deploy callback arrived within FM's configured wait).

**Record ownership (amended by ADR-0052).** SRM **writes a `service_order` row** for federated
**Record ownership (amended by ADR-0053).** SRM **writes a `service_order` row** for federated
deploys and terminates, as it does for every command it accepts: it is the `UNIQUE(operation_id)`
idempotency anchor (§D.4) and the record that lets SRM correlate a late
`event.fm.operation.completed` after a restart. SRM **writes no `service_instance` rows** — a