Skip to content

fix: select state resolution algorithm by room version#231

Merged
sufforest merged 1 commit into
mainfrom
wzy/state-res-by-room-version
Jul 3, 2026
Merged

fix: select state resolution algorithm by room version#231
sufforest merged 1 commit into
mainfrom
wzy/state-res-by-room-version

Conversation

@sufforest

Copy link
Copy Markdown
Owner

state_res::resolve hardcoded the room-version-12 algorithm (state-res v2.1) for every room. vela deliberately supports v6–v11 rooms over federation, so a fork in one of those rooms was resolved with the wrong algorithm and could settle on a different state than Synapse/Dendrite — permanent, non-self-healing state divergence (disagreement on membership/power, undecryptable timelines).

Thread the room version into resolve and branch at the two points where v12 differs from classic state-res v2:

  • Iterative auth checks on power events start from the unconflicted state map in v2, versus empty in v12.
  • The conflicted state subgraph is folded into the full conflicted set in v12 only.

Everything else (both ordering algorithms, the auth rules invoked, the final unconflicted overlay) is identical across versions; the per-version auth-rule differences are already handled inside check_auth.

Also gate the create-event seed to v12, where room_id is the create event's hash. Pre-v12 gets the create event from auth_events (v6–v10) or from the unconflicted map (v11). This fixes a latent bug: before, v11 forks used empty-init, create isn't in a v11 event's auth_events, and the seed can't derive create from an opaque v11 room_id — so the create was absent during resolution and every conflicted event was dropped.

Both call sites (state_before_event, compute_state_at_event) look up the room version and warn! if it can't be resolved rather than silently defaulting a pre-v12 fork to v2.1.

Tests: the uses_state_res_v21 version boundary; a fork where a subgraph-only node resolves under v12 but not v6; and a v11-shaped fork whose topics resolve under v2 (unconflicted-init supplies create) but are dropped under v2.1 (empty-init) — pinning both halves of the branch.

state_res::resolve hardcoded the v12 variant (state-res v2.1) for every
room. vela supports v6-v11 rooms over federation, so a fork in one of
those rooms was resolved with the wrong algorithm and could settle on a
different state than Synapse/Dendrite — permanent state divergence that
doesn't self-heal.

Thread the room version into resolve and branch where v12 differs from
classic state-res v2: the iterative auth checks start from the
unconflicted state map (v2) versus empty (v12), and the conflicted state
subgraph is folded into the full conflicted set (v12 only). Gate the
create-event seed to v12, where the room_id is the create hash; pre-v12
gets create from auth_events (v6-v10) or the unconflicted map (v11), so a
v11 fork no longer loses its create event and drops all conflicted state.

Both call sites look up the room's version and warn if it can't be
resolved rather than silently defaulting a pre-v12 fork to v2.1.
@sufforest sufforest merged commit a899494 into main Jul 3, 2026
11 checks passed
@sufforest sufforest deleted the wzy/state-res-by-room-version branch July 3, 2026 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant