FEP 070c: Block synchronization across servers

This FEP is provides an optional mechanism for detecting and repairing blocks between accounts across servers, inspired by the Follow Sync FEP.

You certainly move fast @dansup :slight_smile:

Overall I love it - the lack of eventual consistency of block state has concerned me for a while.

One concern is the potential for Blocks to be dropped if there are changes while requesting a paginated collection. The worst case being; the collection is reduced in size, and pagination causes some users who have Blocks in pace to be missed - which the FEP says to consider being an Undo Block.

For syncs being triggered after noticing a digest mismatch, the receiving server can re-compile the digest after receiving the collection, to tell if it was changed during that time (might be worth advising this in the FEP).

But for servers doing a periodic reconciliation, they won’t have that digest to compare to. The issue should be rectified upon the next reconciliation, but I’d be more comfortable if there was a more immediate way to detect this issue. I don’t know the best way to do that though. Servers could attach the block sync digest as a response header? Paginated collections could contain a hash of results in the collection object? Use ETag / If-Match headers?

Thanks, this is a great catch, and you’re right that it’s worse than an eventual consistency issue: a block dropped mid-pagination gets undone, which is the one direction we really can’t afford to get wrong.

I’m working on updating the FEP draft with four changes:

  • The collection now carries its own blockSynchronizationDigest, computed from the same state as the items. That covers periodic reconciliation, which has no header to compare against, and it makes header-triggered and periodic syncs follow the same rules. The header digest is now only a trigger.

  • Removals are now a MUST NOT unless every page was fetched, nothing was discarded, and the items hash to the collection’s digest. Additions are still allowed from any fetch, since an extra block is far less harmful than a missing one. On a mismatch the receiver MAY retry once.

  • A new Pagination section recommends serving the set as a single document (a single peer’s set is usually small), and when paginating, a stable sort with cursor-based pages. Offsets are what cause the skip you described; with cursors, a block that exists for the whole fetch is always returned.

  • The grace period for recently recorded blocks moved from implementation advice into the spec as a RECOMMENDED 10 minutes, to cover a Block activity arriving during a fetch.

On the alternatives: I went with a property in the body over a response header because a lot of fetch helpers only return the JSON body (Pixelfed’s included). I stayed away from ETag / If-Match because each page is its own resource, so using its ETag to mean “collection version” stretches the semantics. ETag with If-None-Match stays as a 304 optimization.

Let me know if this addresses it or if you see gaps!

I updated the FEP based on your feedback, thanks again!

1 Like

[FEP-2677] Ryan Barrett, Identifying the Application Actor, 2024

This FEP has different author: https://codeberg.org/fediverse/fep/src/branch/main/fep/2677/fep-2677.md?display=source#L3

Also, consider referring to FEP-d556 instead. FEP-d556 is also about instance actors but proposes WebFinger as discovery mechanism, while FEP-2677 proposes NodeInfo. FEP-d556 is implemented in Mastodon.

Will update this now!

1 Like

I just finished and shipped the first implementation of this in Pixelfed :partying_face: