"That's it I'm done, no more blog posts about spaces" is what I told myself when I published my last blog post @dholms.at was right.
But then himself published a great piece on thinking about spaces as a locality and while I think it makes sense I want to talk about 2 particular edges. I'll then wrap them in a trenchcoat and pretend they're a single problem, and maybe a broader problem for atproto... Will it doom the protocol? Probably not but I have another post about what I think atproto is doing right in the mix, so we'll save that discussion for later.
So before we dive in go read Daniel's great blog post:
Reintroducing Spaces
Zooming out and re-motivating the design of spaces, the new primitive for non-public data on atproto.
Then let's talk about edges...
Beyond Space and Time
If we're going to talk about spaces as a locality – and I think it's good framing so we should – then fundamentally most of the issues I've been talking about are ones related to data changing locality over time. I think time is one of the key components that's missing from Daniel's blog post and it's where we get the biggest breakdown. Of course time comes for all things, but when we're talking about feeling atmospheric part of what makes the atmosphere feel refreshing is not thinking on the timescale of platforms but protocols. There are plenty of examples where the timescale of communities outlive the platforms they're on, but I'm going to give an example where the timescale of a locality is 1 week. At, least for this I'm going to give a possible answer.
Nebula First
Anyone who has watched a certain segment of Youtube videos is probably familiar with Nebula First. It is a program where creators post their latest video to the subscription platform Nebula, and only move videos to Youtube when there's something newer on Nebula.
I've been enjoying 's tour of the English Counties which drops new episodes once a week. If I was subscribed to Nebula I could watch his videos a week early.
I've been building a serialized / prerelease / very long form reading platform called Cavu Reader and part of the goal is to find a way to help people monetize their work. So let's imagine we offer a Cavu+ subscription that gets you early access to content a week before it becomes generally available, our Cavu First approach.
Because Cavu is designed for serialized publication, data is generally structured with 1 chapter per-record, all joined up with a publication record that links them together.
Using our locality framing we shouldn't think about who can access our data rather "where is our data" so let's try to apply this framing.
Our Records are in a book?
We can start simple, our records are part of a book, so one book = one space. This works fine for the first week when we give access to books to subscribers. Then once week two rolls around we're in trouble, we can't give readers access to our first segment without giving them access to our next. After all access to a space is either all or nothing.
Our Records are in the pre-release space?
This is a bit of an odd framing, we said locality not who we're sharing it with, but now we've invented a locality that is more about the people in it then anything else. Of course this still fails because records move between pre-release and full-release after a week so the space doesn't stay consistent.
Our Records are part of a Release
This is the framing that actually works. We think of the chapter record, and anything else that we publish with it as a "release" that's a locality that is defined in part by what is in there but just as much by when it occurred. By including the "when" framing we allow our locality to survive over time better since it freezes time in the locality.
Public Spaces?
Of course there is still one problem. Before spaces we had public data, data that was locked open, that meant that anyone, even anonymous users could access the data. Spaces as they're designed can never become public, they always require you to at-least be logged in. Daniel points out that there's certain things we can do with the app view, but as a general rule I want the protocol to enforce the visibility and I'd like to avoid app views that open records up to a wider audience then I've intended them for.
The good news is that I've already (sorta) solved this problem with a custom space host.
Public spaces (https://public.chrispardy.dev/browse) is a space host that doesn't require access credentials to get a space credential. That means that any data under a DID that lists public spaces as it's space host is truly public.
I think this is probably the biggest missing piece in the reference implementation and something that I'm going to work to contribute back. It's the path to making data not just "viewable by anyone logged in" but "viewable by anyone"
But why build a totally new space host implementation and spend all these words talking about locality at all? Why not just move the records? We'll tackle that in the next section.
The Cosmic Ballet
Moving records between spaces, or from spaces to public seems like an appealing option, however you quickly find you need to perform a carefully choreographed dance.
Space Hosts (intentionally) can't give out write credentials, these have to come from the user to whose PDS you're writing. This means we must have each user take action to move data from one space to another, or from a space to public. We could have an app view hold long-lived service credentials but that would have a few limitations.
- 1.
Every user would be required to have authenticated with the app view (rather than with multiple app views)
- 2.
The app view would have needed to request write permissions to the future destination space before the move was requested.
In practice we should assume that moving records is a single user only option.
Let's re-examine our Cavu+ only for 1 week policy, our solution of release spaces was fine, but let's see if we can simplify it and just copy a record.
Social Currency
In Cavu+ we've got people who are following, leaving likes, and highlighting passages. We don't want these to be public, otherwise someone could spoil information that non-subscribers don't have. Additionally publicly announcing that you've left a highlight for a subscriber only portion allows subscriber lists to leak.
This leaves us with the simple answer of writing information like likes, comments, and annotations into a space for subscribers only. If we were to then copy the document records from a space into a public repository we would be unable to move these public records with it. In some cases that may be the right call but Cavu+ is a shared revenue model so our social currency turns into real currency. Leave the likes and the comments behind and you leave behind real money.
One possible solution would be to copy over all the data, but into which account? We can't trust that data about a publication in the authors own account is the complete picture. We could potentially write it into the repo that belongs to but this requires other app views to trust us. Wouldn't it be better if we could verify all that social capital with it's original authors?
Who Owns Space?
One of the things I think a lot of people like about atproto is the idea that you control your own data. To quote Paul "Muad'Dib" Atreides "He who can destroy a thing, controls a thing" – So by this logic we control our own data if we can destroy it. With public data that's only partly possible, but we can delete records on our PDS. In spaces similar restrictions apply but importantly we can delete records without the space authority granting us access.
Of course single records are rarely ever useful on their own, and in a social web collections of records rarely ever have a single author. This means that when we think about data we want to imagine it being made up of multiple records from multiple authors. Spaces give us some notion of shared ownership but at a protocol level we don't get any say in the balance of that relationship.
We imagined with Cavu+ that social currency could become real currency, and spaces give us the ability to gate access to content in a way where that conversion is going to become increasingly meaningful.
This all falls under a general umbrella of contributed data. Something the authors of struggled with and ultimately decided to move off the PDS. When you provide one piece of data to a larger system if that data is an important part of the system we cannot simply delete it. There are many cases where we'd like to tip the current balance of ownership so that the record once written to the space becomes owned by the space not owned by the user who wrote it. Ideally this would have the following properties.
- 1.
The record could become anonymous, and a user could deny that they were the one who wrote the record.
- 2.
You could prove someone "didn't" write the record, specifically people who would have incentive to fake records.
- 3.
We could do this with at-most 2 parties involved
I'm not enough of a cryptography wizard to know if this is even possible so let me suggest something simpler.
Signed Copies
Let's assume that we're ok abandoning deniability in some cases, we have it at the protocol level but we can build verification in at the app level using signed content. Additionally we have all the components in place.
- 1.
Public keys can be broadcast via public repos, this allows 3rd parties to cache public keys and maintain a historical mapping of public keys to DIDs
- 2.
Private keys can be stored in private spaces allowing portability.
- 3.
Users can sign records with their private keys including both the content of the record and the uri of the record.
- 4.
Space authorities, or other trusted parties, can publish signatures of records in a space to their own repository.
Once data is signed it can now be copied and we can verify the original author created it without that author's involvement.
The nice part about this scheme is that while it sits above the protocol level it's also something that all apps reading or writing a specific piece of data can do, this lets us build a deniable-by-default, signed-by-design pattern, which is generally preferred to the alternative.
So we've solved all the problems?
Well unfortunately, no. The reality is that copying data and relying on signing data is probably not a widely applicable option. Carefully considered localities of data are probably still better. Copies are viable when they have certain characteristics that matter, and when we've signed all the data we're going to be copying.
In my own projects I'll probably adopt a mix of strategies, the release spaces, some kind of truly public space, and verified records where needed.
The bigger problem won't be solved by protocols but people, and that's helping to build an understanding (and understandable model) of permissions. We're used to data living in walled gardens and walls can be both prison and protection. A lot of people adopted atproto after being traumatized by the prisons and looking at how to build without walls. With spaces we're given a whole new type of wall, one that can be protection but never turned into prison. It's going to take a bit of effort to help people understand that and where it's edges may be.