# Resource Registry — API Management (Instances & Admin)

## Instance Management — base path `/instances`

> 💡 **Architectural Note: Nested JSON vs Flat URIs**  
> Throughout this chapter, you will see deep conceptual structures (like **Facet** instances or **ConsistsOf** instances attached to a **Resource** instance) represented as heavily nested JSON objects. This nesting is used for readability, payload efficiency, and representing the structural graph topology in a single response.  
> However, **the REST URIs remain strictly flat**. You do not update a **Facet** instance by constructing a nested path like `/instances/{resource-type}/{resource-uuid}/{consists-of-type}/{consists-of-uuid}/{facet-type}/{facet-uuid}`. Because every instance (**Resource** instance, **Facet** instance, **IsRelatedTo** instance, or **ConsistsOf** instance) is a topologically independent graph instance with a globally unique UUID, the API addresses every single instance individually via `/instances/{type}/{instance-uuid}`. For the design rationale behind this separation, see [Flat Addressability vs Nested ROA Paths](12-is-architectural-decisions.html#rest-api-flat-addressability-vs-nested-roa-paths).

### Authorization & Token Selection

| Action | HTTP | Path | Query Parameters | IS-M / Infra-M | IS-Admin | Ctx-M | IS-Editor | IS-Contrib | IS-Member |
|--------|------|------|------------------|:--------------:|:--------:|:-----:|:---------:|:----------:|:---------:|
| `List` | GET | `/instances/{type}` | `limit`, `offset`, `polymorphic`, `hierarchical`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `Execute JSON Query` | QUERY | `/instances` (`POST /instances/query` fallback) | `limit`, `offset`, `polymorphic`, `hierarchical`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `Exists` | HEAD | `/instances/{type}/{instance-uuid}` | `hierarchical`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `Read` | GET | `/instances/{type}/{instance-uuid}` | `hierarchical`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `Create` | POST | `/instances/{type}` | `sync`, `bypassHierarchyCheck`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
| `Create / Update` | PUT | `/instances/{type}/{instance-uuid}` | `sync`, `bypassHierarchyCheck`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
| `Merge Update` | PATCH | `/instances/{type}/{instance-uuid}` | `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
| `Remove from Current Context` | DELETE | `/instances/{type}/{instance-uuid}` | `propagationMode`, `dryRun`, `metadataPolicy`, `contextsPolicy`, `membershipScope` | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ |
| `Add to Context` | PUT | `/instances/{type}/{instance-uuid}/contexts/{new-context-uuid}` | `hierarchical`, `propagationMode`, `dryRun`, `metadataPolicy`, `contextsPolicy`, `membershipScope`, `bypassHierarchyCheck` | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | ❌ |
| `Remove from Context` | DELETE | `/instances/{type}/{instance-uuid}/contexts/{context-uuid}` | `hierarchical`, `propagationMode`, `dryRun`, `metadataPolicy`, `contextsPolicy`, `membershipScope`, `bypassHierarchyCheck` | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | ❌ |
| `List Instance Contexts` | GET | `/instances/{type}/{instance-uuid}/contexts` | `hierarchical`, `membershipScope` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

**Token Scope Rule:**

| Operation Group | Token must be issued for |
|----------------|---------------------------|
| `List`, `Execute JSON Query`, `Exists`, `Read` | The operational Context from which visibility is evaluated |
| `Create`, `Create / Update`, `Merge Update`, `Remove from Current Context` | The operational Context where the instance is managed |
| `Add to Context` | The token Context is the deterministic source topology. `Ctx-M` and `IS-Editor` may target only its subtree. `IS-M`, `Infra-M`, and `IS-Admin` may also target a sibling Context, and any other live Context only by explicitly supplying `bypassHierarchyCheck=true`. |
| `Remove from Context` | The Context in the path, or `@current` for the token Context. As for `Add to Context`, `Ctx-M` and `IS-Editor` may target only the token Context subtree; `IS-M`, `Infra-M`, and `IS-Admin` may also target a sibling Context, and any other live Context, also under another Root, only by explicitly supplying `bypassHierarchyCheck=true`. |
| `List Instance Contexts` | The operational Context in which the instance is looked up, exactly as for `Read`; it also anchors `membershipScope=subtree` |

### HTTP Contract

| Action | Additional Request Headers | Response Headers | Success HTTP Code | Error HTTP Code |
|--------|----------------------------|------------------|-------------------|-----------------|
| `List` | `Accept` | `Content-Type`, `Link`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found` |
| `Execute JSON Query` | `Content-Type`, `Accept` | `Content-Type`, `Link`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden` |
| `Exists` | `Accept` | `Content-Length`, `Content-Type`, `Link`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found` |
| `Read` | `Accept` | `Content-Type`, `Link`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found` |
| `Create` | `Content-Type`, `Accept` | `Content-Type`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `201 Created` | `400 Bad Request`, `403 Forbidden`, `404 Not Found`, `409 Conflict` |
| `Create / Update`        | `Content-Type`, `Accept` | `Content-Type`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `201 Created` / `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found`, `409 Conflict` |
| `Merge Update`        | `Content-Type: application/merge-patch+json`, `Accept` | `Content-Type`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found`, `409 Conflict` |
| `Remove from Current Context` | `Accept`, `Prefer` (return) | `Content-Type`, `X-Warning`, `Preference-Applied`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found`, `409 Conflict` |
| `Add to Context` | `Accept`, `Prefer` (return) | `Content-Type`, `X-Warning`, `Preference-Applied`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found`, `409 Conflict` |
| `Remove from Context` | `Accept`, `Prefer` (return) | `Content-Type`, `X-Warning`, `Preference-Applied`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found`, `409 Conflict` |
| `List Instance Contexts` | `Accept` | `Content-Type`, `Link`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden`, `404 Not Found` |

### Operational Notes

- **`HEAD` Is the Bodyless Read:** `HEAD /instances/{type}/{instance-uuid}` is the automatic bodyless view of the corresponding `GET`, not an independent operation with reduced semantics. It accepts the same `hierarchical`, `metadataPolicy`, `contextsPolicy`, and `membershipScope` parameters and returns the same status and representation headers (plus the computed `Content-Length`), while omitting only the response body.
- **`List` Endpoint `403` Absence:** The `List` endpoint never returns `403 Forbidden` for data visibility boundaries. Results are strictly filtered according to the token's operational Context. If no instances exist within the token's scope, it simply returns an empty list `[]`, even if those instances exist in other Contexts. *(Note: A `List` operation returns `403 Forbidden` only for authorization reasons, never because nothing is visible: when the caller has no Resource Registry role, when it requests a privileged parameter value it is not entitled to (e.g., `membershipScope=global`), or when the token Context itself is in a non-`active` state, which acts as a global administrative block for standard roles, as detailed in the Context Management chapter).*
- **Path vs Body Consistency (Double-Check):** When creating or updating an instance via `PUT` or `PATCH` on `/instances/{type}/{instance-uuid}`, the `type` and `id` parameters in the URL path must exactly match the `type` and `id` fields provided inside the JSON payload. The same holds for the `type` of a `POST /instances/{type}`: a body `type` different from the path, a subtype included, returns `400 Bad Request`. Even though `PATCH` acts as a partial merge, the `type` and `id` fields are strictly mandatory in the JSON body. If they are missing or do not match, the server strictly rejects the request with a `400 Bad Request` to prevent accidental data corruption or schema-mismatch errors.
- **Type-in-Path Semantics (Exact Type Enforcement):** For all endpoints targeting a specific instance using the path variable `{type}` (e.g., `/{type}/{instance-uuid}`), the client **MUST specify the exact concrete Type** of the instance. Specifying an abstract supertype (e.g., calling `/instances/Resource/{uuid}` when the instance is actually an `EService`) is strictly invalid. On `HEAD`, `GET`, `PATCH`, and `DELETE` it is rejected with a `404 Not Found` (as the requested composite key `(type, instance-uuid)` effectively does not exist, which safely prevents any existence leakage of the UUID). The same `404 Not Found` holds, on every endpoint that addresses the `(type, instance-uuid)` key (`HEAD`, `GET`, `PATCH`, `DELETE`, `List Instance Contexts`, `Add to Context`, and `Remove from Context`), for a `{type}` that is not a **Resource**, **Facet**, **IsRelatedTo**, or **ConsistsOf** Type, such as a **`Property`** Type; on `POST`, on `PUT`, and on the collection `GET /instances/{type}` such a Type returns `400 Bad Request`. `PUT` and `POST` follow the creation and update rules below: an abstract Type cannot be instantiated (`409 Conflict`), and a UUID already identifying an instance of another Type is occupied (`409 Conflict`). The system enforces strict 1:1 parity between the concrete instance schema and the `{type}` path parameter. *(Note: This exact-match restriction applies strictly to single-instance targeting endpoints. The collection endpoint `GET /instances/{type}` fully supports querying by abstract supertypes when combined with the `polymorphic=true` parameter).*
- **Instance Creation Scope:** While flat URIs address every graph instance individually for reads and updates, standalone creation via `POST /instances/{type}` or `PUT /instances/{type}/{instance-uuid}` is structurally valid only for **Resource**, **IsRelatedTo**, and **ConsistsOf** instances, of a concrete Type: a creation request for an abstract Type returns `409 Conflict`. As dictated by the core IS-Model topology, a **Facet** instance cannot exist independently (a standalone creation request for a **Facet** Type returns `400 Bad Request`) and must be created exclusively as a nested element (either within a parent **Resource** mutation payload, or within a standalone **ConsistsOf** mutation payload acting as its `target`). When a Relation instance is created on its own, its endpoints follow the direction of the Relation:
  - **`source`** is always an endpoint reference to a **Resource** instance that already exists; it is never created by the Relation. A `source` that is missing `type` or `id`, or that carries anything beyond an endpoint reference, returns `400 Bad Request`. A source that does not exist returns `404 Not Found`, and so does a `type` that is not the concrete Type of the instance, because the source is looked up by its exact `(type, id)` key; a source that exists but is not present in the token Context returns `403 Forbidden`.
  - **ConsistsOf `target`:** always the complete new **Facet** instance, created together with the **ConsistsOf** instance. A reference to an existing **Facet** instance is rejected with `409 Conflict`, because every **Facet** instance already has its own **ConsistsOf** instance and can have only one.
  - **IsRelatedTo `target`:** either an endpoint reference to an existing **Resource** instance, or the complete new **Resource** instance (with its **ConsistsOf**/**Facet** composition), created together with the **IsRelatedTo** instance. An endpoint reference (`type` and `id` only) to a UUID that does not exist returns `404 Not Found`: a reference never creates. A referenced target that exists but is not present in the token Context returns `403 Forbidden`.

  When a Relation instance is updated, `source` is an endpoint reference to the persisted source, and `target` is either an endpoint reference to the persisted target or its complete representation, which updates it (see below). The same payload that created a Relation instance together with its target can therefore be repeated with the same outcome.
- **`Create` (`POST`) — Optional Client-Supplied UUIDs:** Unlike `PUT`, `POST /instances/{type}` does not require an `id` on the root instance or on any instance nested in it. Any supplied `id` is honored only when it is globally unused. An `id` that is already in use, by an instance of any Type or by any other registry element, is a creation conflict (`409 Conflict`): the request is well formed and fails only because of the current state of the registry. Because the whole payload tree is created inside a single database transaction, a conflict anywhere in the tree rolls back the entire request atomically.
- **`Create` (`POST`) Is Intentionally Not Idempotent:** Two identical `POST` requests that omit every `id` always produce two distinct instances (**Resource**, **Facet**, **IsRelatedTo**, or **ConsistsOf** alike, depending on what is being created) — this is deliberate `POST` semantics per [RFC 9110 §9.3.3](https://datatracker.ietf.org/doc/html/rfc9110#section-9.3.3), not a limitation. Clients that need retry-safety for a specific element should supply that element's own `id`; see the point above for what happens on a resubmit in that case.
- **Writes on instances outside the token Context:** A `PUT` or `PATCH` whose root instance, or an existing **ConsistsOf** or **Facet** instance named in its body, exists but is not present in the token Context returns `403 Forbidden`, by the same rule as lookups. A write never brings an existing instance into the token Context: it enters it only through `Add to Context`. The only write that extends membership is a `PUT` with `hierarchical=true`, which reaches the descendants of the token Context (see Hierarchical Distribution below).
- **Lookup (`403` vs `404`):** For instance lookup endpoints (`HEAD`/`GET` on `/instances/{type}/{instance-uuid}`), the API intentionally distinguishes `404 Not Found` (no instance exists for the requested lookup key) from `403 Forbidden` (an instance matching the lookup key exists, but is outside the caller's authorization scope). This distinction is preserved by design for operational diagnosability. Given the D4Science exposure model (write surfaces internal; `/access` facade internet-facing but read-scoped), this is an explicit and accepted security/operational trade-off. Mutation collision checks can also disclose UUID occupancy through `POST` conflicts or cross-Type validation, so returning `403 Forbidden` on `GET` does not materially change the threat model.
- **Point Read Scope Contract (`hierarchical`):** Point lookups (`HEAD` / `GET /instances/{type}/{instance-uuid}`) intentionally support `hierarchical` for scope alignment with collection discovery. Without `hierarchical=true`, lookup is restricted to the token Context; with `hierarchical=true`, lookup is evaluated against the authorized descendant subtree.
- **Discovery -> Fetch Symmetry Rule:** If a client discovers an instance through a hierarchical collection operation (`GET /instances/{type}?hierarchical=true` or `QUERY /instances?hierarchical=true`), it should keep the same `hierarchical=true` scope on the subsequent point read. Dropping the flag narrows the scope and can legitimately turn a previous discovery into `403 Forbidden` on point fetch.
- **Lookup vs UUID Uniqueness:** Point lookup uses the exact composite key `(type, instance-uuid)` so that a wrong concrete Type returns `404 Not Found` without disclosing which Type owns the UUID. Mutation validation nevertheless enforces one graph-wide UUID namespace across all instance categories and Types.
- **`PUT` Create-or-Update and UUID Reuse:** The root UUID addressed by `PUT /instances/{type}/{instance-uuid}` creates the instance when globally unused and updates it in place when it already identifies the same concrete Type. A nested UUID identifying the same concrete Type is likewise updated only when its immutable topology (ownership or Relation endpoints) is consistent with the payload; an inconsistent placement or endpoint assertion returns `409 Conflict`. Any root or nested UUID already identifying an instance of a different concrete Type returns `409 Conflict`, as every occupied UUID does. A UUID composed entirely of one repeating hexadecimal character (e.g., `1111…11`, `aaaa…aa`) is reserved by the system: supplying one as an instance ID or as a target Context ID returns `400 Bad Request` (see ["System" Environments](12-is-architectural-decisions.html#system-environments-infrastructure-metadata)). These rules are deterministic.
- **`List Instance Contexts` returns:** Returns a map of Context UUID → Context path. With the default `membershipScope=subtree`, every role receives memberships within the token Context subtree; a Root Context token therefore yields a topologically global subtree. `IS-M`, `Infra-M`, and `IS-Admin` may instead request `membershipScope=global` to receive every membership independently of the token Context. The instance is looked up exactly as by `Read` and `Exists`, for every role and every `membershipScope` value: it must be present in the token Context, or in one of its descendants when `hierarchical=true`; otherwise the request returns `403 Forbidden` (or `404 Not Found` when the exact `(type, instance-uuid)` key does not exist). `membershipScope` only selects which memberships of the instance found this way are returned. The response emits `Link: rel="up"` pointing back to the owning instance URI. Omitting memberships outside an explicitly requested `subtree` emits no `X-Result-Scope` token; `state-filtered` is emitted when the applicable state policy removes a membership inside the requested boundary.

### Contextual Mutations & Update Intent (`PUT` vs `PATCH`)

*(Note on Response Shape: All `PUT` and `PATCH` operations on the base instance path `/instances/{type}/{instance-uuid}` always return a representation with the same structural shape as a standard `Read` operation for the targeted instance. Even if `sync` is used to distribute the state across multiple Contexts, the API response remains strictly bounded to the requested target instance. These operations do not trigger broad topological traversal (unlike membership operations) and therefore **do not** return an Operation Envelope).*

Because **Resource** instances act as structural hubs for their nested **Facet** instances (via **ConsistsOf** instances), and because all these graph nodes are shared across Contexts by reference rather than being duplicated, updating a **Resource** instance's topology in one Context can have broader repercussions. To effectively manage these shared topologies, the API explicitly distinguishes between `PATCH` (Merge) and `PUT` (Full Replace) operations, providing an escalating mechanism of topological impact.

**Important (Global Property Mutations):** Because property fields are intrinsically bound to the single underlying instance, modifying a property field via `PATCH` or `PUT` applies globally across *all* Contexts where that instance is shared. Therefore, the concept of a hierarchical Context sync applies exclusively to topological structural changes (i.e., modifying the graph structure, such as attaching or detaching **Facet** instances), never to property field mutations.

#### `PATCH` (Merge Semantic)

`PATCH` applies a **Merge** semantic (`application/merge-patch+json`), modifying only the provided fields and leaving the rest of the instance intact. In accordance with [RFC 7396](https://datatracker.ietf.org/doc/html/rfc7396), arrays containing standard data fields (e.g., a list of strings) are treated as atomic values; providing such an array in a `PATCH` payload will completely replace the existing array.

- **Mandatory Identity Fields:** Even though a Merge Patch normally allows clients to send only the fields they wish to change, the Resource Registry strictly requires the top-level `type` and `id` fields to be present in the JSON body. These fields must exactly match the `type` and `id` provided in the URL path. If they are omitted or mismatched, the request is instantly rejected with a `400 Bad Request`.
- **Relation endpoints in a `PATCH`:** On a **IsRelatedTo** or **ConsistsOf** instance, `source` and `target` may be omitted. When present they follow the same rules as in a `PUT`: system fields inside them are dropped, a malformed `source` or `target` returns `400 Bad Request`, and one that identifies a different endpoint returns `409 Conflict`. A `target` that carries content is merged into the persisted target, exactly as a `PATCH` addressed to the target itself does; a `target` that is an endpoint reference leaves it untouched.
- **Null and Omission Semantics:** An omitted property is left unchanged, whereas an explicitly submitted `null` is an update instruction that removes the property in accordance with RFC 7396. Optional properties may therefore be removed through `PATCH`; mandatory properties cannot be removed, and attempting to do so results in `409 Conflict` during schema validation. The model does not expose `notnull` as an independent constraint.
- **Pragmatic Deviation on Graph Arrays:** The Resource Registry API intentionally diverges from the RFC rule for structural graph arrays like `consistsOf` when the `PATCH` is performed on a **Resource** instance. If a `PATCH` payload on a **Resource** instance includes a `consistsOf` array, the backend performs a surgical merge: it patches only the explicitly referenced **ConsistsOf** and **Facet** instances (requiring both the `id` of the **ConsistsOf** instance and the `id` of its target **Facet** instance to safely match the instances) without dropping the omitted ones. If a client attempts to execute a `PATCH` omitting these nested IDs (e.g., intending to create a new nested structure on the fly), the request is strictly rejected with a `400 Bad Request`. To create new topological structures like adding a new **Facet** instance, clients must use a `PUT` operation: a `PATCH` never creates, so a nested `id` that does not exist returns `400 Bad Request`, and a **ConsistsOf** instance whose submitted target `id` differs from its persisted **Facet** instance returns `409 Conflict`, because a Relation never changes endpoint. A nested **ConsistsOf** instance that belongs to another **Resource** instance returns `409 Conflict`, as in a `PUT`. `PATCH` does not support hierarchical parameters: they are ignored with `X-Warning` for roles allowed to use them, and return `403 Forbidden` for any other role.

#### `PUT` on Resource Instances (Topological Impact)

When the target of a `PUT` operation is a **Resource** instance, the API enforces a **Full Replace** semantic for the target Context. Any **ConsistsOf** instance or nested **Facet** instance omitted from the payload will be systematically removed from the Context: it leaves the token Context only, stays unchanged in every other Context it belongs to, and is deleted when the token Context was its last one. This enables atomic, transaction-level replacements of mandatory **Facet** instances without breaking schema validation (e.g., solving the "Cardinality Chicken-and-Egg" problem). The topological impact of a `PUT` operation on a **Resource** instance is governed by its query parameters:

##### 1. Single Context Update (Local Copy-on-Write)

Without hierarchy parameters, the topological effect (adding, removing, or replacing **Facet** instances) is confined strictly to the current token Context. This operation handles any combination of structural changes: adding new **Facet** instances (by including new **ConsistsOf** JSON objects with a freshly client-generated `id` that does not yet exist in the system), removing existing ones (by omitting them from the payload), or both simultaneously.

This simultaneous action is what enables the **Local Copy-on-Write** (Forking) pattern: to create a local variation of a shared **Facet** instance without affecting other Contexts, the client can perform a `PUT` on the parent **Resource** instance, assigning a freshly client-generated `id` to both the new **ConsistsOf** instance and its nested **Facet** instance, instead of the `id` of the shared instances.

The system will create a new isolated clone for the current Context and seamlessly drop the old association locally. (Note: It is crucial to generate fresh ids for both. If the client reused the existing **ConsistsOf** instance's `id` while only generating a new `id` for the **Facet** instance, it would attempt to retarget an existing shared **ConsistsOf** instance to a different **Facet** across different Contexts, which strictly violates the topological rule that a **ConsistsOf** instance points to exactly one immutable **Facet** target).

While a fork could theoretically be achieved using two distinct operations (a `Remove from Current Context` on the existing **ConsistsOf** instance, followed by a standalone creation of a new **ConsistsOf** instance along with its new target **Facet** instance), performing it in two steps is restricted by `min`/`max` constraints on the **Resource**:

- If `max: 1` but no `min`, you could remove then create.
- If `min: 1` but no `max`, you could create then remove.
- If both `min: 1` and `max: 1` are set, any sequential order violates the schema.

More importantly, even without schema constraints, using a single `PUT` on the parent **Resource** is the only way to guarantee that both the addition and the removal are executed atomically within a single transaction.

For example, consider a **Resource** instance `R` currently composed of **Facet** instances `[F1, F2, F3, F4]` in the current Context, where `F1` satisfies a strict `min: 1, max: 1` schema constraint.
If a `PUT` request provides a new configuration `[F1b, F2, F3, F5]`: the old `F1` and `F4` are removed, while the new `F1b` and `F5` are added, all simultaneously.
Because it executes as a single atomic transaction, the `min: 1, max: 1` constraint (transitioning from `F1` to `F1b`) is never violated.

*(Note: Schema validation is strictly evaluated at the very end of the transaction. If the resulting topological state of the **Resource** instance violates its schema, the entire operation is safely rolled back and returns a `409 Conflict`).*

##### 2. Subtree Synchronization (`?sync=existing`)

Safely pushes topological changes (like attaching or detaching **Facet** instances) only to descendant Contexts where the **Resource** instance is already explicitly shared.
This atomically synchronizes the submitted Resource payload across the applicable descendant Contexts.

It is a synchronization of the payload, not a membership operation: every applicable descendant Context is aligned to exactly what the payload describes, and the propagation constraints of the **ConsistsOf** instances are not consulted (they govern `Add to Context` and `Remove from Current Context`, whose outcome depends on the graph rather than on a payload).

Similar to the Single Context Update scenario, attempting to manually replicate these topological shifts across the hierarchy via sequential `Remove from Current Context` and `Add to Context` operations on the nested instances in each child Context is heavily restricted by `min`/`max` constraints on the parent **Resource**:

- If `max: 1` but no `min`, you could remove then add.
- If `min: 1` but no `max`, you could add then remove.
- If both `min: 1` and `max: 1` are set (e.g., swapping `F1` for `F1b`), any manual sequential propagation in the descendant Contexts strictly violates the schema.

By executing the `[F1, F2, F3, F4]` -> `[F1b, F2, F3, F5]` mutation described above with `?sync=existing`, the identical simultaneous atomic replacement occurs not just in the current Context, but simultaneously across all applicable descendant Contexts, safely bypassing the schema deadlock.

**Important (Strict Uniformization):** Because the `PUT` operation enforces a **Full Replace**, any local topological deviations (e.g., an extra **Facet** instance previously added only in a child Context) are systematically wiped out to perfectly align the target Context with the submitted payload.
Because the resulting topology becomes completely uniform across all synced Contexts, the schema validation result is globally deterministic: it is mathematically impossible to adhere to the schema in one Context while violating it in another.

Crucially, a client can also achieve this in two separate phases: they might first update the local Context without the flag, and later issue the identical `PUT [F1b, F2, F3, F5] ?sync=existing` payload.
In this second phase, the operation behaves as a "pure sync": it makes no local topological changes (since the state already matches) but atomically forces the alignment down the hierarchy. This "pure sync" pattern is extremely valuable for reconciling descendant Contexts that have become topologically misaligned (e.g., due to operational drift or mistakes).
Reconciling them in a single shot via `PUT ?sync=existing` is infinitely safer than the manual alternative (i.e., removing the entire **Resource** instance from the descendant Context and re-adding it with the corrected facets).
Removing a **Resource** instance from a Context normally triggers the avalanche destruction of its associated **IsRelatedTo** instances. Even if a client attempted to bypass the standard avalanche using a `surgical` removal of the **Resource** instance, the problem persists: a relation cannot logically exist in a Context if its `source` and `target` **Resource** instances are missing.
Therefore, removing the **Resource** instance inherently drops all its incoming and outgoing **IsRelatedTo** instances from that Context.
The client would then be forced to meticulously track down and perform surgical `Add to Context` operations to restore all those `N` relations (and potentially recreate from scratch any relations that existed *only* in that local Context). The atomic "pure sync" completely avoids this operational nightmare and collateral damage, perfectly restoring the intended schema and structure. (The orphaned `F1` and `F4` continue to exist in any external Contexts; if no longer referenced anywhere, they are destroyed by the Garbage Collector).

*(Note: On a creation, `sync=existing` is logically ignored as the instance does not yet exist anywhere, and the system safely emits an `X-Warning` header. A role that is not allowed to use `sync` receives `403 Forbidden` instead, because authorization is evaluated before applicability; see [Parameter Value Handling](11-api-query-parameters.html#parameter-value-handling)).*

##### 3. Hierarchical Distribution (`?sync=tree`)

Operates identically to the **Subtree Synchronization** mode, but with one fundamental expansion in blast radius: instead of pushing changes *only* to descendant Contexts where the **Resource** instance is already explicitly shared, it forcefully propagates the **Resource** instance itself and all its topological changes to *every* descendant Context within the authorized subtree, systematically overriding local absences.

In other words, `sync=tree` synchronizes the payload over the whole subtree rooted at the token Context, whether or not the **Resource** instance is already present in each descendant: the result in every descendant Context is the same as in the token Context. Like `sync=existing`, it is a synchronization, not an `Add to Context`:

- **The payload decides, not the propagation constraints.** Every **ConsistsOf**/**Facet** instance the payload describes reaches every descendant Context, including those whose **ConsistsOf** instance carries `add=unpropagate`; every one it omits is removed there (strict uniformization, below). Propagation constraints govern membership operations only.
- **Nothing outside the payload moves.** **IsRelatedTo** instances attached to the **Resource** instance, which the payload does not describe, are neither added to nor removed from any descendant Context, and no related **Resource** instance follows. There is no `Add to Context` avalanche.
- **It is the non-administrative way to push a Resource down a subtree.** Hierarchical and `surgical` Add to Context remain restricted to `IS-Admin` or higher because they propagate the live relation graph rather than a caller-bounded payload (see [Privileged Add to Context Uses the Canonical Membership Endpoint](12-is-architectural-decisions.html#privileged-add-to-context-uses-the-canonical-membership-endpoint)).

This mode enforces the exact same strict uniformization, shares the exact same atomic transaction guarantees, and completely bypasses the manual schema violation limitations described above.

*(Note: Unlike `sync=existing`, which is logically ignored on creation (emitting an `X-Warning` header), `sync=tree` is fully supported and actively used during the initial creation of a **Resource** instance to establish a baseline configuration across the entire subtree from day one).*

##### 4. Synchronization of One Context (`?sync={context-uuid}`)

Operates as the **Hierarchical Distribution**, restricted to one named Context: the write is on the token Context, and the named Context ends up with the same **Resource** instance and the same **ConsistsOf**/**Facet** instances. A **ConsistsOf** instance the payload creates is created in both; one the payload names must be present in the token Context or be new. The cardinality constraints are checked on the token Context, and the named Context, aligned to it, satisfies them too; everything is one transaction. It is available on `POST` and `PUT`.

The named Context follows the rules of the destination of `Add to Context`: it must be live, reachable by the caller's role (for `IS-Editor` and `Ctx-M` the token subtree; for `IS-M`, `Infra-M`, and `IS-Admin` also a sibling, and any live Context with `bypassHierarchyCheck=true`) and, for `IS-Editor`, effectively `active` (see [`sync`](11-api-query-parameters.html#sync)).

Its typical use is a change that a Context must take from a parent rather than create on its own, such as the state of a service per Context: a VRE goes back to `active` with a `PUT` from its parent, where the service is active, carrying the **EService** instance as the parent sees it, with `sync={vre-uuid}`. The parent receives what it already holds and is unchanged; the VRE takes the shared `StateFacet` again and its own one leaves it.

#### `PUT` on Other Instances (Full Replace Semantic)

When the target of a `PUT` operation is not a **Resource** instance, the submitted payload is the complete replacement representation, not a merge patch. Every custom property that must remain must be repeated; an omitted optional property is removed, while omission of a mandatory property is resolved with its declared `defaultValue`, or, when none is declared, makes the resulting representation invalid and returns `409 Conflict` after schema validation.

- **Facet instances:** The payload includes matching `type` and `id` plus every custom property that must remain.
- **IsRelatedTo instances:** The payload includes matching `type` and `id`, the complete custom-property set, `source`, `target`, and `propagationConstraint`.
- **ConsistsOf instances:** The payload includes matching `type` and `id`, the complete custom-property set, `source`, `target`, and `propagationConstraint`.

For both Relation categories, `source` and `target` are required and identify the Relation's persisted endpoints, which never change. In its basic form each is an endpoint reference (see [Relation endpoint references](06-data-representation-instances-envelopes.html#isrelatedto-instance)): `type` and `id` are required, while the system fields `supertypes`, `metadata`, and `contexts` are accepted and dropped without warning, so that a Relation read from the API can be submitted back unchanged. An endpoint reference leaves the endpoint untouched.

A `target` whose only other members are an empty `consistsOf` or `isRelatedTo` array is an endpoint reference too. The `target` may instead carry content beyond the system fields: the properties of the **Facet** instance for a **ConsistsOf** instance, or the `consistsOf` composition of the **Resource** instance for an **IsRelatedTo** instance. It is then the complete representation of the target and replaces it, exactly as a `PUT` addressed to the target itself does, with the same validation and the same outcomes. This is what makes the `PUT` that created a Relation instance together with its target repeatable. To change only the Relation instance, submit the `target` as an endpoint reference: a complete representation replaces the target with what is submitted, including any change made to it in the meantime. Since a `target` without content is a reference, the properties of a **Facet** instance cannot all be removed through its **ConsistsOf** instance; that is done with a `PUT` on the **Facet** instance. The `source` is always an endpoint reference.

A missing, null, or malformed `source` or `target`, including a `source` that carries custom fields or nested instances, returns `400 Bad Request`; a well-formed `source` or `target` whose `id` or `type` differs from the persisted endpoint returns `409 Conflict`. `propagationConstraint` is mutable and validated against the concrete Relation contract; it is always required in a `PUT`, on creation and on update alike (omission returns `400 Bad Request`), and optional only in a `POST`, where omission applies the model defaults (see [IS-Model core topology](03-is-model-core-topology.md)). A Relation can be retargeted only by deleting it and creating a new one.

These requirements apply even when a submitted value is unchanged: `PUT` always carries the full client-controlled state. System-managed fields continue to follow the common drop-without-warning rule.

> **Note on `sync`:** Because `sync` exclusively governs the topological distribution of a **Resource** instance, it has no structural meaning when targeting a **Facet**, **IsRelatedTo**, or **ConsistsOf** instance directly. If a client mistakenly passes it when mutating these specific types, the system safely ignores it and emits an `X-Warning` header, for roles allowed to use it (any other role receives `403 Forbidden`, since authorization is evaluated first) (e.g., `199 resource-registry "ignored-query-parameters=sync; ignored-count=1; reason=Not applicable for this instance type"`).

For detailed operational patterns (including **Facet** instance Forking, Copy-on-Write, and resolving cardinality constraints), refer to the [API Operational Cookbook & Advanced Use Cases](appendix/05-api-operational-cookbook.md).

### Membership Operations (`Add to Context` / `Remove from Context`)

> **Conceptual Note (Sharing & Unsharing):** Because Contexts act as logical environments over a global graph, the act of "Adding to Context" can be conceptually viewed as **"sharing"** an instance into another Context, making it visible and usable there. Conversely, "Remove from Current Context" acts as **"unsharing"**. This documentation and the broader ecosystem may occasionally use the terms *share* and *unshare* informally to describe these membership operations.

The API manages an instance's Context membership on one sub-resource, `/instances/{type}/{instance-uuid}/contexts/{context-uuid}`:

1. **Add (`PUT`):** The `Add to Context` operation (`PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}`) adds an instance from a *source* Context (determined by the authorization token) to a *destination* Context (specified in the URL).
2. **Remove (`DELETE`):** The `Remove from Context` operation (`DELETE /instances/{type}/{instance-uuid}/contexts/{context-uuid}`), its inverse, removes it from the Context specified in the URL, or from the token Context when the URL names `@current`.
3. **Remove from the current Context (`DELETE`):** The `Remove from Current Context` operation (`DELETE /instances/{type}/{instance-uuid}`) is the shortcut of `Remove from Context` on `@current` without `hierarchical`, and is available to every writer role.

The source topology is always the exact token Context, even for universal roles and even when
`bypassHierarchyCheck=true` is used. The bypass waives only destination containment; it never turns
the source lookup into a global or hierarchical search. Combining it with `hierarchical=true`
atomically applies that one source blueprint to the destination Context and all its descendants.
`hierarchical=true` applies to an `Add to Context` of any instance category: a **Facet**,
**IsRelatedTo**, or **ConsistsOf** instance is added to the destination Context and all its
descendants as a **Resource** instance is.

> **Implicit Pull on Relations (downstream only):** If the direct target of the `Add to Context` operation is a **Relation** instance (**IsRelatedTo** or **ConsistsOf**), strict topological integrity applies: a **Relation** instance cannot exist in a Context without both its source and its target. The two ends are treated differently, because propagation travels strictly downstream, from source to target, and never upstream (see [Strict Downstream Propagation](04-is-model-mutations-and-avalanches.html#multi-context-mutations)):
>
> - **Source:** the source **Resource** instance must already be in the destination Context. The system never pulls it; when it is missing, the operation fails with `409 Conflict`.
> - **Target:** the system ALWAYS pulls the target **Entity** instance into the destination Context (if it isn't already there), whatever the `add` constraint of the explicitly added **Relation** instance, `unpropagate` included.
>
> The same holds when the direct target is a **Facet** instance: the **ConsistsOf** instance pointing to it is added with it, as a structural requirement and not as upstream propagation, and its source **Resource** instance must already be in the destination Context, otherwise `409 Conflict`.
>
> This guarantees that the graph is always structurally sound within any given Context boundary.

**Authorization Rules:**

- `Ctx-M` and `IS-Editor` can add instances only to the token Context or one of its descendants.
- `IS-M`, `Infra-M`, and `IS-Admin` can add to the token Context subtree or to a sibling Context without an override. A sibling is a Context with the same parent as the token Context; the descendants of a sibling are not siblings, and the Root has none.
- `IS-M`, `Infra-M`, and `IS-Admin` can add to any live Context by explicitly setting `bypassHierarchyCheck=true`.
- `propagationMode=surgical` and `hierarchical=true` on Add to Context require `IS-M`, `Infra-M`, or `IS-Admin`.
- `Remove from Context` follows the same rules on the Context it names: `Ctx-M` and `IS-Editor` reach only the token Context subtree; `IS-M`, `Infra-M`, and `IS-Admin` also reach a sibling Context without an override, and any live Context, also under another Root, with `bypassHierarchyCheck=true`; `hierarchical=true`, which removes the instance from the Context and all its descendants, requires `IS-M`, `Infra-M`, or `IS-Admin`. `propagationMode` keeps the meaning it has on every removal (`surgical` is available to every role allowed to remove).
- `Remove from Current Context` retains its endpoint-specific role and scope rules: it acts on the token Context only, and ignores `hierarchical` with `X-Warning`.

**Add to Context error outcomes:**

| Situation | Status |
|-----------|--------|
| Destination outside the Contexts the role may reach without `bypassHierarchyCheck=true`, or privileged parameter without the required role | `403 Forbidden` |
| Destination Context does not exist | `404 Not Found` |
| Destination Context exists but is `deleted` (cemetery) | `409 Conflict` |
| Source `(type, instance-uuid)` key does not exist | `404 Not Found` |
| Source exists but is not present in the token Context | `403 Forbidden` |
| Token Context, or destination Context, not `active`, for a role without the administrative state override | `403 Forbidden` |
| Final validation of the resulting state fails (e.g., missing source of an explicitly added Relation, mandatory Facet left behind) | `409 Conflict` |

The destination is examined before its reachability: a destination that does not exist or is in the cemetery returns `404 Not Found` or `409 Conflict` also to a caller that could not reach it.

**Remove from Context error outcomes:**

| Situation | Status |
|-----------|--------|
| Context outside the Contexts the role may reach without `bypassHierarchyCheck=true`, or privileged parameter without the required role | `403 Forbidden` |
| Context does not exist | `404 Not Found` |
| Context exists but is `deleted` (cemetery) | `409 Conflict` |
| `(type, instance-uuid)` key does not exist | `404 Not Found` |
| Instance exists but is present neither in the Context nor, with `hierarchical=true`, in any of its descendants | `200 OK`, empty Operation Envelope (the requested state already holds) |
| Token Context, or the Context, not `active`, for a role without the administrative state override | `403 Forbidden` |
| Final validation of the resulting state fails (e.g., a mandatory Facet removed) | `409 Conflict` |

As for `Add to Context`, the Context is examined before its reachability.

Adding or removing from a Context triggers an avalanche effect. Before successfully returning, the system **always** strictly validates the resulting state in the target Contexts to prevent logical inconsistencies (e.g., ensuring mandatory **Facet** instances are present, or ensuring that a **Relation** instance is not added to a Context where its source **Resource** instance is missing). If this final validation fails, the operation is aborted and returns a `409 Conflict` (topological/schema violation). If successful, every membership operation (`Add to Context`, `Remove from Context`, `Remove from Current Context`) returns the full list of instances affected by the avalanche effect. For a removal, the list includes the **Relation** instances that leave the Context only because one of their endpoints does, incoming ones included.

Even though the `Add to Context` operation triggers a complex avalanche process, it is exposed via `PUT` because it is strictly **idempotent**. Calling the endpoint 1 time or 100 times results in the same final graph state. The URI explicitly identifies the membership association. The same endpoint carries the privileged `surgical`, hierarchical, and cross-boundary variants; parameter-level authorization prevents less privileged roles from invoking them. A non-administrative caller that needs to bring a **Resource** instance into descendant Contexts without the relation avalanche uses the hierarchical instance `PUT` instead (*Hierarchical Distribution* above), which carries only the structure described by its payload.

### Operation Envelope and Parameter Matrix

Because these operations can trigger avalanche effects, their canonical response is an **Operation Envelope**. The HTTP status code is always `200 OK` (if successful), but the density of the response body and the effect of query parameters (`metadataPolicy`, `contextsPolicy`, `membershipScope`) depend strictly on the `Prefer: return` header. The default behavior is to return the full representation.

Successful operation-envelope responses always emit `Preference-Applied` with the applied payload shape (`return=representation` or `return=minimal`). When the request omits `Prefer`, the response still emits `Preference-Applied: return=representation` to make the default explicit.

| `dryRun` | `Prefer: return` header | Success HTTP Code | Action | Body Density | `metadataPolicy`, `contextsPolicy`, `membershipScope` |
|:---:|---|---|---|---|---|
| `false` | *Missing* or `representation` | `200 OK` | **Real Execution** | Full Operation Envelope | **Applied** (enrich the returned envelope elements) |
| `false` | `minimal` | `200 OK` | **Real Execution** | Minimal Operation Envelope | **Ignored** (no structural payload to enrich; a privilege-expanding value without the role still returns `403`) |
| `true` | *Missing* or `representation` | `200 OK` | **Simulation Only** | Simulated Full Operation Envelope | **Applied** (enrich the simulated envelope elements) |
| `true` | `minimal` | `200 OK` | **Simulation Only** | Simulated Minimal Operation Envelope | **Ignored** (no structural payload to enrich; a privilege-expanding value without the role still returns `403`) |

**Content Negotiation (`Prefer` header) and Payload Shape:**
Returning the full array of complex objects can be bandwidth-intensive for large avalanche operations. Clients can use the standard HTTP `Prefer` header to explicitly request different shapes of the response payload.

- `Prefer: return=minimal`: Returns a highly optimized flat array payload containing only the core topological fields (`type`, `id`, and for **Relation** instances: `source`, `target`). Custom fields, `supertypes`, `metadata`, `contexts`, and `propagationConstraint` are **strictly omitted**. If a client explicitly passes inclusion query parameters (e.g., `metadataPolicy=root`), the system ignores them to honor the minimal structural contract, and emits a `X-Warning` header (e.g., `199 resource-registry "ignored-query-parameters=metadataPolicy; ignored-count=1; reason=Overridden by Prefer: return=minimal"`).
- `Prefer: return=representation` (Default): Returns the same flat array, with every element in its own complete representation. The system fields `metadata` and `contexts` are included only if explicitly requested via their respective query parameters (`metadataPolicy`, `contextsPolicy`), whereas `propagationConstraint` is inherently included as a standard structural field for all **Relation** instances.

Both forms list every affected instance as a separate element of the array (**Resource**, **Facet**, **IsRelatedTo**, and **ConsistsOf** alike); no element is nested inside another. Every **Relation** element carries `source` and `target`: in the minimal form as `"type"` and `"id"`, in the full form as endpoint references (`type`, `supertypes`, `id`, plus `metadata` with `metadataPolicy=all` and `contexts` with `contextsPolicy=all`). With `metadataPolicy` and `contextsPolicy`, `root` enriches every element of the array and `all` also the endpoint references. See [Operation Envelope Representation](06-data-representation-instances-envelopes.html#operation-envelope-representation).

### Try-Check-Confirm Pattern

Because these operations can trigger powerful and unpredictable avalanches, it is highly recommended to adopt a "Try-Check-Confirm" pattern using `dryRun=true`, and using `Prefer: return=representation` to simulate the operation without persisting changes.

### Removal Paradigm (Reference Counting)

The `Delete` operation on the base instance endpoint (`DELETE /instances/{type}/{instance-uuid}`) functions as a removal from the *current* Context (triggering local `remove` propagation constraints). The instance is physically destroyed (Garbage Collected) only when removed from its very last Context. When the exact `(type, instance-uuid)` key exists but the instance is not present in the token Context, the requested state already holds: the operation is a no-op that returns `200 OK` with an empty Operation Envelope, exactly as an `Add to Context` of an instance that is already present does, so a `Remove from Current Context` can be repeated safely. It returns `404 Not Found` only when the key does not exist at all. *(A read of the same instance returns `403 Forbidden` instead, because a read asks for an instance that is not available in this Context, while a removal asks for a state that is already in place.)*

The `Remove from Context` operation (`DELETE /instances/{type}/{instance-uuid}/contexts/{context-uuid}`) removes the instance from the Context named in the URL, and with `hierarchical=true` from that Context and all its descendants, atomically. Executed with `hierarchical=true` on a Root Context, it removes the instance from every Context of that tree, so it is deleted unless it is also in a Context under another Root. Executed with `hierarchical=true` on a specific Virtual Organization (VO), it removes the instance from that subtree while allowing it to survive in parallel Contexts. The same reference counting applies: the instance is deleted when it leaves its last Context. `hierarchical=true` and `bypassHierarchyCheck=true` are reserved to `IS-M`, `Infra-M`, and `IS-Admin`, as on `Add to Context`.

Because both operations trigger avalanche effects (via propagation constraints), they support the `dryRun=true` query parameter and the `Prefer: return=representation` header. Following the same "Try-Check-Confirm" pattern, clients can simulate deletion to receive a `200 OK` with the Operation Envelope of all affected instances before committing.

### Additional Constraints

- `hierarchical` is available to every role on read/query operations. On instance writes it is available to `IS-M`, `Infra-M`, `IS-Admin`, `Ctx-M`, and `IS-Editor` according to the endpoint-specific rules; hierarchical `Add to Context` and hierarchical `Remove from Context` are restricted to `IS-M`, `Infra-M`, and `IS-Admin`.
- `List Instance Contexts`: the instance is looked up as by `Read`; `membershipScope=subtree` is the default for every role; `IS-M`, `Infra-M`, and `IS-Admin` may explicitly request `membershipScope=global`. The requested subtree boundary emits no `X-Result-Scope` token.
- **Non-`active` Context behavior:** See the detailed behavior documented in [Context Management](08-api-contexts-and-types.html#operational-notes).

## Admin API — base path `/admin`

This section groups the whole-system maintenance, diagnostics, and destructive operations. These APIs are intentionally segregated under the `/admin` path to allow strict API Gateway and WAF filtering. They are designed for administrative interventions and are restricted to global administrators (`IS-Manager` / `Infrastructure-Manager`).

### Authorization & Token Selection

| Action | HTTP | Path | Query Parameters | IS-M / Infra-M | IS-Admin | Ctx-M | IS-Editor | IS-Contrib | IS-Member |
|--------|------|------|------------------|:--------------:|:--------:|:-----:|:---------:|:----------:|:---------:|
| `Execute Raw Query` | QUERY | `/admin/raw-query` (`POST /admin/raw-query/query` fallback) | `hierarchical`, `metadataPolicy`, `contextsPolicy`, `membershipScope`, `rawResult` | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `System Dump` | GET | `/admin/system/dump` | — | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |
| `System Restore` | POST | `/admin/system/restore` | — | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ |

**Token Scope Rule:**

| Operation Group | Token must be issued for |
|----------------|---------------------------|
| All `/admin/*` operations | Administrative role (`IS-M` / `Infra-M`) is required. `System Dump` and `System Restore` are whole-system operations: the token's Context is irrelevant. |

### HTTP Contract

| Action | Additional Request Headers | Response Headers | Success HTTP Code | Error HTTP Code |
|--------|----------------------------|------------------|-------------------|-----------------|
| `Execute Raw Query` | `Content-Type`, `Accept` | `Content-Type`, `X-Warning`, conditional `X-Result-Scope` / `X-Resolved-Context-Path` | `200 OK` | `400 Bad Request`, `403 Forbidden` |
| `System Dump` | `Accept` (`application/zip`) | `Content-Type` (`application/zip`), `Content-Disposition` (`attachment`) | `200 OK` | `403 Forbidden` |
| `System Restore` | `Content-Type` (`application/zip`) | — | `204 No Content` | `400 Bad Request`, `403 Forbidden`, `409 Conflict` |

### Operational Notes

- **Execute Raw Query:** Body: JSON payload `{"query": "..."}`. ⚠️ NOT for production (OrientDB SQL, backend may change). Should not be used programmatically or implemented in a client library — intended for manual administrative diagnostics only. Only read-only statements are accepted. Any valid read-only OrientDB SQL statement is supported (e.g., `SELECT`, `TRAVERSE`, `MATCH`, `EXPLAIN`). Because the endpoint executes under a read-only database user, metadata/system-class reads and vendor-specific read functions are permitted, whereas destructive operations are inherently rejected at the engine level. The database session is scoped to the token Context; `hierarchical=true` extends its visibility to descendants. With `rawResult=false` (default), element rows are formatted through the Information System model and honour `metadataPolicy`, `contextsPolicy`, and `membershipScope`, while scalar and projection rows have no Information System representation and are therefore preserved in backend-native JSON without being dropped; explicitly requested enrichment parameters are ignored for those rows with `X-Warning`. With `rawResult=true`, every row retains the backend-native JSON shape and field names unmodified. Serialization is all-or-nothing: a row-formatting failure never produces a partial successful result.
- **System Dump:** Produces a complete logical dump of the entire Resource Registry state as a closed seven-entry ZIP archive (`Content-Disposition: attachment; filename="resource-registry-dump.zip"`), independently of the caller's token Context: `manifest.json`, `RegistryMetadata`, every registered Type schema, every Context (live and cemetery alike), every Query Template, and every **Resource** and **IsRelatedTo** instance, each with full metadata and embedded Context membership. **Facet** and **ConsistsOf** instances are not dumped separately — they are embedded within the representation of their owning **Resource** instance, exactly as when reading a **Resource** instance "as-a-whole". Serialization is all-or-nothing: any collection or row serialization failure aborts the download instead of producing a successful incomplete archive. Every entry can be read with `information-system-model` alone: `manifest.json` (a `DumpManifest`) describes the archive — `formatVersion` and `createdAt` — while `registry-metadata.json` (a `RegistryMetadata`) describes the registry the information comes from — `models`, every model by name (`information-system-model`, the domain model, and the runtime model holding the types created through REST, marked `runtime: true`), each with its `version` from the classpath, its `types` (`{ typeName: version }`) and its `revisionCount`, next to the global `revisionCount`.
- **System Restore:** Ingests the exact seven-entry ZIP archive produced by `System Dump` and recreates the entire Resource Registry state in strict topological order: Types, Contexts, Query Templates, **Resource** instances, then **IsRelatedTo** instances, and finally `RegistryMetadata`, kept as dumped except its global `revisionCount`, which stays the target's. Missing, duplicate, unexpected, malformed, incompatible, or referentially invalid archive content is rejected with `400 Bad Request` before any write — incompatible meaning an unsupported `formatVersion`, or an `information-system-model` version in `registry-metadata.json` newer than the target's; every **Resource** and **IsRelatedTo** instance must declare at least one valid Context membership. Referentially invalid means that a reference does not resolve inside the archive (a Context `parent`, without cycles, or an **IsRelatedTo** endpoint); preflight does not verify that an **IsRelatedTo** instance is only in Contexts where both its **Resource** instances are; such an inconsistency fails during the restore, and neither **Resource** is added to a Context to make it hold. A restore reproduces the dumped state exactly: nothing is derived again, and no item is modified by being restored. The content of the archive is not validated again against the constraints a write is checked for (mandatory properties, `min` and `max` bounds, name rules): what the dumped registry held comes back as it was. Every original UUID and every original `metadata` object (creator, creation/last-update timestamps) is preserved verbatim. Every instance comes back in exactly the Contexts the archive records for it. This holds for the **ConsistsOf** and **Facet** instances embedded in a **Resource** too: each carries its own `contexts`, which is restored as it is and never recomputed from the **Resource** through the propagation constraints, so a **Facet** that was in fewer Contexts than its **Resource** comes back in those Contexts only. An archive in which an embedded **ConsistsOf** or **Facet** instance carries no `contexts`, or in which a **ConsistsOf** is in a Context where its **Resource** or its **Facet** is not, is rejected with `400 Bad Request` before any write. Every Context comes back as dumped, with its `state`, `effectiveState`, `path`, `previousPaths`, History and `metadata`; restoring a Context adds no History event. A Context whose `state` is `deleted` is re-created in the cemetery: it has no `parent`, its `path` records where it was, and it is not a Root. An archive is rejected with `400 Bad Request` when a Context lacks `state`, `effectiveState` or `path`, when a cemetery Context declares a `parent` or is declared as one, when more than one live Context has no `parent`, or when an instance declares a membership in a cemetery Context. Requires the target system to be empty (no Context, Query Template, **Resource** instance, or **IsRelatedTo** instance may already exist, and no Type may extend **Resource**, **Facet**, **IsRelatedTo**, **ConsistsOf**, or **`Property`**) — the state immediately after a service startup against an empty database. This is a hard precondition with no override: restoring into an already-populated system is rejected outright (`409 Conflict`), never attempted as a merge. The archive is validated before the target is inspected: an invalid archive returns `400 Bad Request` also when the target is not empty. Archive preflight completes before the first write, but the subsequent restore is not one global transaction: an unexpected persistence failure can leave a partially populated target, which must be recreated before retrying.

### High-Impact Topological Operations Summary

To consolidate the reader's mental model before proceeding to Query Templates, the API provides several powerful mechanisms that can drastically alter the graph structure across multiple boundaries. Because of their significant **high-impact** nature and potential for massive avalanche consequences, it is vital to fully understand their blast radius. To ensure operational comprehension and safety, the following table summarizes these high-impact structural operations and their typical safe use cases:

| Operation Name | Method, Path & Parameters | Blast Radius | Dry-run? | Typical Safe Use |
|---|---|---|:---:|---|
| **Single Context Update** | `PUT /instances/{type}/{instance-uuid}` | **Current Context.** Replaces local topology and overwrites properties globally. | ❌ | Forking a shared element (Local Copy-on-Write) or updating a field globally. |
| **Subtree Synchronization** | `PUT /instances/{type}/{instance-uuid}?sync=existing` | **Shared Subtree.** Descendant Contexts where the instance is already explicitly shared. | ❌ | Safe topological alignment across the hierarchy without forcing inclusion in new Contexts. |
| **Hierarchical Distribution** | `PUT /instances/{type}/{instance-uuid}?sync=tree` | **Current Context + Entire descendant subtree.** | ❌ | Forced blanket replication of a mandatory baseline configuration for all child tenants. |
| **Synchronization of One Context** | `PUT /instances/{type}/{instance-uuid}?sync={context-uuid}` | **Current Context + the named Context.** | ❌ | Aligning one Context to its parent, e.g. bringing the state of a service back to `active` there. |
| **Surgical Add to Context** | `PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?propagationMode=surgical` | **Target Context (Targeted instance only).** What the targeted instance brings with it depends on its type: see [`surgical`](11-api-query-parameters.html#propagationmode-add-to-context), case by case. | ✅ | Manual topology repair or targeted injection of a single node. *(Restricted to IS-M / Infra-M / IS-Admin).* |
| **Shallow Add to Context** | `PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?propagationMode=shallow` | **Target Context + Avalanche** (stops at existing instances). | ✅ | Safe, standard sharing of an instance and its strictly missing dependencies. |
| **Deep Add to Context** | `PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?propagationMode=deep` | **Target Context + Full Transitive Closure Avalanche.** | ✅ | Forced re-evaluation and importation of a deeply interconnected graph. |
| **Cross-Boundary Add** | `PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?bypassHierarchyCheck=true` | **Cross-subtree** (breaks logical tree boundaries). | ✅ | Injecting harvested infrastructure data or migrating cross-tenant instances. *(Restricted to IS-M / Infra-M / IS-Admin).* |
| **Hierarchical Add** | `PUT /instances/{type}/{instance-uuid}/contexts/{new-context-uuid}?hierarchical=true` | **Target Context + Entire descendant subtree.** | ✅ | Forced blanket propagation of an external instance into a specific target subtree. *(Restricted to IS-M / Infra-M / IS-Admin).* |
| **Surgical Removal** | `DELETE /instances/{type}/{instance-uuid}?propagationMode=surgical` | **Current Context (Targeted instance only).** Stops Remove-Propagation. | ✅ | Emergency "undo" facility to eliminate a relation without collateral resource damage. |
| **Standard Removal** | `DELETE /instances/{type}/{instance-uuid}?propagationMode=shallow` | **Current Context + Garbage Collector Avalanche** (for orphans). | ✅ | Standard removal. The instance dies physically only if removed from its final Context. |
| **Hierarchical Removal** | `DELETE /instances/{type}/{instance-uuid}/contexts/{context-uuid}?hierarchical=true` | **Named Context + Entire descendant subtree** (every Context of the tree if the Context is a Root). | ✅ | Decommissioning of a corrupted or obsolete instance from a whole subtree. *(Restricted to IS-M / Infra-M / IS-Admin).* |
| **Cross-Boundary Removal** | `DELETE /instances/{type}/{instance-uuid}/contexts/{context-uuid}?bypassHierarchyCheck=true` | **Cross-subtree** (a Context outside the token subtree, also under another Root). | ✅ | Undoing a Cross-Boundary Add, or removing an instance from another tree. *(Restricted to IS-M / Infra-M / IS-Admin).* |

*(Note: Whole-system maintenance remains under `/admin`; the privileged variants of Add to Context and Remove from Context share the canonical membership endpoint and are gated by role-specific query parameters.)*

## Statistics API — Served by SmartGears

Aggregate figures on the whole registry, public, for the landing page of the service and the
landing page of the IS GUI shown before the login. The Resource Registry gives them as the
statistics of a SmartGears service: SmartGears computes them in the background and serves them,
with the activity of the service, under `/smartgears/` (the contract is in the documentation of
`common-smartgears`, "Activity and Statistics"). Only numbers appear: never a Context path or name,
nor an instance UUID or content. Type names do appear, as the model documentation already
publishes them. Every figure is computed on the IS model alone; the registry does not know the
domain model.

### Authorization & Token Selection

| Action | HTTP | Path | Query Parameters | Caller |
|--------|------|------|------------------|--------|
| `Read Statistics` | GET | `/smartgears/resource-registry/statistics` | — | Anyone: no token is needed |

### HTTP Contract

| Action | Additional Request Headers | Response Headers | Success HTTP Code | Error HTTP Code |
|--------|----------------------------|------------------|-------------------|-----------------|
| `Read Statistics` | `Accept` | `Content-Type`, `Cache-Control` (`public, max-age=300`) | `200 OK` | — |

The path is relative to the root of the container, not to the base path of the service: it is
served by SmartGears, not by the Resource Registry.

### Operational Notes

- **Document.** One field per group; each group has `title`, `description`, `computedAt` (ISO 8601)
  and `figures`, each figure an `id`, a `label` and a `value`, a number or a distribution of numbers
  by name. A group not computed yet has `computedAt` null and no figures.
- **Groups and refresh.** `contexts`, `types` and `queryTemplates` are refreshed every 30 minutes;
  `instances` and `connectivity`, which scan every instance, every 6 hours.
- **Never waiting.** SmartGears computes each group on its own thread once the service is active,
  then at its interval; a request never computes and never waits, and a failed group keeps its
  previous result and is retried a minute later. Two instances of the service compute their figures
  independently: they can differ by what changed between their computations.
- **Depth.** Contexts are counted by depth in the tree, `1` being a Root. In D4Science depth 2 is a
  VO and depth 3 a VRE.

| Group | Figure | Value |
|---|---|---|
| `contexts` | `total` | Contexts, the deleted ones included |
| | `byState` | Contexts per state: `created`, `active`, `suspended`, `deleted` (the cemetery) |
| | `byDepth` | Live Contexts per depth |
| | `maxDepth` | The depth of the deepest live Context |
| | `childrenPerContextAverage`, `childrenPerContextMax` | Per depth, the average and the most live children of a Context at that depth |
| | `createdLast12Months` | Contexts created in the last 12 months, the deleted ones included |
| `types` | `total` | Types of the five base types |
| | `byBaseType`, `abstractByBaseType`, `concreteByBaseType` | Per base type (**Resource**, **Facet**, **IsRelatedTo**, **ConsistsOf**, **`Property`**), its types, the abstract and the concrete ones |
| | `byModel` | The types each model declares, keyed by the model name `RegistryMetadata` records; a model also declares types outside the five base types |
| | `evolved` | Types with more than one version in their changelog |
| `queryTemplates` | `total` | Query Templates |
| | `parameters` | `parametric` (at least one `templateVariables` entry) and `parameterless` |
| | `results` | `projection` (the template contains `_emit`) and `whole instances` |
| `instances` | `byBaseType` | Instances of **Resource**, **Facet**, **IsRelatedTo**, **ConsistsOf** |
| | `topResourceTypes` | The ten **Resource** types with the most instances |
| | `facetsPerResource` | Average number of **Facet** instances of a **Resource** instance |
| | `resourcesPerContextMedian`, `resourcesPerContextMax` | Per depth, the median and the most **Resource** instances in a live Context at that depth |
| | `contextsWithoutInstances` | Live Contexts holding no instance |
| | `updatedLast24Hours`, `updatedLast7Days` | Instances whose `lastUpdateTime` falls in that window |
| | `notUpdatedForAYear` | Instances whose `lastUpdateTime` is more than a year old |
| `connectivity` | `isRelatedToPerResourceAverage`, `isRelatedToPerResourceMedian`, `isRelatedToPerResourceMax` | **IsRelatedTo** instances of a **Resource** instance, in either direction |
| | `resourcesWithoutIsRelatedTo` | Percentage of **Resource** instances with no **IsRelatedTo** instance |
| | `contextsPerResource` | Average number of Contexts a **Resource** instance belongs to |
