| … | … | @@ -0,0 +1,186 @@ |
| 1 | # The Social Model |
| 2 | |
| 3 | **Status:** design. Nothing built. |
| 4 | **Date:** 2026-09-05 |
| 5 | **Sits above:** `favela-markdown/spec/` (the record and its projections), `favela-identity/spec/identity.md` |
| 6 | (users and credentials), and every `bridge-*` project. |
| 7 | **Builds on:** `ROOMS-ARE-THE-COMPUTER.md` (rooms as the only data structure), |
| 8 | `SOCIAL-GRAPH-NAVIGATION.md` (graph, not tree), `COMMUNITY-EMERGENCE.md` (privacy through |
| 9 | architecture), `ARCHITECTURE.md` (the fracture principle). |
| 10 | |
| 11 | **Why this document exists.** Bridges translate our social model outward. So the model has to be |
| 12 | *ours*, defined first and on purpose. Twice now a bridge concern has silently become the substrate — |
| 13 | first the record encoding (caught: `favela-markdown/spec/design.md` §1), then the shape of the social |
| 14 | layer itself (not caught until now). This is the correction. |
| 15 | |
| 16 | --- |
| 17 | |
| 18 | ## 1. The diagnosis — each network forces one primitive |
| 19 | |
| 20 | | network | everything is… | what it therefore cannot hold | |
| 21 | |---|---|---| |
| 22 | | **atproto** | a record in *your* repo — public, single-author, globally addressed | chat (bolted on as a central service), communities (lists + feedgens + labelers), any addressing at all | |
| 23 | | **ActivityPub** | an activity sent to an inbox — addressed, push | history, co-owned objects, search | |
| 24 | | **Threads / Instagram** | content in a feed the platform owns | everything not monetisable | |
| 25 | |
| 26 | Each is a projection of social life onto a single primitive, and each one's awkward parts are the |
| 27 | things that primitive cannot express. **Adopting any of them as the substrate imports its ceiling.** |
| 28 | |
| 29 | ## 2. What the substrate actually affords |
| 30 | |
| 31 | Not aspiration — properties Hypercore has and the others do not. |
| 32 | |
| 33 | | affordance | what it makes native | |
| 34 | |---|---| |
| 35 | | append-only log with verifiable history | edit history and "what did this look like then". A *workaround* on atproto (`$orig`/`$hist`); impossible on AP | |
| 36 | | multi-writer autobase, deterministic apply | genuinely **co-authored** records and **co-owned** identities — structurally impossible on both | |
| 37 | | sparse replication | hold a slice of a room; pay for what you read | |
| 38 | | content-addressed bytes | media that outlives its origin host. WhiteWind bakes the PDS hostname into image URLs and breaks on migration | |
| 39 | | swarm topics + presence | liveness as a substrate property. Neither AP nor atproto has presence at all | |
| 40 | | every peer derives its own view | the timeline is a user artifact, not a platform product | |
| 41 | |
| 42 | Any model that does not use these is paying Hypercore's costs without taking its benefits. |
| 43 | |
| 44 | ## 3. The primitives — six, and no more |
| 45 | |
| 46 | 1. **Identity** — a seed, deriving accounts, with attested devices beneath them. |
| 47 | (`favela-identity/spec/identity.md`; the SLIP-48 `accountIndex` is what makes many accounts per |
| 48 | seed a switch rather than a build.) |
| 49 | 2. **Room** — a multi-writer log with membership and roles. The unit of **scope, audience, |
| 50 | governance and history**, all at once. |
| 51 | 3. **Record** — a named, content-addressed document in a room. Markdown is canonical. |
| 52 | 4. **Edge** — a record whose content is a relation. |
| 53 | 5. **Projection** — a pure function from records to a view: a timeline, a notification list, an AS2 |
| 54 | object, an atproto repo. Derived on read, never stored, never replicated. |
| 55 | 6. **Bridge** — a projection plus a courier, holding its own credentials. |
| 56 | |
| 57 | ⛔ **A projection must never constrain the log.** That rule is the whole lesson of §1, and it is |
| 58 | checkable: *if adding a network changes the record, it was done wrong.* |
| 59 | |
| 60 | ## 4. The central move — visibility is a PLACE, not a field |
| 61 | |
| 62 | **You do not mark a post followers-only. You write it in a room whose members are your followers.** |
| 63 | |
| 64 | | the thing | where it is written | |
| 65 | |---|---| |
| 66 | | a public post | your public room | |
| 67 | | a followers-only post | your followers room | |
| 68 | | a DM | a two-member room | |
| 69 | | a community post | that community's room | |
| 70 | | a chat message | a room, read at a different tempo (§6) | |
| 71 | |
| 72 | This is `COMMUNITY-EMERGENCE.md`'s privacy principle applied to authoring: **architecture, not |
| 73 | policy.** A `visibility` field is a promise every projection must remember to honour, and it leaks |
| 74 | the first time one forgets. A room membership is enforced by replication itself. |
| 75 | |
| 76 | ### 4.1 An interaction inherits the audience of what it acts on |
| 77 | |
| 78 | A like on a post is written **in the room where the post lives**. Three things follow, and all of |
| 79 | them are properties we would otherwise have had to build: |
| 80 | |
| 81 | - **It is visible to exactly the people who can see the post.** Not a rule — the only place it could |
| 82 | have been written. |
| 83 | - **You cannot interact with what you cannot see.** There is no room to write in. |
| 84 | - **Write access to a room IS interaction permission.** A public room anyone may write to is an open |
| 85 | comment section; one only its owner writes to is a broadcast feed. **atproto's threadgate and |
| 86 | postgate become room roles**, which keet already has (admin / moderator / peer / read-only). |
| 87 | |
| 88 | This settles the question that hpp answered by inheritance: an interaction is neither globally public |
| 89 | nor privately held — **it has exactly the audience of its subject.** |
| 90 | |
| 91 | ### 4.2 Following is membership; the follow edge is a projection artifact |
| 92 | |
| 93 | To follow someone is to join their public room. To unfollow is to leave. `app.bsky.graph.follow` and |
| 94 | AS2 `Follow` are then **derived at projection time**, exactly as the atproto commit signature is |
| 95 | (`design.md` §4) — artifacts for consumers who cannot see the room. |
| 96 | |
| 97 | ### 4.3 The aggregation attack is bounded by construction |
| 98 | |
| 99 | `COMMUNITY-EMERGENCE.md` names the danger: several peers pooling their local views to reconstruct one |
| 100 | person's full activity. Under a per-identity public repo that reconstruction is trivial, because |
| 101 | everything is in one place by design. Under rooms, a disclosure reaches one room's members and no |
| 102 | further, so the attack is bounded by membership rather than by the absence of a feature. |
| 103 | |
| 104 | ## 5. What a personal feed is |
| 105 | |
| 106 | **A room you own, with one writer.** atproto's repo is exactly that — the degenerate case of this |
| 107 | model, not a different thing. Which is why the atproto projection works at all, and why it can only |
| 108 | ever carry the public room. |
| 109 | |
| 110 | ## 6. Tempo — chat and posts are the same primitive |
| 111 | |
| 112 | A chat message and a post differ in **tempo and retention**, not in kind. Both are records in a room. |
| 113 | This is how realtime integrates later without a new subsystem: keet chat is already an autobase room, |
| 114 | and keet already runs many rooms on **one corestore and one swarm**, per-room autobase keyed by |
| 115 | discovery key — the topology is proven, not hypothetical. |
| 116 | |
| 117 | ⚠ **Tempo is not purely a rendering choice.** Chat wants bounded retention; posts want durability. |
| 118 | That makes retention a **room property**, and it must be in the model rather than discovered later. |
| 119 | This is the one place §3's "six primitives and no more" takes on a modifier. |
| 120 | |
| 121 | ## 7. Translating outward |
| 122 | |
| 123 | Bridges map *our* model onto theirs. The mapping quality is not uniform, and the asymmetry is |
| 124 | structural rather than a matter of effort: |
| 125 | |
| 126 | | target | maps how | why | |
| 127 | |---|---|---| |
| 128 | | **ActivityPub** | well | AP **has addressing**. Room membership → `to`/`cc`; a followers room → the followers collection; a two-member room → a directly addressed Note | |
| 129 | | **atproto** | poorly | atproto has **no addressing at all**. Only public rooms can project; everything else has no representation. `maxReach` becomes structural, not a check | |
| 130 | | **IRC / Matrix / Discord** | naturally | they are room-shaped already — `bridge-*` exists because this was always the closer fit | |
| 131 | | **Threads / Instagram** | barely | a public post is a public post; nothing else survives | |
| 132 | |
| 133 | **This explains an asymmetry we kept rediscovering.** ap-bridge is light and the atproto path is |
| 134 | heavy not because of implementation quality, but because AP's model is nearer to ours. Every time |
| 135 | atproto felt like it was fighting us, this was why. |
| 136 | |
| 137 | ## 8. What this expresses that neither network can |
| 138 | |
| 139 | - a **co-authored** post — several writers, one record |
| 140 | - a post with **verifiable edit history** |
| 141 | - a post scoped to **an arbitrary group**, with no platform to host the group |
| 142 | - a conversation that is **the same object** as a feed |
| 143 | - **presence** |
| 144 | - a community that **owns itself** — membership, moderation and history in one artifact |
| 145 | |
| 146 | These are not features to add later. They are what the substrate already does, once the model stops |
| 147 | imitating a system that cannot do them. |
| 148 | |
| 149 | ## 9. Costs, honestly |
| 150 | |
| 151 | 1. **Rooms multiply autobases.** `ROOMS-ARE-THE-COMPUTER.md`'s answer holds — use keet-core's rooms |
| 152 | rather than hand-rolling, and one corestore + one swarm carries many — but the cost is real and it |
| 153 | is the main argument against this model. |
| 154 | 2. **The atproto projection must GATHER.** With the repo no longer the source, `bridge:bsky` collects |
| 155 | public rooms into a repo instead of reading one. That inverts hpp's shape and is a larger change |
| 156 | than the encoding it accompanies. |
| 157 | 3. **⛔ It contradicts a decision already taken.** `favela-markdown/spec/interaction.md` §3.4 settled |
| 158 | the native URI as `favela://<identity-root>/<collection>/<rkey>`. If the room is the container, a |
| 159 | record's address must name the **room**. For a personal room the key is derivable from the |
| 160 | identity root, so both can hold — but this is **unreconciled** and §3.4 must not be treated as |
| 161 | final until it is (§10 #1). |
| 162 | 4. **Discovery is harder without a global index**, which `AUTO-DISCOVERY.md` and |
| 163 | `ROOMS-ARE-THE-COMPUTER.md` already accept and answer with registry rooms, DM room-shares, DHT |
| 164 | topics and local MI. |
| 165 | 5. **A record's meaning is now context-dependent.** The same bytes in two rooms are two disclosures. |
| 166 | Copying a record between rooms is therefore a **new authorship act**, never a move. |
| 167 | |
| 168 | ## 10. Open |
| 169 | |
| 170 | 1. **Reconcile the URI with rooms** (§9 #3). Blocking for `interaction.md`. |
| 171 | 2. **Retention as a room property** (§6) — what the vocabulary is, and who may set it. |
| 172 | 3. **Cross-room identity of one record.** A post quoted into another room: one record with two |
| 173 | addresses, or two records with an alias edge? The alias mechanism exists (`interaction.md` §3.3). |
| 174 | 4. **Room-per-audience proliferation.** Does every follower subset become a room, and if so who |
| 175 | manages them? This is the model's ergonomic risk and it is not addressed. |
| 176 | 5. **Moderation** — `COMMUNITY-MODERATION.md` is 30KB and has not been read into this model. Room |
| 177 | roles are the mechanism; *"moderation is shared context, not rules"* is the principle; the |
| 178 | connection between them is unwritten. |
| 179 | 6. **Where governance of a public room lives** when its membership is "anyone". |
| 180 | |
| 181 | ## 11. What this does not claim |
| 182 | |
| 183 | - It does not remove the need for atproto compatibility, or make it cheap. |
| 184 | - It does not make `visibility` enforceable once a record has been projected outward. Nothing can. |
| 185 | - It does not settle moderation, discovery ergonomics, or retention. |
| 186 | - It is **not yet reconciled** with `interaction.md` §3.4, and says so (§9 #3). |