diff --git a/proposals/4059-mutable-event-content.md b/proposals/4059-mutable-event-content.md new file mode 100644 index 000000000..aeaaab018 --- /dev/null +++ b/proposals/4059-mutable-event-content.md @@ -0,0 +1,132 @@ +# MSC4059: Mutable event content + +[Edits](https://spec.matrix.org/v1.8/client-server-api/#event-replacements) are +used to "replace" an event's contents, and are structured as events themselves. +This can, in some circumstances, cause excessive event traffic which slows down +scrollback. + +This proposal introduces a complimentary feature to edits which allows events to +be partially changed in-place. By editing events in-place, there is no edit +history for clients to use - this can make the feature unhelpful in many cases. + +## Proposal + +**TODO**: Detail. + +Events must self-declare as mutable by *not* providing a content hash over +federation. Events *with* a content hash are considered immutable because the +hash is covered by both the reference hash (event ID) and signatures. + +Mutable events can only change change details which don't affect their reference +hash. For example, the `membership` field of `m.room.member` *cannot* be mutated +because it is part of the redaction algorithm, which then feeds into both the +event's signatures and reference hash. Fields like `displayname` would be +mutable, however. + +A mutation is signed by the sender to help ensure it's not forged by a server. +**TODO**: Involve cross-signing in here? + +Mutations are advertised over federation using EDUs (**TODO**: EDU definition), +indicating to other servers that they need to either re-fetch or apply the +contained change to their copy of the event. Only mutations sent by the original +event sender are permitted/legal - all others are ignored. + +For example, if given an "original event" as follows: + +```jsonc +{ + "type": "m.room.member", + "state_key": "@alice:example.org", + "sender": "@alice:example.org", + "content": { + "membership": "join", + "displayname": "Alice", + "avatar_url": "mxc://example.org/abc123" + }, + "origin_server_ts": 1234567890, + "signatures": { + "example.org": { + "ed25519:abcd": "" + } + }, + "auth_events": [/* ... */], + "prev_events": [/* ... */] + // note lack of `hashes`, indicating mutability +} +``` + +A mutation EDU might be sent out as such: + +```jsonc +{ + "event_id": "$event", + "mutation": { + "displayname": "Alice LastNameHere", // we're changing `content.displayname` + // note lack of `avatar_url` - we're "removing" it + }, + "signatures": { + "@alice:example.org": { + // TODO: Which device(s) sign this? + "ed25519:DEVICEID": "" + } + } +} +``` + +The server then applies that over top of the redactable fields in `content`, +including the sender's signatures for clients to verify (if they want to): + +```jsonc +{ + "type": "m.room.member", + "state_key": "@alice:example.org", + "sender": "@alice:example.org", + "content": { + "membership": "join", + "displayname": "Alice LastNameHere", + "signatures": { + "@alice:example.org": { + "ed25519:DEVICEID": "" + } + } + }, + "origin_server_ts": 1234567890, + "signatures": { + "example.org": { + "ed25519:abcd": "" + } + }, + "auth_events": [/* ... */], + "prev_events": [/* ... */] + // note lack of `hashes`, indicating mutability +} +``` + +## Potential issues + +**TODO**: Detail. + +It's unclear as a server or client if you have the "latest" copy of an event. +This makes the feature useful only when loss is tolerable. A server can always +try to ask the origin for the latest copy of mutable events, but that server +might not be online anymore. Other participating servers might not have the +latest copy either. + +## Alternatives + +**TODO**: Detail. + +Just send edits, or regular state updates!? + +## Security considerations + +**TODO**: Detail. + +## Unstable prefix + +As of writing, it is not intended that implementation begin. Therefore, an +unstable prefix is deliberately not declared. + +## Dependencies + +No direct dependencies.