Information System Model — Mutations & Avalanches

Multi-Context Mutations

The mechanism that governs Context membership and instance propagation is the propagationConstraint field embedded in every Relation instance. This field defines the “Avalanche Effect”—how the target Entity instance behaves when the source Resource instance (or the Relation instance itself) is added to or removed from a Context.

Strict Downstream Propagation: The “Avalanche Effect” travels strictly forwards along directed Relation instances (from source to target).

  • For Add to Context: When adding a source Resource instance to a target Context, its outgoing Relation instances are added if and only if their constraint is add: propagate. Because a Relation instance cannot exist without its target, the propagate constraint implicitly pulls the target Entity instance into the target Context as well. Conversely, if the constraint is unpropagate, the Relation instance is simply left behind (it is NOT added to the target Context), even if the target Entity instance happens to already exist in that target Context independently. (Note on explicit Relation instance additions: If a client attempts to execute an Add to Context directly on a Relation instance, and its source Resource instance is missing from the target Context, the system will not implicitly pull the source. Instead, the operation strictly fails, enforcing the rule that a Relation instance cannot exist without its source. Conversely, the target Entity instance is always implicitly pulled into the target Context to satisfy the relation’s endpoints, regardless of its add propagation constraint).

  • For Remove from Context: This operation acts on a single Context. When evaluating constraints, the avalanche travels exclusively downstream. If a client removes a Relation instance, its source Resource instance remains completely untouched in that Context. Conversely, if a client removes a Resource instance, the system must drop all incoming Relation instances pointing to it to preserve graph integrity (a Relation instance cannot exist without its target). This drop is a strict topological cleanup, not a backwards avalanche: it does not trigger any remove constraint evaluations on the sources of those incoming Relation instances.

To understand this powerful concept, we will build up the logic through simple didactic examples before demonstrating a comprehensive scenario.

Note: While the following examples illustrate an Add to Context or Remove from Context operation starting from a Resource instance, the exact same rules apply when explicitly adding or removing an IsRelatedTo instance or a ConsistsOf instance. (An operation starting directly on a Facet instance is also possible, but it simply would not trigger any downstream avalanche since Facet instances have no outgoing relations).

Add Propagation

When an instance (e.g., a Resource instance) is added to a new Context (e.g., via an Add to Context operation), the system evaluates the add propagation constraint on all its visible outgoing Relation instances to determine if the target Entity instances (Resource instance or Facet instance) should follow.

Cycle Prevention (Depth-First Search): To prevent infinite traversal loops during propagation avalanches (especially when propagate constraints form closed cycles in complex topologies), the model prescribes a Modified Depth-First Search (DFS) traversal equipped with a Visited Set mechanism. The traversal explores all reachable instances and processes their connecting edges, but safely halts recursion upon encountering an instance that has already been evaluated in the current avalanche (see Complex Topology Scenarios).

Initial State:

The scenario contains the following Resource instances:

  • Resource instance R1 exists in Context C1.

The scenario contains the following Facet instances:

  • Facet instance F1 exists in Context C1.

  • Facet instance F2 exists in Context C1.

