Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 41 additions & 32 deletions FluidCompatibilityConsiderations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,55 @@

## Overview

Fluid Framework is a distributed system where multiple clients collaborate on shared documents in real-time. To understand why we need different types of compatibility, we must first recognize the two fundamental parts of the Fluid software:
Fluid Framework is a distributed system where multiple clients collaborate on shared documents in real-time. To understand why we need different types of compatibility, we must first recognize three fundamental aspects of the Fluid software:

1. **Code**: APIs (public and internal) and Behavior (or logic)
2. **Data**: Ops and Summaries (or snapshots)
1. **Build Time**: What happens during development and build of projects using Fluid. Includes compatibility of package dependencies and TypeScript types.
2. **In Memory**: What happens at runtime in memory. Includes compatibility of runtime behaviors and data structures.
3. **Serialized Data**: Ops and Summaries (or snapshots). Includes anything which leaves the memory of the specific JavaScript context which created it.

The interaction between code and data, combined with Fluid's distributed architecture, creates four distinct dimensions of compatibility that must be carefully managed:
Combined with Fluid's distributed architecture, these aspects create four distinct dimensions of compatibility that must be carefully managed:

```mermaid
flowchart TD
A[Code] --APIs--> B[Public APIs]
B --API stability--> C[API compatibility]
A --API/Behavior--> D[Layered architecture]
D --Interactions between layers--> E[Layer compatibility]

F[Data] --Ops--> G[Multi-client collaboration]
G --Collaboration via ops--> J[Cross-client compatibility]
F --Ops/Snapshots--> I[Persistence]
I --Read saved files--> H[Data-at-rest compatibility]
BuildTime[Build Time] --APIs--> TypeScript
TypeScript --TypeCheck--> PackageCompat[Package Compatibility]

InMemory[In Memory] --External APIs/Behaviors--> CustomerUse[Use by customer]
CustomerUse --Run Application--> PackageCompat
InMemory --Internal APIs/Behaviors--> LayeredArch[Layered architecture]
LayeredArch --Interactions between layers--> LayerCompat[Layer compatibility]

SerializedData[Serialized Data] --Ops--> MultiClient[Multi-client collaboration]
MultiClient --Collaboration via ops--> CrossClientCompat[Cross-client compatibility]
SerializedData --Ops/Snapshots--> Persistence[Persistence]
Persistence --Read saved files--> DataAtRestCompat[Data-at-rest compatibility]
```

### How Code and Data create Compatibility Dimensions
### How These Aspects Create Compatibility Dimensions

**From Code:**

- **API compatibility** arises because applications depend on public APIs that are released across versions (including alpha and beta APIs). Applications need a stable, predictable upgrade path as Fluid releases new package versions.
- **Package compatibility** arises because applications depend on Fluid packages using version ranges which guarantee compatibility according to our [API support levels](./docs/docs/build/releases-and-apitags.mdx#api-support-levels) for both Type compatibility and runtime behavior.
- **Layer compatibility** arises because Fluid's modular design consists of four distinct layers (Driver, Loader, Runtime, and Datastore), each of which can be versioned independently. These layers must interoperate at runtime even when they're at different versions. They interact by calling APIs (mostly internal) on other layers and the signatures and behavior of these APIs must be compatible.

**From Data:**

- **Data-at-rest compatibility** arises because documents (stored as summaries/snapshots) may be dormant for extended periods and then reopened by clients running newer versions of Fluid.
- **Cross-client compatibility** arises because multiple clients collaborating on the same document in real-time by exchanging ops may be running different versions of Fluid during rolling upgrades or version transitions.

This document defines and explains each compatibility type in detail, describing what it means, why it matters, and the scenarios it enables. Understanding these distinctions helps both Fluid Framework maintainers and application developers reason about version compatibility and upgrade strategies.

> **Note:** This document does not specify the policies around what version compatibility matrix and guarantees we provide — it focuses on defining the compatibility types themselves.

## API compatibility
## Package compatibility

API compatibility implies that we cannot break existing APIs within the supported set of versions. For example, if we were to say we support compatibility of public APIs where the major version matches, we can only break them when releasing a major version (with reasonable documentation) but we cannot break them in minor or patch releases.
Package compatibility implies that we cannot break existing APIs within the supported set of versions. For example, if we were to say we support compatibility of public APIs where the major version matches, we can only break them when releasing a major version (with reasonable documentation) but we cannot break them in minor or patch releases.
See [API support levels](./docs/docs/build/releases-and-apitags.mdx#api-support-levels) for the actual guarantees we make.

### Motivation

Application developers need a clear, predictable upgrade path to newer Fluid versions. When API changes occur, documented and well-communicated breaking changes allow teams to plan and execute upgrades with confidence.
This allows users of our packages to use [dependency ranges](https://github.com/npm/node-semver) like "^2.100.0" providing predictable upgrade path to newer Fluid versions, ensuring bug fixes are easy to integrate, and it's clear when breaking changes need to be checked for.

## Layer compatibility

Layer compatibility implies that a single client can have different versions for different compatibility layers we support - Driver, Loader, Runtime and Datastore. For example, Driver is v1.0, Loader is v2.0, Runtime is v3.0 and Datastore is v3.1 on the same client. The APIs at the boundaries of these layers have strict compatibility requirements at _runtime_ (distinct from API compatibility, which is about in-code dependencies), to support the full range of versions that may be calling them from another layer.
Layer compatibility implies that a single client can have different versions for different compatibility layers we support - Driver, Loader, Runtime and Datastore. For example, Driver v1.0, Loader v2.0, Runtime v3.0 and both Datastore v3.1 and v3.2 are used on the same client. Multiple Datastore versions can coexist within a single Runtime because each datastore type may come from a separately-versioned package loaded through the runtime's code-loading registry. The APIs at the boundaries of these layers have strict compatibility requirements at _runtime_ (distinct from package and type compatibility, which are about build-time dependencies), to support the full range of versions that may be calling them from another layer.

The APIs between these layers are often internal, and their implementations involve downcasting, so special mechanisms beyond simple type checking are needed to ensure their compatibility.

### Motivation

Expand All @@ -65,28 +67,35 @@ graph TD
subgraph DataStore[DataStore - version D]
DDSes[DDSes]
end
subgraph DataStore2[DataStore - version E]
DDSes2[DDSes]
end
end
end
FFS[Fluid Service]

Driver --> Loader
Driver --> FFS
Loader --> Runtime
Driver <--> Loader
Driver <--> FFS
Loader <--> Runtime

style Driver fill:#4472c4,stroke:#2f5496,color:#fff
style Loader fill:#548235,stroke:#3d5c28,color:#fff
style Runtime fill:#c55a11,stroke:#a04a0e,color:#fff
style DataStore fill:#5b9bd5,stroke:#4a8bc4,color:#fff
style DataStore2 fill:#5b9bd5,stroke:#4a8bc4,color:#fff
style DDSes fill:#5b9bd5,stroke:#2f5496,color:#fff,stroke-width:1px
style DDSes2 fill:#5b9bd5,stroke:#2f5496,color:#fff,stroke-width:1px
style FFS fill:#7030a0,stroke:#5a2680,color:#fff
```

Arrows depict data flow between components.

This diagram shows different Fluid layers with different versions in a client:

- **Driver layer**: Fluid package version A.
- **Loader layer**: Fluid package version B.
- **Runtime layer**: Fluid package version C.
- **Datastore layer**: Fluid package version D.
- **Datastore layer**: Fluid package version D and E.

## Cross-client compatibility

Expand Down Expand Up @@ -131,11 +140,11 @@ graph LR

FFS[Fluid Service]

Driver1 --> Loader1
Loader1 --> Runtime1
Driver1 <--> Loader1
Loader1 <--> Runtime1

Driver2 --> Loader2
Loader2 --> Runtime2
Driver2 <--> Loader2
Loader2 <--> Runtime2

Client1 --A ops--> FFS
Client2 --B ops--> FFS
Expand Down
Loading