1
Fork 0
mirror of https://codefloe.com/pat-s/zendrite.git synced 2026-11-02 21:16:42 +00:00
[Pull Mirror] An opinionated fork of element-hq/dendrite https://zendrite.pat-s.me
  • Go 99%
  • Shell 0.4%
  • Astro 0.2%
  • JavaScript 0.1%
  • Go Template 0.1%
  • Other 0.1%
Find a file
pat-s 77ce55372c fix(roomserver): recheck rejected events against the repaired state (#566)
Follow-up to #563, #564 and #565.

## Problem

On matrix.devxy.io the state key repair finished (59 events in 7 rooms, 42 memberships and 92 messages accepted in the Codeberg room), but the Codeberg room still holds 94 rejected messages and 13 rejected memberships with state since event NID 700000.
A copy of the room's roomserver rows, run locally, shows three causes.

1. **Partial state resolution.** The message re-check resolved the sender's accepted membership against only the state entries the message's auth needs. State resolution checks the conflicting events' own auth against the partially resolved state, which then has no join rules, so it refused the sender's restricted join and kept their old leave. Example: `@wolftune`'s messages after NID 807849 hold his 2025 leave in the state before them. Resolved over the full state, his join wins.
2. **Pass scope.** A rejected message was re-checked only in the pass that accepted its sender's membership. 807849, whose prev event is the accepted join itself, passes, but was never checked again.
3. **Stale snapshots.** A restricted join authorized by a user whose own join the repair accepted was checked against a snapshot without that join (817139 via `@zwopdrek`, 839725 via `@pepperonijail77`). The same applies to joins that only update a member's profile and cite their own earlier join.

## Changes

- `roomserver/state/state.go`: `StateAfterEventsWith` loads the full state after the given events, adds the given entries, settles keys held more than once with state resolution over the full state, and returns the requested tuples.
- `roomserver/internal/input/input_state_key_repair.go`:
  - `stateBeforeForAuth` builds the state before a rejected event from the full state after its prev events, with the memberships among its accepted auth events added. A later leave or ban of the same user still wins through state resolution.
  - The message re-check considers every rejected timeline event, not only those citing a membership accepted in the same pass; the auth checks decide.
  - The membership re-check takes no repaired events to depend on when called with nil, and then checks every rejected membership.
  - `acceptRecheckedEvents` holds the accept logic the repair and the new pass share.
- `roomserver/internal/input/input_rejected_recheck.go`: `RecheckRejectedEvents` runs at startup after the state key repair, room by room, in one room transaction per room. It accepts what passes, adds accepted memberships that also pass against the current state to it, updates the membership table, announces the memberships as `OutputNewRoomEvent` and the timeline events as `OutputOldRoomEvent` (redactions applied), as the repair does. Progress is recorded per room, and each room with accepted events is logged at warning level.
- `roomserver/storage/{postgres,sqlite3}/rejected_recheck_table.go`, `deltas/20261103120000_rejected_recheck.go`, `shared/rejected_recheck.go`, `interface.go`, `tables/interface.go`: a `roomserver_rejected_recheck` cursor table, a migration that schedules the pass once, and listing the rooms with rejected events that have state. `RoomIDFromNID` is added to `RoomDatabase`.
- `roomserver/internal/api.go`: run the pass between `RepairStateKeys` and `RepairResyncedRooms`.
- `setup/ha`: contract level 20, `surface.txt` and `levels.json` regenerated on PostgreSQL 18. The table is additive, so `upgrade_from` and `rollback_to` stay at 1.
- `roomserver/rejected_recheck_test.go`: a restricted room left in the shape found on matrix.devxy.io: a member's two messages after his accepted rejoin, with his leave in the state stored before them, and a restricted join authorized by a user whose join is missing from the state stored before it, all rejected. After the pass all three must be accepted and the messages announced. A message from a user banned before it, citing her earlier join, must stay rejected.

## Testing

- `go test -tags goolm ./roomserver/... ./setup/ha/... ./federationapi/... ./syncapi/...` passes against SQLite and PostgreSQL 18.
- `TestRecheckRejectedEvents` and `TestRepairStateKeys` pass five runs in a row on both backends.
- Without adding the cited memberships, `TestRecheckRejectedEvents` fails.
- Against a local copy of the Codeberg room's roomserver rows from matrix.devxy.io, the pass took 25 s and accepted 13 memberships and 1337 timeline events; 87 rejected events with state remain (49 messages, 6 memberships, the rest other state events). Without the cited memberships it accepts 186 events and no membership. The 13 memberships are 2 restricted joins and 11 joins that cite the sender's own earlier accepted join (profile changes), some of them chained.

## Behaviour change

On the first start after upgrading, the roomserver checks the rejected memberships and timeline events of every room once more and accepts those that pass.
On matrix.devxy.io this restores more than a thousand older messages in the Codeberg room and messages of long-time members in other rooms such as the Forgejo room, which appear in the room history, and replies to them load again.
Many of them were rejected because the sender's join was stored as an outlier and never entered the room state; the pass accepts their messages, but does not add such joins to the current state.
Rejected state events other than memberships, outliers and redactions are left alone, and rooms in partial state are skipped.

Reviewed-on: https://codefloe.com/pat-s/zendrite/pulls/566
2026-11-02 19:46:30 +00:00
.crow chore(deps): update codefloe.com/crow-plugins/clone docker tag to v1.2.2 (#550) 2026-10-31 00:43:24 +00:00
.forgejo chore(deps): update cr.codefloe.com/docker.io/thegeeklab/git-sv docker tag to v3.0.6 (#540) 2026-10-24 00:58:11 +00:00
.gitsv ci(commitlint): require a package scope in commit and PR titles (#248) 2026-07-08 14:23:57 +00:00
appservice feat(clientapi): complete spec v1.13 with suspension, room reports and appservice ephemeral data (#531) 2026-10-18 12:55:58 +00:00
build chore(deps): update docker/dockerfile docker tag to v1.28 (#512) 2026-10-09 01:27:56 +00:00
clientapi feat(clientapi): implement MSC4108 QR login rendezvous (MSC4388) (#560) 2026-11-02 18:44:25 +00:00
cmd test(ci): wait for the seeded message in the Dendrite migration test (#463) 2026-10-01 10:04:00 +00:00
federationapi feat(roomserver): implement MSC4284 policy servers (#557) 2026-11-02 14:03:33 +00:00
internal feat(clientapi): implement MSC4108 QR login rendezvous (MSC4388) (#560) 2026-11-02 18:44:25 +00:00
mediaapi feat(clientapi): complete spec v1.12 with account locking and media headers (#530) 2026-10-18 12:02:18 +00:00
relayapi fix: replace deprecated Sentry SetExtra with SetContext for error events 2026-04-01 12:04:05 +00:00
roomserver fix(roomserver): recheck rejected events against the repaired state (#566) 2026-11-02 19:46:30 +00:00
scripts refactor!: rebrand from Dendrite to Zendrite (#68) 2026-02-18 19:21:22 +00:00
setup fix(roomserver): recheck rejected events against the repaired state (#566) 2026-11-02 19:46:30 +00:00
syncapi feat(clientapi): implement MSC4306 thread subscriptions (#562) 2026-11-02 16:30:42 +00:00
test fix(roomserver): merge gap-filled state instead of rewriting the room (#527) 2026-10-17 09:57:14 +00:00
userapi feat(clientapi): implement MSC4108 QR login rendezvous (MSC4388) (#560) 2026-11-02 18:44:25 +00:00
website feat(clientapi): implement MSC4108 QR login rendezvous (MSC4388) (#560) 2026-11-02 18:44:25 +00:00
.commitlintrc.json ci(commitlint): require a package scope in commit and PR titles (#248) 2026-07-08 14:23:57 +00:00
.dockerignore refactor!: rebrand from Dendrite to Zendrite (#68) 2026-02-18 19:21:22 +00:00
.editorconfig chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
.editorconfig-checker.json docs: add Starlight documentation site and clean up stale references (#50) 2026-02-09 00:21:48 +00:00
.gitignore test(ha): qualify failover and split-brain protection under faults (#399) 2026-09-25 06:42:56 +00:00
.golangci.yaml fix(roomserver): avoid RoomID.Domain() panics for version 12 rooms in leave and 3PID invites (#429) 2026-09-29 09:02:06 +00:00
.hadolint.yaml chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
.markdownlint.yaml feat: add vectorized project logo with light/dark mode support (#80) 2026-03-02 15:52:23 +00:00
.pre-commit-config.yaml chore(deps): update pre-commit hook igorshubovych/markdownlint-cli to v0.50.0 (#547) 2026-10-26 04:02:46 +00:00
.prettierignore chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
.prettierrc.json chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
.trivyignore ci(security): ignore the unreachable x/crypto/openpgp advisory (#439) 2026-09-29 13:48:14 +00:00
.yamllint.yaml chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
are-we-synapse-yet.list chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
build-zendritejs.sh refactor!: rebrand from Dendrite to Zendrite (#68) 2026-02-18 19:21:22 +00:00
Dockerfile chore(deps): update docker/dockerfile docker tag to v1.28 (#512) 2026-10-09 01:27:56 +00:00
go.mod chore(deps): update module github.com/altcha-org/altcha-lib-go to v2 (#552) 2026-11-02 12:48:55 +00:00
go.sum chore(deps): update module github.com/altcha-org/altcha-lib-go to v2 (#552) 2026-11-02 12:48:55 +00:00
justfile fix(build): replace obsolete lint bootstrap with pinned hook (#341) 2026-09-09 16:09:21 +00:00
LICENSE Update license file 2024-10-17 17:21:06 +02:00
LICENSE-COMMERCIAL chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
README.md docs(website): add Liberapay badge to README and navbar (#260) 2026-07-23 16:47:44 +00:00
renovate.json fix(renovate): resolve Forgejo artifact action tags (#306) 2026-09-07 17:03:51 +00:00
sytest-blacklist chore: add various linters, format all files 2026-02-06 16:42:37 +01:00
test-zendritejs.sh refactor!: rebrand from Dendrite to Zendrite (#68) 2026-02-18 19:21:22 +00:00
zendrite-sample.yaml feat(clientapi): implement MSC4108 QR login rendezvous (MSC4388) (#560) 2026-11-02 18:44:25 +00:00

Zendrite

Zendrite logo

Zendrite is a second-generation Matrix homeserver written in Go, designed to be efficient, reliable, and scalable.

Liberapay receives

Forked from element-hq/dendrite in February 2026

The existing Dendrite Matrix rooms are used for chatting:

  • #dendrite:matrix.org for general project discussion and support
  • #dendrite-dev:matrix.org for chat about development specifically

Getting Started

See the documentation site for installation, administration, and development guides.

Downloads

The first public release of this fork is v0.15.3.

Migrating from Dendrite

If you are upgrading from an existing Dendrite installation, see the migration guide for details on config, API endpoint, and JetStream changes.

License

Copyright 2017 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2017-2025 New Vector Ltd

This software is dual-licensed by New Vector Ltd (Element):

  1. GNU AGPL v3 (or later); or
  2. A paid-for Element Commercial License (terms may vary).