What news from AWS re:Invent last week will have the most impact on you?
Amazon Q, an AI chatbot for explaining how AWS works.
Super-fast S3 Express storage.
New Graviton 4 processor instances.
Emily Freeman leaving AWS.
I don't use AWS, so none of this will affect me.
Frontend Development / Open Source

Build Your Own Decentralized Twitter, Part 2: Mitigations

Creating a distributed social media system is all well and good, but how do you address problems like deleted tweets? David Eastman explains.
Dec 3rd, 2022 9:07am by
Featued image for: Build Your Own Decentralized Twitter, Part 2: Mitigations
Image via Shutterstock 

In Part 1 of this series, we created an architecture for a distributed social media system, using a Visual Studio code project and corresponding JSON files. Here is the architecture we created:

Our decentralized architecture

The tweet view platform must fetch tweets from the tweeter’s store, based on permission from the platform’s identity files. The key is that the tweeter owns their tweets completely.

The Visual Studio code project and corresponding JSON files are here. You can follow along with just the JSON. The purpose of the project is to investigate the issues around a system where ownership and control were firmly in the tweeters’ hands (or beaks). We set everything up in the last article, so read that now and then come back so we can knock it all down.

Just as a quick reminder:

  • We use Unix time as both a unique id as well as the time the tweet was made.
  • My replies only lock on to the last tweet — a simplification that saves a lot of code.
  • When playing with the code, don’t forget to change BASEDIRECTORY in JsonServices.cs to match your directory structure.

Name Change

Just as you can on Twitter, you can easily change the name that will be displayed by our tweet view platform without affecting anything else. Alan is tired of his alphabetically convenient username, and decides to change it to “ZoZo” — at least allowing our output format to remain aligned.

He changes his Identity in our example tweet view platform:

Running the TweetDisplay gives us:

Because the identity controls the displayed name, not the tweet, everything is fine. Alan can be known as something different on another similar platform. With this architecture, tweeters have no unique identifying name — uniqueness would imply a central controller. Within each tweet view platform, they do at least have a local id. He is ‘1’ — we assume that Alan does not control that internal identifier.

Now, we have explicitly not given the platform its own identity (because this is not a federation), so with our architecture, there is no way to ensure that Alan is uniquely identified. Good for anonymity, but also useful for trolls.

No More Alan

Now let’s start the more destructive changes. What happens if Alan stops giving permission to display his tweets?

TweetDisplay now shows:

While legal, without Alan’s tweets the first thread is damaged. This is not particularly different to a multiple deletion of individual tweets in Twitter. They at least know that there is no simple way to delete all your tweets at once — and they could add friction to the process if they so wished.

What extra scaffolding could be erected to at least maintain structure? The tweet platform could replace the deleted tweets with a replica of the same id with the content “[deleted by user].” With that, the platform can assert its right to maintain a structure that the user has broken. But it also proves that an act of deletion took place from the tweeter, so could this betray the tweeter in some extreme circumstances?

On further examination, it is really just threads that need this warning — and this is where the structure matters. What we could do as an example mitigation is to add a shadow tweet record when a reply is made to an existing tweet.


Unlike with Twitter, not only is editing trivial in our project, but you could change every tweet you ever posted as quickly as you can a “search and replace” on a document. Of course this provides for a rather large number of legal problems. At least in Twitter, because you have to delete a tweet before you can change it, the thread is immediately broken. But by editing directly in his tweet store, Alan realises that he can placate Elon Musk rapidly:

(Note: in case you hadn’t spotted it, you can’t use an apostrophe in JSON and hence it is escaped in the example above)

Immediately this changes the display, because nothing is triggered by a change of content:

Elon changes to Jack

So without any warning, ‘Elon’ has been replaced by ‘Jack’. This would make our model honest to the user’s intent, but absolutely useless as a journal of record. Again, we can mitigate this with an “[edited]” warning.

More Vandalism

As stated in the earlier article, we use the tweeter’s platform identity to link a name to their tweet. That is the main job of the TweetFrom class.

We can see that it also implements IComparable in order to allow us to use the tweet Time to compare whether a tweet is younger or older. As mentioned in the first article, the Time variable doubles up as a unique id for a tweet as well as defining the timeline.

So to list tweets in order, we just call the Sort method on all the TweetFrom objects:

With this simple model, a malign tweeter could easily adjust the tweet ids in their own store and thus how the tweet appears in the timeline. So again we are forced to ask, can we easily mitigate for this? We can use internal scaffolding to record the Time that the tweet was first seen by the platform, but this is arbitrary since the tweeter could reveal their tweets at any time.


Mitigation: the action of reducing the severity, seriousness, or painfulness of something.

This is exactly what we want to do. We have underlined the weakness of this model, but let’s see how easy it is to address that deletion problem in particular. What we can do is store tweets that have replies, and thus maintain some structure. We don’t have to worry about every tweet, nor content (in fact, we remove this), just the metadata. If you want to see this in code, I’ve used the branch mitigation in the project’s Github entry.

The main change in the code is the addition of a new Identity, which we use to store the mitigation tweets. We have also made use of the SortedDictionary so we can mix in our mitigation tweets if they disappear from the graph.

Here is our familiar tweet display:

The difference is that we have saved a set of tweets that have replies to them in our new Mitigations internal identity. You can see above that there are four tweets with replies, and they are stored:

So let’s turn off access to Alan’s tweets (either remove them from his store, or turn off permission in his Identity).

and see the effect:

It is small, but at least you can now see that Beth wasn’t talking to herself. We don’t reveal anything further about the missing tweet, except when it was made. Also, Alan’s tweet at the end of the thread is not replaced as it doesn’t have any replies.

I hope I’ve persuaded you that while ‘complete user control’ is perfectly possible, the resulting mayhem may not be very palatable for the social graph. You might well respond that if the platform is in control, it could also vandalize things — but there are many eyes on that.

In the final article, we will look a bit closer at federation and how that changes things again.

Group Created with Sketch.
THE NEW STACK UPDATE A newsletter digest of the week’s most important stories & analyses.