Travis Ralston 2 weeks ago committed by GitHub
commit 991ecfc3fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,241 @@
# MSC4107: Feature-focused versioning
**Disclaimer**: This MSC is an independent and initial idea which requires significant review and iteration.
Reading material:
* https://spec.matrix.org/v1.9/#specification-versions
* https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientversions
* https://spec.matrix.org/v1.9/client-server-api/#modules
Implementation of a feature in Matrix can span multiple different systems and require multiple different
identifiers. Typically, a feature begins its implementation as an *unstable* feature flag attached to
a particular MSC. As that MSC progresses, the feature flag may change to accommodate sub-versioning of
the proposed feature. When the MSC finally finishes a `merge` FCP, implementations can then use *stable*
identifiers - the ones described in the actual normative sections of the MSC (`m.*`). Typically, clients
require further feature negotiation to determine if they can actually use that feature though, because
it hasn't yet been assigned to a specification version. This leads to *unstable* feature flags to denote
the *stable* state, such as `org.matrix.msc4107.stable`. Some time after that, the stable MSC gets
converted to formal spec, and that spec gets released as an assigned number. Clients are then able to
detect feature support using that specification number.
There are several issues with this approach. Most obviously, clients want to know if they can use
*features*, but the versioning prioritizes specification. Specification is important, however other
mechanics outside the versioning scheme can ensure MSCs are written up as formal spec.
In a related concern, server implementations *often* lag behind the spec release cycle due to the size
and complexity of the spec. The spec itself is very monolithic, and that causes friction when a server
wishes to support a given subset or limited scope, or when a server implementation is trying to get
started and immediately falls behind on client support. Unfortunately, reducing the release cadence
from quartly to biannually does not have an effect of easier releases to implement - the releases just
become chunkier (or don't happen at all because it doesn't feel "worth it" to release).
This proposal explores a feature-focused versioning scheme to prioritize the information needs of clients
over the full specification ideals imposed onto servers.
## Proposal
The [`GET /versions`](https://spec.matrix.org/v1.9/client-server-api/#get_matrixclientversions) endpoint
is modified to add a new `features` key. The existing `unstable_features` and `versions` keys are deprecated.
```json5
{
// New field
"features": {
"msc3440": ["org.matrix.msc3440", "fcp-stable:msc3440", "v1.4", "v1.5", "v1.6"],
"msc1772": ["org.matrix.msc1772"],
"encryption": ["r0.0.0", /* ... */, "v1.9"],
"msc2659": ["fcp-stable:msc2659"],
"core": ["r0.0.0", /* ... */, "v1.9"]
},
// Existing fields - now deprecated
"versions": ["v1.2", "v1.3"],
"unstable_features": {
"org.matrix.msc4107": true
}
}
```
The new `features` key maps a feature ID to array of supported versions by the server. The supported
versions are a combination of unstable feature flags (like `org.matrix.msc4107`), the string `fcp-stable`,
and specification releases. The feature ID is typically the MSC number, though for historical modules
in the Client-Server API some are named features. If a given feature spans multiple MSCs, it is expected
that an MSC to allocate a feature ID is created.
**TODO**: Needing an MSC to create a feature ID is awkward. Can we make it a line of text in the
'foundational' MSC for the feature? (should we always require an architecture/foundation MSC for
large features?)
**TODO**: Assign feature IDs to existing modules where appropriate. There's an assumption that a 'core'
feature ID would be assigned to, well, the core functionality of Matrix. Core would probably encompass
anything not covered by a more specific feature ID, like the ability to send/receive events.
Versions matching the `rX.Y.Z` or `vX.Y` formats are specification releases. If a feature is unchanged
in a given spec release, the array is not required to list it. However, servers may find it easier to
list all supported specification releases in each array.
The string `fcp-stable` is used to denote the time between successful `merge` FCP and specification
release. The string contains a `:` to delineate the string from the MSC number which completed FCP.
This allows for the feature ID to be modified by future MSCs - see the example case below for details.
All other strings not mentioned by this proposal are considered to be unstable feature flags.
Instead of having to detect and estimate the specification version, clients can simply look up the
specific features they need and disable/degrade as appropriate. Servers can then also incrementally
make progress on new spec releases without affecting clients, as one feature might support "latest"
while another is stuck 4 versions behind. In the existing (deprecated) system, a server would be
required to have *both* features fully supported before it could advertise the specification version.
### Example case: Net-new feature
An MSC is opened to describe a new feature such as threads or spaces. That MSC is assigned a number,
in our case MSC4107, and that number becomes the feature ID going forwards.
Implementation then begins on the feature using *unstable* prefixes and feature flags. `/versions`
would look something like:
```json5
{
"features": {
"msc4107": ["org.matrix.msc4107"]
}
}
```
Though rare, sometimes the MSC iterates in a breaking way and needs another unstable feature flag.
This gets implemented, and `/versions` updated to include that flag:
```json5
{
"features": {
"msc4107": ["org.matrix.msc4107", "org.matrix.msc4107.v2"]
}
}
```
Later, the MSC is proposed for `merge` FCP. After sufficient time, the FCP completes, MSC is adopted
into `matrix-spec-proposals` `main` branch, and everyone can start using stable prefixes. The server
implements the stable prefixes, and adds `fcp-stable` to the `/versions`:
```json5
{
"features": {
"msc4107": ["org.matrix.msc4107", "org.matrix.msc4107.v2", "fcp-stable:msc4107"]
}
}
```
Then, the MSC is written up as formal specification and released in v1.10 (in this example). Like the
FCP concluding, the server implements the needed changes (if any), and adds the spec release to `/versions`:
```json5
{
"features": {
"msc4107": [
"org.matrix.msc4107",
"org.matrix.msc4107.v2",
"fcp-stable:msc4107",
"v1.10"
]
}
}
```
At this point, it's advised that the server wait 2 months before dropping the unstable feature flag
versions, but it is not required to. To fully demonstrate the lifecycle here, the example server does
*not* drop the unstable feature support.
Eventually, after 2 spec releases go by, a new MSC is opened to modify the feature. Instead of getting
a whole new feature ID, the existing one is reused. The server implements the unstable feature using
unstable prefixes, and advertises that on `/versions`:
```json5
{
"features": {
"msc4107": [
"org.matrix.msc4107",
"org.matrix.msc4107.v2",
"fcp-stable:msc4107",
"v1.10",
"v1.11", // optional - the feature didn't change in this version, but time did pass
"v1.12", // optional - the feature didn't change in this version, but time did pass
"org.matrix.msc0001",
]
}
}
```
The new MSC then completes its FCP and is formally released in v1.13, which the server dutifully
implements each step of.
```json5
{
"features": {
"msc4107": [
"org.matrix.msc4107",
"org.matrix.msc4107.v2",
"fcp-stable:msc4107",
"v1.10",
"v1.11", // optional - the feature didn't change in this version, but time did pass
"v1.12", // optional - the feature didn't change in this version, but time did pass
"org.matrix.msc0001",
"fcp-stable:msc0001",
"v1.13" // required - the feature changed in this version
]
}
}
```
The server is once again encouraged to drop the unstable feature flags 2 months after the spec release.
This time, the server does that:
```json5
{
"features": {
"msc4107": [
"v1.10",
"v1.11", // optional - the feature didn't change in this version, but time did pass
"v1.12", // optional - the feature didn't change in this version, but time did pass
"v1.13" // required - the feature changed in this version
]
}
}
```
... and that's it. If the second MSC were to change the feature dramatically, it may be best to use
a new feature ID instead. For example, if "threading v2" is completely incompatible with "threading v1",
then a new feature ID would be recommended. The SCT is responsible for determining when/if a new feature
ID should be used.
## Potential issues
This approach could fragment implementation slightly, allowing servers to selectively implement a given
MSC up to the "latest" spec release, but exactly zero other features receive the same treatment. This
situation is how XMPP largely works: implementations are a mix of core functionality and whatever
desirable XEPs are needed. We at Matrix want to avoid this. Though the MSC doesn't go into detail about
it currently, the author's theory is that a `core` feature ID could be assigned to most functions in
the spec, and clients would in practice be checking `core + msc4107` support of the server. This still
encourages the server to keep up to date on the core functionality, and push for complete features as
well.
Another possible way to ensure full compliance with the specification is The Matrix.org Foundation C.I.C.
running a "certification" program to verify a given implementation's level of spec support.
**TODO**: There's probably other issues. They should be documented.
## Alternatives
**TODO**: Reiterate alternatives which are buried in prose above.
## Security considerations
**TODO**: This section
## Unstable prefix
While this proposal is not considered stable, implementations should use `org.matrix.msc4107.features`
on `/versions` instead.
## Dependencies
This proposal has no direct dependencies.
Loading…
Cancel
Save