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.

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} | hierarchical, metadataPolicy, contextsPolicy, membershipScope | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | | Create / Update | PUT | /instances/{type}/{instance-uuid} | hierarchical, syncExistingHierarchy, 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 | ✅ | ✅ | ⚠️ | ⚠️ | ❌ | ❌ | | 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. | | 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 | | 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 Admin 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, 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). 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 query parameters like syncExistingHierarchy=true or hierarchical=true are 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, 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. 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 (?syncExistingHierarchy=true)

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 ?syncExistingHierarchy=true, 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] ?syncExistingHierarchy=true 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 ?syncExistingHierarchy=true 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, this flag 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 the flag receives 403 Forbidden instead, because authorization is evaluated before applicability; see Parameter Value Handling).

3. Hierarchical Distribution (?hierarchical=true)

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, hierarchical=true 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 syncExistingHierarchy, 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).

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 syncExistingHierarchy, which is logically ignored on creation (emitting an X-Warning header), hierarchical 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).

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): 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). 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 Hierarchical Parameters: Because syncExistingHierarchy and hierarchical exclusively govern the topological distribution of a Resource instance, they have no structural meaning when targeting a Facet, IsRelatedTo, or ConsistsOf instance directly. If a client mistakenly passes these query parameters when mutating these specific types, the system safely ignores them and emits an X-Warning header, for roles allowed to use them (any other role receives 403 Forbidden, since authorization is evaluated first) (e.g., 199 resource-registry "ignored-query-parameters=hierarchical; 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.

Membership Operations (Remove from Current Context / Add to 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 provides two ways to manage an instance’s Context membership:

  1. Single Remove (DELETE): The Remove from Current Context operation (DELETE /instances/{type}/{instance-uuid}) removes it from the token’s Context.

  2. Single 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).

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):

  • 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.

  • Removal from the current Context retains its endpoint-specific role and scope rules; the global hierarchical removal remains a separate /admin operation.

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.

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, both operations (Add to Context, Remove from Current Context) return 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.

Try-Check-Confirm Pattern (dryRun=true)

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.

DELETE vs /admin/ DELETE 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 Admin Remove from Context operation (available exclusively to global admins) uses the admin path DELETE /admin/instances/{type}/{instance-uuid}. When executed with a token representing the Root Context and ?hierarchical=true, it completely annihilates the instance across all Contexts. However, if executed with a token representing a specific Virtual Organization (VO), it performs a surgical hierarchical wipe, removing the instance from that specific subtree while allowing it to survive in parallel Contexts. Because of its destructive nature, this explicit path is strictly reserved for global administrators (IS-Manager, Infrastructure-Manager).

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 is 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.

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 | |——–|——|——|——————|:————–:|:——–:|:—–:|:———:|:———-:|:———:| | Admin Remove from Context | DELETE | /admin/instances/{type}/{instance-uuid} | hierarchical, propagationMode, dryRun, metadataPolicy, contextsPolicy, membershipScope | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | 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. For Admin Remove from Context, the operational token Context dictates the starting root of the subtree the operation applies to (use a root-Context token for true global scope). 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 | |——–|—————————-|——————|——————-|—————–| | Admin 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 | | 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

  • Admin Remove from Context: A standard user DELETE /instances/ removes an instance from a single Context. The admin DELETE /admin/instances/ acts hierarchically when hierarchical=true; with the default hierarchical=false it removes the instance from the token Context only, exactly as Remove from Current Context does, and differs from it only in its path and permitted roles. When the instance exists but is present neither in the token Context nor, with hierarchical=true, in any of its descendants, the requested state already holds and the operation is a no-op that returns 200 OK with an empty Operation Envelope; it returns 404 Not Found only when the (type, instance-uuid) key does not exist. If the admin provides a token for /VO1 and uses ?hierarchical=true, the instance is cleanly wiped from /VO1 and all its VREs, but survives in /VO2. If they provide a Root token, the instance is completely annihilated globally.

  • 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 Context memberships across instances, whose inconsistency fails during the restore. Every original UUID and every original metadata object (creator, creation/last-update timestamps) is preserved verbatim. 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}?syncExistingHierarchy=true | 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}?hierarchical=true | Current Context + Entire descendant subtree. | ❌ | Forced blanket replication of a mandatory baseline configuration for all child tenants. | | 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, 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. | | Admin Hierarchical Wipe | DELETE /admin/instances/{type}/{instance-uuid}?hierarchical=true | Entire descendant subtree (Or global ecosystem if invoked from Root). | ✅ | Brutal global decommissioning of a corrupted or obsolete instance everywhere it exists. (Restricted to IS-M / Infra-M). |

(Note: Whole-system maintenance and global hierarchical removal remain under /admin; privileged Add to Context variants share the canonical membership endpoint and are gated by role-specific query parameters.)