The scenario contains the following ConsistsOf instances:

  • R1 is attached to F1 via ConsistsOf instance CO11, which exists in Context C1 and is configured with add: propagate.

  • R1 is attached to F2 via ConsistsOf instance CO12, which exists in Context C1 and is configured with add: unpropagate.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    F1("<b>F1</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2("<b>F2</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R1 -->|"<b>CO11</b> <br/> add: propagate <br/> <sub>[<i>C1</i>]</sub>"| F1
    R1 -->|"<b>CO12</b> <br/> add: unpropagate <br/> <sub>[<i>C1</i>]</sub>"| F2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;
    classDef facet fill:#9bbb59,stroke:#4f6228,stroke-width:3px,color:#fff;

After Add to Context C2: If a user in Context C1 adds R1 into Context C2, CO11 and F1 follow R1 into the new Context, while CO12 and F2 stay behind. The resulting contextual projection of R1 in Context C2 is structurally different from its contextual projection in Context C1. (Note: If the resulting topology in the target Context violates the Resource schema—for example, if an instance of F2’s Type was mandatory, or if the propagation would violate a max cardinality limit—the entire operation strictly fails and is aborted with a validation error! The system does not attempt partial merges or silent replacements; it strictly propagates the eligible elements and validates the final candidate graph).

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"):::resource
    F1("<b>F1</b> <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"):::facet
    F2("<b>F2</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R1 -->|"<b>CO11</b> <br/> add: propagate <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"| F1
    R1 -->|"<b>CO12</b> <br/> add: unpropagate <br/> <sub>[<i>C1</i>]</sub>"| F2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;
    classDef facet fill:#9bbb59,stroke:#4f6228,stroke-width:3px,color:#fff;

Remove Propagation

Visual Disclaimer (Infrastructure Topology Focus): To avoid unreadable diagrams, the following simplified scenarios focus exclusively on the Infrastructure Topology (the graph of Resource instances and IsRelatedTo instances). While omitted from these didactic diagrams to reduce noise, it is strictly understood that every valid Resource instance must encapsulate its own Descriptive Topology (its attached Facet instances).

To understand the difference between cascade, cascadeWhenOrphan, and keep during a removal operation, consider the following scenario strictly contained in Context C1.

Initial State:

The scenario contains the following Resource instances:

  • Resource instance R1 exists in Context C1.

  • Resource instance R2 exists in Context C1.

  • Resource instance R3 exists in Context C1.

  • Resource instance R4 exists in Context C1.

  • Resource instance R5 exists in Context C1.

  • Resource instance R6 exists in Context C1.

The scenario contains the following IsRelatedTo instances:

  • R1 is linked to R2 via IsRelatedTo instance IRT12, which exists in Context C1 and is configured with remove: cascadeWhenOrphan.

  • R1 is linked to R3 via IsRelatedTo instance IRT13, which exists in Context C1 and is configured with remove: cascadeWhenOrphan.

  • R1 is linked to R4 via IsRelatedTo instance IRT14, which exists in Context C1 and is configured with remove: cascade.

  • R1 is linked to R5 via IsRelatedTo instance IRT15, which exists in Context C1 and is configured with remove: keep.

  • R5 is linked to R4 via IsRelatedTo instance IRT54, which exists in Context C1 and is configured with remove: keep.

  • R6 is linked to R2 via IsRelatedTo instance IRT62, which exists in Context C1 and is configured with remove: keep.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R6("<b>R6</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R3("<b>R3</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R4("<b>R4</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R5("<b>R5</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> remove: cascadeWhenOrphan <br/> <sub>[<i>C1</i>]</sub>"| R2
    R1 -->|"<b>IRT13</b> <br/> remove: cascadeWhenOrphan <br/> <sub>[<i>C1</i>]</sub>"| R3
    R1 -->|"<b>IRT14</b> <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| R4
    R1 -->|"<b>IRT15</b> <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R5

    R6 -->|"<b>IRT62</b> <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R2
    R5 -->|"<b>IRT54</b> <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R4

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

After removing R1 from Context C1: When the user explicitly removes R1 from Context C1, the system evaluates the remove constraints on the outgoing IsRelatedTo instances:

  1. On R2 (cascadeWhenOrphan): IRT12 drops. The system checks R2 and sees it still has another incoming IsRelatedTo instance in Context C1 (IRT62 from R6). Therefore, R2 is “saved” and kept in Context C1.

  2. On R3 (cascadeWhenOrphan): IRT13 drops. The system checks R3 and sees it has no other incoming IsRelatedTo instances in Context C1. It is officially an orphan, so R3 is removed from Context C1.

  3. On R4 (cascade): IRT14 drops. The constraint is a pure, strict cascade. The system doesn’t care that the Relation instance IRT54 was still pointing to it; R4 is forcefully removed from Context C1. As a topological consequence, IRT54 also disappears. A Relation instance cannot exist in a Context if either its source or its target is missing: IRT15 died because its source (R1) was removed, whereas IRT54 dies because its target (R4) was removed. (Note on Cycles: Because the avalanche drops Relation instances from the Context as it progresses, any cycle in the graph is naturally broken when the first relation drops, preventing infinite topological loops).

  4. On R5 (keep): IRT15 drops (because the source R1 is gone). The constraint is explicitly keep. The system leaves R5 completely untouched, without even checking if it becomes an orphan. R5 is kept in Context C1.

The resulting topology in Context C1 demonstrates all behaviors at a glance:

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R6("<b>R6</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R5("<b>R5</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource

    R6 -->|"<b>IRT62</b> <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R2
    
    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

Recursive Avalanche

The removal avalanche is a recursive transaction. cascadeWhenOrphan evaluates the final state of the Context after the entire wave of deletions, not just the initial snapshot. Consider this advanced topology:

Initial State:

The scenario contains the following Resource instances:

  • Resource instance R1 exists in Context C1.

  • Resource instance R2 exists in Context C1.

  • Resource instance R3 exists in Context C1.

  • Resource instance R4 exists in Context C1.

The scenario contains the following IsRelatedTo instances:

  • R1 is linked to R2 via IsRelatedTo instance IRT12, which exists in Context C1 and is configured with remove: cascadeWhenOrphan.

  • R1 is linked to R4 via IsRelatedTo instance IRT14, which exists in Context C1 and is configured with remove: cascade.

  • R4 is linked to R2 via IsRelatedTo instance IRT42, which exists in Context C1 and is configured with remove: cascadeWhenOrphan.

  • R4 is linked to R3 via IsRelatedTo instance IRT43, which exists in Context C1 and is configured with remove: keep.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R3("<b>R3</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R4("<b>R4</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> remove: cascadeWhenOrphan"| R2
    R1 -->|"<b>IRT14</b> <br/> remove: cascade"| R4
    R4 -->|"<b>IRT42</b> <br/> remove: cascadeWhenOrphan"| R2
    R4 -->|"<b>IRT43</b> <br/> remove: keep"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

What happens if we remove R1 from Context C1?

  1. R1 is removed. Its outgoing IsRelatedTo instances drop.

  2. IRT14 drops with cascade. R4 is forcefully removed from Context C1.

  3. Because R4 is removed, its outgoing IsRelatedTo instances also drop in the same transaction avalanche!

  4. IRT43 drops. The constraint is keep, so R3 safely remains in Context C1.

  5. Now, look at R2. Both IRT12 and IRT42 drop (both with cascadeWhenOrphan). Because both of its incoming IsRelatedTo instances are destroyed in this single avalanche, R2 becomes a true orphan at the end of the transaction. Thus, R2 is removed from Context C1.

Resulting Graph: Only R3 survives the avalanche.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R3("<b>R3</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

Add and Remove Asymmetry

Removing an instance from a Context is not always the exact inverse of adding it. Invertibility is strictly not guaranteed. The remove constraints dictate what happens to the target Entity instances, and depending on how they are paired with add constraints, applying an Add to Context followed by a Remove from Context (or vice versa) will likely not return the graph to its initial state. (Note: in the following visual examples we primarily illustrate propagation using a Resource instance, but the same mechanics apply when removing a Relation instance, e.g., an IsRelatedTo instance).

Sequence A: Add first, then Remove | Propagation Constraint | Remove: cascade
(or cascadeWhenOrphan when orphan) | Remove: keep
(or cascadeWhenOrphan when not orphan) | |————————|——————————————————————-|———————————————————————–| | Add: propagate | Symmetrical Context Add/Remove | Add expands Context, Remove leaves targets in Context | | Add: unpropagate | Add isolated, Remove cascades to targets | Symmetrical isolated Add/Remove |

Sequence B: Remove first, then Add | Propagation Constraint | Add: propagate | Add: unpropagate | |————————|———————-|————————| | Remove: cascade
(or cascadeWhenOrphan when orphan) | Symmetrical Context Add/Remove | Add isolated, Remove cascades to targets | | Remove: keep
(or cascadeWhenOrphan when not orphan) | Add expands Context, Remove leaves targets in Context | Symmetrical isolated Add/Remove |

To demonstrate this fundamental asymmetry, let’s explore two specular scenarios.

Scenario 1: add: propagate and remove: keep

Suppose we have an IsRelatedTo instance (IRT1) from R1 to R2 configured to propagate on add, but keep on remove.

1. Initial State:

The scenario contains the following Resource instances:

  • Resource instance R1 exists in Context C1.

  • Resource instance R2 exists in Context C1.

The scenario contains the following IsRelatedTo instances:

  • R1 is linked to R2 via IsRelatedTo instance IRT12, which exists in Context C1 and is configured with add: propagate and remove: keep.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

2. After Add (Add R1 to Context C2): Adding R1 to Context C2 triggers the propagate constraint on IRT12. IRT12 and R2 are automatically pulled into Context C2 alongside R1.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"| R2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

3. After Remove (Remove R1 from Context C2): We now remove R1 from Context C2, attempting to revert our action. Because the constraint on IRT12 is keep, R2 is left untouched in Context C2. The final state does not match the initial state.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>, <i>C2</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

Scenario 2: add: unpropagate and remove: cascade

Suppose we have an IsRelatedTo instance (IRT12) configured to NOT propagate on add, but forcefully cascade on remove.

1. Initial State:

The scenario contains the following Resource instances:

  • Resource instance R1 exists in Contexts C1 and C2.

  • Resource instance R2 exists in Contexts C1 and C2.

The scenario contains the following IsRelatedTo instances:

  • R1 is linked to R2 via IsRelatedTo instance IRT12, which exists in Contexts C1 and C2 and is configured with add: unpropagate and remove: cascade.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1, C2</i>]</sub>"| R2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

2. After Remove (Remove R1 from Context C2): Removing R1 from Context C2 triggers the strict cascade on IRT12. IRT12 drops and R2 is forcefully removed from Context C2 as well.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| R2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

3. After Add (Add R1 back to Context C2): We now add R1 back into Context C2, attempting to revert the removal. Because the constraint on IRT12 is unpropagate, R2 does not follow R1 into Context C2. Again, the final state is permanently altered from the initial state.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource

    R1 -->|"<b>IRT12</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| R2

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

Reference Counting

Removing an instance from a Context simply erases its presence from that specific Venn diagram, but it does not necessarily destroy the instance from the global Sea of Nodes of the infrastructure.

However, an instance has no reason to exist if it doesn’t belong to any Context. To prevent the system from filling up with orphaned, invisible instances, the Information System employs a strict Reference Counting paradigm. Whenever an instance is removed from a Context (either explicitly or implicitly via a removal avalanche), its Context presence is decremented. If an instance’s Context count drops to exactly zero (meaning it no longer exists inside any Venn diagram), it faces true global destruction: the system automatically performs a full “Garbage Collection”, physically purging the instance from the graph. (Note on Race Conditions: Because every API operation is executed within an ACID transaction using Optimistic Concurrency Control, if two concurrent operations attempt to remove an instance from its last Contexts simultaneously, the database strictly serializes the final state. The winning transaction safely performs the Garbage Collection, while the losing transaction receives a concurrency error and is rolled back).

Authorization Blast Radius in Avalanches: A common concern is whether a user triggering an avalanche in Context C1 needs explicit permissions in Context C2 if their action indirectly causes an instance to be globally Garbage Collected from Context C2. The answer is no. An administrator operating in Context C1 only drops their own Relation instances in Context C1. They never modify Relation instances in Context C2. If an instance happens to lose its last remaining Context presence (which was Context C1) and is Garbage Collected, it means by definition it was already absent from Context C2. The blast radius of any operation is naturally, mathematically contained within the boundaries of the authorized Context.

To see this in action across multiple Contexts, consider the following scenario involving Resource instances (the exact same garbage collection mechanism applies equally to Facet and Relation instances).

1. Initial State:

  • Resource instance R1 is present across three Contexts: C1, C2, and C3.

  • Resource instance R3 is present across Contexts C1 and C2.

  • Resource instance R2 exists in Context C1.

  • R1 has outgoing IsRelatedTo instances: IRT1 (with remove: cascade) pointing to R2, and IRT2 (with remove: cascade) pointing to R3.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::resource
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    R3("<b>R3</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::resource

    R1 -->|"<b>IRT1</b> <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| R2
    R1 -->|"<b>IRT2</b> <br/> remove: cascade <br/> <sub>[<i>C1, C2</i>]</sub>"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

2. First Remove (Remove R1 from Context C1): A user removes R1 from Context C1. The cascade avalanche evaluates the outgoing IsRelatedTo instances in Context C1:

  • IRT1 drops. R2 is removed from Context C1. Since Context C1 was its only Context, R2 reaches a reference count of 0 and is permanently Garbage Collected.

  • IRT2 drops from Context C1. R3 is removed from Context C1. However, R3 is still present in Context C2, so it safely survives.

  • R1 itself is removed from Context C1. It survives because it still exists in Contexts C2 and C3.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C2, C3</i>]</sub>"):::resource
    R3("<b>R3</b> <br/> <sub>[<i>C2</i>]</sub>"):::resource

    R1 -->|"<b>IRT2</b> <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

3. Second Remove (Remove R1 from Context C2): Later, a user removes R1 from Context C2. The avalanche evaluates the outgoing IsRelatedTo instances in Context C2:

  • IRT2 drops from Context C2. R3 is removed from Context C2. This was its last remaining Context. R3 hits a reference count of 0 and is Garbage Collected.

  • R1 is removed from Context C2. It safely survives because it still exists in Context C3.

Final State: The graph is not empty, but R2 and R3 have been physically destroyed because their respective reference counts dropped to zero. R1 is the only survivor, resting securely in its last remaining Context C3.

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C3</i>]</sub>"):::resource

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;

Comprehensive Scenario

Now that the basic mechanics are clear, we can analyze a complex, real-world topology involving multiple Contexts, differing constraints, and strict schema validation. This scenario demonstrates the full power of the “avalanche effect” combining both Resource instances and multiple Facet instances.

To provide a comprehensive view, we display the Global Topology, showing all instances with their respective Contexts annotated in brackets (e.g., [C1, C2]).

Initial State

The scenario contains the following Resource instances:

  • Resource instance R1 exists in Contexts C1 and C2.

  • Resource instance R2 exists in Context C1.

  • Resource instance R3 exists in Contexts C1 and C2.

  • Resource instance R4 exists in Context C2.

The scenario contains the following Facet instances:

  • Facet instance F1a exists in Contexts C1 and C2.

  • Facet instance F1b exists in Context C1.

  • Facet instance F2a exists in Context C1.

  • Facet instance F2b exists in Context C1.

  • Facet instance F2c exists in Context C1.

  • Facet instance F3a exists in Contexts C1 and C2.

  • Facet instance F3b exists in Context C1.

  • Facet instance F4a exists in Context C2.

  • Facet instance F4b exists in Context C2.

The scenario contains the following ConsistsOf instances:

  • R1 is attached to F1a via ConsistsOf instance CO11a, which exists in Contexts C1 and C2 and is configured with add: propagate and remove: cascade.

  • R1 is attached to F1b via ConsistsOf instance CO11b, which exists in Context C1 and is configured with add: propagate and remove: cascade.

  • R2 is attached to F2a via ConsistsOf instance CO22a, which exists in Context C1 and is configured with add: propagate and remove: cascade.

  • R2 is attached to F2b via ConsistsOf instance CO22b, which exists in Context C1 and is configured with add: unpropagate and remove: cascade.

  • R2 is attached to F2c via ConsistsOf instance CO22c, which exists in Context C1 and is configured with add: propagate and remove: cascade.

  • R3 is attached to F3a via ConsistsOf instance CO33a, which exists in Contexts C1 and C2 and is configured with add: propagate and remove: cascade.

  • R3 is attached to F3b via ConsistsOf instance CO33b, which exists in Context C1 and is configured with add: unpropagate and remove: cascade.

  • R4 is attached to F4a via ConsistsOf instance CO44a, which exists in Context C2 and is configured with add: propagate and remove: cascade.

  • R4 is attached to F4b via ConsistsOf instance CO44b, which exists in Context C2 and is configured with add: unpropagate and remove: cascade.

The scenario contains the following IsRelatedTo instances:

  • R1 is linked to R2 via IsRelatedTo instance IRT12, which exists in Context C1 and is configured with add: propagate and remove: keep.

  • R1 is linked to R3 via IsRelatedTo instance IRT13, which exists in Contexts C1 and C2 and is configured with add: propagate and remove: cascadeWhenOrphan.

  • R4 is linked to R3 via IsRelatedTo instance IRT43, which exists in Context C2 and is configured with add: unpropagate and remove: cascade.

(Note: ConsistsOf instances must implicitly use remove: cascade by definition, as a Facet instance cannot be orphaned without its parent Resource instance).

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::resource
    F1a("<b>F1a</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::facet
    F1b("<b>F1b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    F2a("<b>F2a</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2b("<b>F2b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2c("<b>F2c</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R3("<b>R3</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::resource
    F3a("<b>F3a</b> <br/> <sub>[<i>C1, C2</i>]</sub>"):::facet
    F3b("<b>F3b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R4("<b>R4</b> <br/> <sub>[<i>C2</i>]</sub>"):::resource
    F4a("<b>F4a</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet
    F4b("<b>F4b</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet

    R1 -->|"<b>CO11a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C2</i>]</sub>"| F1a
    R1 -->|"<b>CO11b</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F1b

    R2 -->|"<b>CO22a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2a
    R2 -->|"<b>CO22b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2b
    R2 -->|"<b>CO22c</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2c

    R3 -->|"<b>CO33a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C2</i>]</sub>"| F3a
    R3 -->|"<b>CO33b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F3b

    R4 -->|"<b>CO44a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4a
    R4 -->|"<b>CO44b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4b

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R2
    R1 -->|"<b>IRT13</b> <br/> add: propagate <br/> remove: cascadeWhenOrphan <br/> <sub>[<i>C1, C2</i>]</sub>"| R3
    
    R4 -->|"<b>IRT43</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;
    classDef facet fill:#9bbb59,stroke:#4f6228,stroke-width:3px,color:#fff;

Scenario A: The Add Avalanche

If a manager acting from Context C2 (starting from the Initial State (Pre-Add)) adds R1 into a new Context C3, the avalanche evaluates only the outgoing Relation instances visible from R1 in Context C2. F1b, R2 (and its Facet instances) are completely invisible to this operation.

  • For R1: F1a is propagated. R3 is propagated.

  • For R3 (pulled via R1): Its outgoing ConsistsOf instances in Context C2 are evaluated. F3a is pushed to Context C3 (propagate).

The updated Global Topology shows [C3] added only to F1a, R3, and F3a:

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::resource
    F1a("<b>F1a</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::facet
    F1b("<b>F1b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    
    R2("<b>R2</b> <br/> <sub>[<i>C1</i>]</sub>"):::resource
    F2a("<b>F2a</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2b("<b>F2b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2c("<b>F2c</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R3("<b>R3</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::resource
    F3a("<b>F3a</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::facet
    F3b("<b>F3b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R4("<b>R4</b> <br/> <sub>[<i>C2</i>]</sub>"):::resource
    F4a("<b>F4a</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet
    F4b("<b>F4b</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet

    R1 -->|"<b>CO11a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C2, C3</i>]</sub>"| F1a
    R1 -->|"<b>CO11b</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F1b

    R2 -->|"<b>CO22a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2a
    R2 -->|"<b>CO22b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2b
    R2 -->|"<b>CO22c</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2c

    R3 -->|"<b>CO33a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C2, C3</i>]</sub>"| F3a
    R3 -->|"<b>CO33b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F3b

    R4 -->|"<b>CO44a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4a
    R4 -->|"<b>CO44b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4b

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C1</i>]</sub>"| R2
    R1 -->|"<b>IRT13</b> <br/> add: propagate <br/> remove: cascadeWhenOrphan <br/> <sub>[<i>C1, C2, C3</i>]</sub>"| R3
    
    R4 -->|"<b>IRT43</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;
    classDef facet fill:#9bbb59,stroke:#4f6228,stroke-width:3px,color:#fff;

Scenario B: Alternate Source Context

If, instead of starting from Context C2, the exact same add operation originates from Context C1 (starting from the Initial State (Pre-Add)), the avalanche evaluates the outgoing Relation instances visible only from Context C1:

  • For R1: Both F1a and F1b are pushed to Context C3 (propagate). R2 and R3 are also pushed to Context C3 (propagate).

  • For R2 (pulled via R1): Its outgoing ConsistsOf instances in Context C1 are evaluated. F2a and F2c are pushed to Context C3 (propagate), while F2b is left behind (unpropagate).

  • For R3 (pulled via R1): Its outgoing ConsistsOf instances in Context C1 are evaluated. F3a is pushed to Context C3 (propagate), while F3b is left behind (unpropagate).

  • R4 and its Facet instances are entirely invisible from Context C1 and are unaffected.

The updated Global Topology shows [C3] added to the propagated elements:

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::resource
    F1a("<b>F1a</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::facet
    F1b("<b>F1b</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::facet
    
    R2("<b>R2</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::resource
    F2a("<b>F2a</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::facet
    F2b("<b>F2b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2c("<b>F2c</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::facet

    R3("<b>R3</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::resource
    F3a("<b>F3a</b> <br/> <sub>[<i>C1, C2, C3</i>]</sub>"):::facet
    F3b("<b>F3b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet

    R4("<b>R4</b> <br/> <sub>[<i>C2</i>]</sub>"):::resource
    F4a("<b>F4a</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet
    F4b("<b>F4b</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet

    R1 -->|"<b>CO11a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C2, C3</i>]</sub>"| F1a
    R1 -->|"<b>CO11b</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C3</i>]</sub>"| F1b

    R2 -->|"<b>CO22a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C3</i>]</sub>"| F2a
    R2 -->|"<b>CO22b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2b
    R2 -->|"<b>CO22c</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C3</i>]</sub>"| F2c

    R3 -->|"<b>CO33a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C2, C3</i>]</sub>"| F3a
    R3 -->|"<b>CO33b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F3b

    R4 -->|"<b>CO44a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4a
    R4 -->|"<b>CO44b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4b

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C1, C3</i>]</sub>"| R2
    R1 -->|"<b>IRT13</b> <br/> add: propagate <br/> remove: cascadeWhenOrphan <br/> <sub>[<i>C1, C2, C3</i>]</sub>"| R3
    
    R4 -->|"<b>IRT43</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;
    classDef facet fill:#9bbb59,stroke:#4f6228,stroke-width:3px,color:#fff;

Scenario C: The Remove Avalanche

Starting directly from the state established in Scenario B: Adding R1 from Context C1 to Context C3, the manager now attempts to remove R1 from Context C1. The avalanche evaluates the remove constraints on all outgoing Relation instances visible in Context C1:

  • For R1: It is removed from Context C1. Its outgoing ConsistsOf instances CO11a and CO11b drop (cascade):

    • F1a is removed from Context C1 but survives in Contexts C2, C3.

    • F1b is removed from Context C1. Since it existed in Contexts C1 and C3, its Context presence count drops to 1, so it safely remains in [C3] and is not Garbage Collected. (Note: if it had been exclusively in Context C1, its count would have hit zero and it would be Garbage Collected).

  • On R2: The IsRelatedTo instance IRT12 drops, but its constraint is keep. R2 safely survives in Context C1 (retaining all its Facet instances in Context C1).

  • On R3: The IsRelatedTo instance IRT13 drops, and its constraint is cascadeWhenOrphan. R3 checks for other incoming IsRelatedTo instances in Context C1. Finding none, it is removed from Context C1.

    • Because R3 is removed from Context C1, its Facet instances must also follow the cascade: F3a survives in Contexts C2, C3, but F3b drops to zero Contexts and is permanently Garbage Collected.

The final Global Topology perfectly illustrates how keep, cascadeWhenOrphan, and Facet instance Garbage Collection shape the graph through cascading side effects:

---
config:
  theme: neutral
  flowchart:
    edgeLabelBackground: "#ffffff"
---
graph LR
    R1("<b>R1</b> <br/> <sub>[<i>C2, C3</i>]</sub>"):::resource
    F1a("<b>F1a</b> <br/> <sub>[<i>C2, C3</i>]</sub>"):::facet
    F1b("<b>F1b</b> <br/> <sub>[<i>C3</i>]</sub>"):::facet
    
    R2("<b>R2</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::resource
    F2a("<b>F2a</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::facet
    F2b("<b>F2b</b> <br/> <sub>[<i>C1</i>]</sub>"):::facet
    F2c("<b>F2c</b> <br/> <sub>[<i>C1, C3</i>]</sub>"):::facet

    R3("<b>R3</b> <br/> <sub>[<i>C2, C3</i>]</sub>"):::resource
    F3a("<b>F3a</b> <br/> <sub>[<i>C2, C3</i>]</sub>"):::facet

    R4("<b>R4</b> <br/> <sub>[<i>C2</i>]</sub>"):::resource
    F4a("<b>F4a</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet
    F4b("<b>F4b</b> <br/> <sub>[<i>C2</i>]</sub>"):::facet

    R1 -->|"<b>CO11a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C2, C3</i>]</sub>"| F1a
    R1 -->|"<b>CO11b</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C3</i>]</sub>"| F1b

    R2 -->|"<b>CO22a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C3</i>]</sub>"| F2a
    R2 -->|"<b>CO22b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C1</i>]</sub>"| F2b
    R2 -->|"<b>CO22c</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C1, C3</i>]</sub>"| F2c

    R3 -->|"<b>CO33a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C2, C3</i>]</sub>"| F3a

    R4 -->|"<b>CO44a</b> <br/> add: propagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4a
    R4 -->|"<b>CO44b</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| F4b

    R1 -->|"<b>IRT12</b> <br/> add: propagate <br/> remove: keep <br/> <sub>[<i>C3</i>]</sub>"| R2
    R1 -->|"<b>IRT13</b> <br/> add: propagate <br/> remove: cascadeWhenOrphan <br/> <sub>[<i>C2, C3</i>]</sub>"| R3
    
    R4 -->|"<b>IRT43</b> <br/> add: unpropagate <br/> remove: cascade <br/> <sub>[<i>C2</i>]</sub>"| R3

    classDef resource fill:#4f81bd,stroke:#385d8a,stroke-width:3px,color:#fff;
    linkStyle default stroke:#385d8a,stroke-width:3px;
    classDef facet fill:#9bbb59,stroke:#4f6228,stroke-width:3px,color:#fff;

Advanced Scenarios: The operations detailed above (Scenarios A, B, and C) cover standard tree-like topologies. The model’s behavior becomes significantly more complex when dealing with topological cycles (loops) and diamond patterns (especially in conjunction with cascadeWhenOrphan). To explore how the system guarantees cycle-breaking and safe Garbage Collection in these advanced topologies, refer to Complex Topology Scenarios.

(Note: The complex scenarios documented in the appendix are self-contained and fully understandable without prior knowledge of the REST APIs.)