ATProto-native Lexicon definitions for Mezzanine, an information networking system using opaque cashtag connectors on Bluesky.

Mezzanine and Composable Trust #2

open opened by baldemo.to edited

I think Mezzanine has figured out something important. It's possible to make rooms in a public network by creating lenses through which to view it. An opaque identifier, rather than hiding a post, simply makes it easy to scope. People have a "frequency" through which to find each other.

I've been working on a proposal called Composable Trust (https://muses.baldemo.to/3mg6rjnlfws25) that tries to solve a different problem -- specifically, community governance on the AT Protocol. However, I think our two projects can lift each other up to create coherent, protocol-native communities.

Composable Trust has 2 primitives. Rosters issue credentials. These are self-authenticating records signed by the Roster's key. They are irrevocable; to remove someone the Roster publishes a withdrawal record with stated reasoning, which acts as a signal for downstream services. They aren't the space where people hang out, as they simply define who belongs within a community.

Venues are services that scope to a Roster. They decide which credentialed members are welcome in their particular context, and have a final say over what gets surfaced. Venues work from Roster credentials to create a curated space within a community that already has a shared foundation of trust.

For a community to feel real, however, members need a shared space to be in. This does not mean just another feed to scroll. It should feel like a room that you can walk into. Consider:

  • An algorithmic feed scoped to a credential works from a shared trust foundation. However, it isn't intentional. People don't choose to show up there.
  • A topical hashtag-based feed (e.g. #art) is intentional, but it's a topic space, not a social space. People who aren't interested have no reason to be there. (By lacking a shared trust foundation, Mezzanine might default here).

A social space is different. People are there by choice, and float freely within it. Their affinity isn't for a topic, but for each other's very presence.

Mezzanine is how you make rooms in an open network. Combined with Composable Trust, this can turn rooms from topic spaces to true, honest-to-God social spaces for communities.

Consider:

A Venue publishes a policy record declaring its existence. That record has a TID. That TID becomes the Venue's Mezzanine-style identifier. Every post from credentialed members intended for the Venue contains an outline tag with that TID. The client handles the tagging for the user, either by displaying a checkmark to add the tag or simply adding the tag automatically while they're "in" the Venue.

On the user's end, the Roster's page shows Venues as tabs. When you switch into a Venue, the interface shifts into a blank slate. Only posts from credentialed members that carry the Venue's TID are surfaced. The Venue's page acts as a hub. Users can build feeds scoped to the tag, discover other active members in the space, and compose their own experience within it.

Composable Trust provides a shared foundation of trust. Mezzanine provides the rooms where members mingle. The user gets a familiar, tangible social space, built entirely from metadata on public posts.

This is the "open" case. But, of course, some community conversations aren't meant to be public. They aren't secret, but they're private/intended for the community only.

Buckets, as Daniel has described them, don't know about communities. They're just DID-permissioned containers within PDSes. But, what if every member had a bucket whose ACL references the Roster? 'Valid credential + no withdrawal record = access'. This would create a distributed repository for private community content.

This allows for 2 kinds of community posts:

  • Public. Posted to public repos with the Venue's TID as an outline tag. The Mezzanine pattern works as described above. The "room" is an intentional lens over the open network.
  • Permissioned posts: Posted within community buckets with the same TID as an outline tag. Same credential verification and same routing, except the data is only readable by members. The room has real walls now.

Venues may set up a convention, but members can choose at any time whether a post is public or permissioned.

In this architecture, Mezzanine's pattern becomes the routing layer for the full community stack. Whether a post is in a public repo or inside a Bucket, the Venue's TID is ultimately what scopes it. Mezzanine is the connective tissue holding communities together into coherent, general social spaces.

Credentials provide the trust, Venues and Mezzanine provide the room, and Buckets provide the walls. Together, I think they make something we can genuinely call a protocol-native community.

I'd be really curious whether this resonates with where you see Mezzanine going. I think there's something real in how these pieces fit together.

This resonates. Let me respond to the architecture, then push on one point.

Where the pieces fit

Your framing β€” credentials provide trust, Mezzanine provides rooms, buckets provide walls β€” maps correctly onto the layer separation. Mezzanine was designed as a routing layer, not an access control layer. The tag points without signifying. It has no opinion on who gets to read what. That makes it a clean fit as connective tissue across both public repos and permissioned buckets.

The Venue TID as Mezzanine-style identifier works. The tag format needs extension β€” current Mezzanine tags are 3–5 alphanumeric characters, while TIDs are timestamp-based β€” but that is an engineering problem, not a design problem.

The critical point: inside and outside are not two kinds of post

Your proposal frames public and permissioned as two distinct post types. I'd push back on that framing, not the mechanism, but the mental model.

Mezzanine was designed around one core principle: the boundary between inside and outside should be blurred, not hardened. A tag creates a lens, not a wall. People with the right lens see more; people without it still see something. The space is the same. The depth of visibility changes.

This matters because of what I'd call the locked-account failure mode. Twitter/X's locked accounts draw a hard binary: follower or not, visible or not. The problem isn't technical. The boundary works as specified. The failure is that human trust is not binary. Relationships shift. Someone you trusted shares a screenshot. The hard wall, once breached, offers no graceful degradation.

Your design already contains the fix. "They aren't secret, but they're private." That's exactly right. If a community operates with most conversation in public and only some in buckets, a leak from the permissioned layer doesn't collapse the entire space. The public layer is still there. The room survives.

So rather than "two kinds of posts," I'd frame it as a single continuous space with variable depth. The tag is the same. The credential determines how deep you can see. This keeps the architecture identical to what you've proposed β€” the implementation doesn't change β€” but it shifts how users and client developers think about the space they're building.

Prior art: Skyblur

This pattern β€” layering visible and hidden content on the same post β€” already has demand on Bluesky. Skyblur (skyblur.uk) implements a spoiler-text system by storing the unredacted original in a custom collection (uk.skyblur.post) while posting the redacted version publicly. It works, but it's an app-level hack with no protocol-level access control. Anyone who queries the PDS directly can read the original.

What you're proposing with Composable Trust + Mezzanine + buckets is the protocol-native version of what Skyblur does by brute force. That existing demand is worth noting.

Open questions from my side

  1. Roster credential verification at the bucket level: Daniel's Diary 3 leaves access control as an open problem. How does a PDS verify that a requesting app holds a valid Roster credential without introducing a trusted third party?

  2. Tag leakage: if a public post carries a Venue TID, the existence of that Venue (and who's posting to it) is visible to anyone. For some communities that's fine. For others, even the membership signal is sensitive. Is there a design where the tag itself is opaque to non-members?

  3. Withdrawal semantics: you describe credential withdrawal as publishing a record with stated reasoning. How do downstream services (Venues, bucket ACLs) propagate this in practice? Especially for partitioned buckets where each member's PDS independently enforces access.

I think there is something real here. Let's keep building.

Hey! I'm glad this seems to resonate with you. I actually didn't know about Skyblur, so it's good to know that there is demand for this kind of layered visibility.

I also agree on the spectrum point. "One continuous space with variable depth" is a more accurate model. A visitor sees only the public layer, but a member can see the full context-- so if the permissioned layer fails, the credential model yields a failsafe.

With Composable Trust's infrastructure, the governance hierarchy sort of maps onto the depth:

  • Rosters control global access. They publish trust withdrawals. The AppView enforces this by removing the user from the community ACL, revoking Venue access from the user, and no longer serving the user's content within Venues.
  • Venues control local access. A Venue can override a Roster trust withdrawal within its own scope. It can either publish a record that whitelists the user within its scope, or it can exclude a user from scope even if the Roster still trusts them.
  • Members have the final say over their own content. If a user disagrees with a Roster or a Venue's decision, they can block the person in question.

Each of these layers is a trust and governance relationship that can be independently audited and overridden without destroying the others. If a Venue's governance is bad, members can migrate to a new Venue without losing the community. If the Roster's governance is bad, that bad governance can be absorbed at the Venue layer. If that fails, a Roster migration is possible.

As for your three questions:

  1. Credential verification at the bucket level.

Unless the PDS infrastructure is designed to recognize Composable Trust infrastucture, the PDS doesn't verify directly. Rather, the PDS grants bucket access and ACL editing authority to the AppView. The AppView then verifies credentials and serves content to members.

The PDS knows which AppViews are authorized to read and edit the bucket. The community can decide which AppView to trust. The AppView then handles all the credential checking.

This does mean the AppView is a trusted third party for credential verification. Credible exit is still possible, however, and different communities can trust different AppViews. Ultimately, though, it's still a real trust requirement, and I'd argue a necessary one.

For communities where even that trust requirement is too much, I do think a sovereign alternative is possible. Stratos (https://discourse.atprotocol.community/t/proposal-shared-private-data-for-social-posting/459/31) is working on an implementation similar to this. The Roster operator runs the AppView, meaning no external services touches the data.

There's a big tradeoff with this sovereignty, however, in that accountability becomes self-enforced rather than a structural guarantee. A sovereign community can still publish governance records, allow overrides, and maintain a back-pressure loop, in theory. But no external party can check integrity. Self-governance is, well, self-governance in a literal sense. For sensitive communities, this tradeoff is necessary, but it probably shouldn't be the default.

I think this could be supported within a single client, seamlessly switching between the "public" AppView and the community-specific AppView.

  1. Tag leakage

I think there could be a way to design around this. The Venue's policy record, for example, could be published within the community bucket. Venues could declare within that record whether they wish to be public or private. If they're public, the Venue shows up for non-members within the Roster's page, allowing non-members to peek in. If they're private, the AppView does not present the Venue to non-members, i.e. it's inaccessible to the public.

When Venue-scoped public content is published, the client publishes a pointer record in the community bucket. This pointer references the pointee record's TID, and the Venue's policy record TID. Appviews/Venue-scoped feeds read this pointer, and use it to serve the content within the Venue, without public knowledge of this. For private content, the same pattern could follow, except the private record is simply placed in the bucket as well. In both cases, scoping is invisible to the public layer but fully parseable by the community and the AppView. Posts may be public, but the routing remains opaque to outsiders.

  1. Withdrawal propagation

The AppView is the propagation point. When the Roster publishes a withdrawal record:

  • The AppView monitors the Roster's bucket and picks up the withdrawal record
  • The credential check for the withdrawn user fails. The AppView stops serving them community content and stops including their posts in community-scoped feeds.
  • The AppView removes them from the community buckets' ACLs.

For Venue overrides: If a Venue publishes a scope record that keeps a withdrawn user visible in their context, the AppView mediates between the two layers. I think default behavior should be: Roster withdrawals apply globally, but Venue overrides apply within the Venue's scope. Since the user has lost access to the ACL, the Venues that whitelisted the user becomes the only place where private community content is served to them.

[deleted by author]

I also think Mezzanine's pattern could be useful outside a pure Composable Trust application. The same UI patterns that power Venues (tabs, scoped feeds, discovery) could present Mezzanine tags as lightweight, flat topic spaces. Without Rosters, credentials, or Buckets, these spaces would essentially act as well-defined public surfaces for discussion that users could build feeds around. For communities, however, the Roster becomes the obvious next step, as it’s the layer that adds depth, identity, and accountability.

sign up or login to add to the discussion
Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:yzvkvbuv3fdwf2hoywb3tmvy/sh.tangled.repo.issue/3mh5f5b7ynp22