| … | … | @@ -20,14 +20,21 @@ default, not by decision"* — still running in the half nobody specified. |
| 20 | 20 | |
| 21 | 21 | ### 0.1 The frame |
| 22 | 22 | |
| 23 | | There is **one log of named records**, and everything else is a projection of it, derived on read |
| 24 | | and never replicated. |
| 23 | **The ROOM is the container.** Membership is the audience; the log is the history |
| 24 | (`hyper-social/docs/SOCIAL-MODEL.md`). A room is a multi-writer autobase, and everything else is a |
| 25 | projection of its records, derived on read and never replicated. |
| 25 | 26 | |
| 26 | | - **The log** — the shared StateBase autobase: `name -> { $oid, size }`. Names are |
| 27 | | `<collection>/<rkey>`. **Authorship lives here** and nowhere else. |
| 27 | - **A room** — the unit of scope, audience and governance. `<roomKey>` addresses it. |
| 28 | - **The log** — that room's StateBase autobase: `name -> { $oid, size }`, names `<collection>/<rkey>`. |
| 29 | **Authorship lives here** and nowhere else. |
| 28 | 30 | - **The bytes** — content-addressed files in hyper-overlay. A record's content. |
| 29 | | - **A projection** — a pure function from records to some other representation: a timeline, a |
| 30 | | notification list, `app.bsky.feed.like`, an AS2 `Like`. |
| 31 | - **A projection** — a pure function from a room's records to some other representation: a timeline, |
| 32 | a notification list, `app.bsky.feed.like`, an AS2 `Like`. |
| 33 | |
| 34 | ⚠ **Revised 2026-09-05.** This section previously read *"there is one log of named records"* — a |
| 35 | single per-identity log, which is atproto's shape inherited by default. A **personal feed is a room |
| 36 | you own with one writer**, so the per-identity repo is the degenerate case of a room, not the general |
| 37 | container. What follows in this document is written against the room. |
| 31 | 38 | |
| 32 | 39 | ⛔ **A projection must never constrain the log.** ActivityPub never did — it derives on read and |
| 33 | 40 | holds its own key. atproto did: it dictated the encoding, the signing and the storage layout, and |
| … | … | @@ -122,16 +129,26 @@ maintain. Ours are *derived* (§3.1); foreign ones are *asserted* when observed |
| 122 | 129 | **A DID rotation therefore adds an edge; it never rewrites a record.** This is the same mechanism |
| 123 | 130 | that fixes the mention problem in `record-vocabulary.md:166,208`, rather than a special case for it. |
| 124 | 131 | |
| 125 | | ### 3.4 The native URI — `favela://<identity-root>/<collection>/<rkey>` |
| 132 | ### 3.4 The native URI — `favela://<roomKey>/<collection>/<rkey>` |
| 126 | 133 | |
| 127 | 134 | **Decision (user, 2026-09-05).** `at://` is atproto's and `identity.md` §5 has just removed the DID |
| 128 | 135 | from the author position so it can rotate, so a native scheme is required — one favela peer could |
| 129 | 136 | otherwise not name another's record without reintroducing the DID. |
| 130 | 137 | |
| 131 | | **The authority segment is the hex identity root** (`pgh/lib/identity.js:101 identityRootHex`), the |
| 132 | | hyperident/keet root that sits ABOVE both the DID and the device keys. Under the SLIP-48 |
| 133 | | `accountIndex` model each user is a distinct derived key (`keet-identity-key/index.js:227`), so a |
| 134 | | user's identity root IS the global name of the `User` that `identity.md` §5 asks records to carry. |
| 138 | **The authority segment is the ROOM key**, because the room is the container (§0.1) — a record's |
| 139 | address must name where it lives, not who wrote it. Authorship is inside the log, and a record moved |
| 140 | between rooms is a new authorship act, never the same record at a new address |
| 141 | (`SOCIAL-MODEL.md` §9 #5). |
| 142 | |
| 143 | **A personal room's key is derivable from its owner's identity root** (`pgh/lib/identity.js:101 |
| 144 | identityRootHex`) — the hyperident/keet root that sits ABOVE both the DID and the device keys, and |
| 145 | under the SLIP-48 `accountIndex` model each user is a distinct derived key |
| 146 | (`keet-identity-key/index.js:227`). So `favela://<identity-root>/…` survives as the **personal-room |
| 147 | case**, resolving to that room, while a community record names the community's room key. |
| 148 | |
| 149 | ⚠ **Revised 2026-09-05.** An earlier version of this section made the identity root the authority |
| 150 | segment in general. That was written while the per-identity repo was still assumed to be the |
| 151 | container; it is now one case of one. |
| 135 | 152 | |
| 136 | 153 | **A key in the bytes; a name only on screen.** pgh's `NameRegistry` |
| 137 | 154 | (`pgh/lib/name-registry.js:74`) is the resolver for display and discovery — it already anchors |
| … | … | @@ -254,39 +271,31 @@ projections is local-only, which unifies the two ways that is expressible today |
| 254 | 271 | |
| 255 | 272 | --- |
| 256 | 273 | |
| 257 | | ### 4.5 An edge's reach is bounded by its SUBJECT |
| 258 | | |
| 259 | | `maxReach` is a lattice (`library.md` §6.1). An edge sits at the **meet** of two constraints, not |
| 260 | | one: |
| 261 | | |
| 262 | | ``` |
| 263 | | reach(edge) = maxReach(edge.visibility, edge.verb) ∩ maxReach(subject.visibility) |
| 264 | | ``` |
| 274 | ### 4.5 An edge's audience is STRUCTURAL — it is the room it was written in |
| 265 | 275 | |
| 266 | | The second term is the one that is easy to forget and expensive to get wrong. **An edge discloses |
| 267 | | its subject.** Projecting a `like` on a followers-only post to bsky publishes two facts — that the |
| 268 | | post exists, and who engaged with it — even when the like itself was marked public. The subject's |
| 269 | | audience is therefore a ceiling on the edge, exactly as `visibility` is a ceiling on `reach` for a |
| 270 | | post (`design.md` §5.1). |
| 276 | **Revised 2026-09-05.** This section previously computed an edge's reach as the meet of its own |
| 277 | `maxReach` and its subject's. That machinery exists to solve a problem the room removes. |
| 271 | 278 | |
| 272 | | **When the subject's visibility cannot be determined, the meet is `{favela}`.** Fail-closed, the same |
| 273 | | direction as an unparseable frontmatter (`library.md` §6.2) and an unknown verb (§5.2). |
| 279 | **An interaction is written in the room where its subject lives.** Three things follow, none of which |
| 280 | has to be enforced: |
| 274 | 281 | |
| 275 | | Two cases behave differently and both are correct: |
| 282 | - **It is visible to exactly the people who can see the subject.** Not a rule — the only place it |
| 283 | could have been written. |
| 284 | - **You cannot interact with what you cannot see**, because there is no room to write in. |
| 285 | - **Write access to a room IS interaction permission.** atproto's threadgate and postgate become room |
| 286 | roles, which keet already has (admin / moderator / peer / read-only). |
| 276 | 287 | |
| 277 | | - **A foreign subject** (a bsky post, a Mastodon status) is already public on the network it came |
| 278 | | from, so the meet is unrestrictive. This is the common case and it costs nothing. |
| 279 | | - **A favela-native subject with restricted visibility** is where the rule bites, and it is the case |
| 280 | | that does not exist yet — which is precisely why it must be written before it does. |
| 288 | This is `COMMUNITY-EMERGENCE.md`'s privacy principle applied to authoring: **architecture, not |
| 289 | policy.** A computed bound is a promise every projection must remember to honour and leaks the first |
| 290 | time one forgets; a room membership is enforced by replication itself. |
| 281 | 291 | |
| 282 | | `reply` inherits rather than intersects: a reply to a restricted post takes its parent's |
| 283 | | `visibility`, not merely a bound on its reach. `record-vocabulary.md` §11 #5 calls this *"almost |
| 284 | | certainly inherit"* — it is, and the reason to state it explicitly rather than let it emerge is that |
| 285 | | the failure mode is publishing to the wrong people. |
| 292 | `reach` **survives as a field**, because a room cannot express *which networks* a record syndicates |
| 293 | to — that is operational, not audience (`design.md` §5.1). `maxReach` therefore narrows to one job: |
| 294 | refusing a projection a network cannot express, and being total over verbs (§5.2). |
| 286 | 295 | |
| 287 | | ⚠ **Limit, not solved here.** A subject can become *more* restricted after an edge on it was already |
| 288 | | projected. The edge cannot be recalled by the lattice; recalling it is the retraction problem, and |
| 289 | | that is per-bridge delivery bookkeeping (`identity.md` §6.3), not a property of the record. |
| 296 | ⚠ **Limit, not solved here.** A room's membership can shrink after an edge in it was already |
| 297 | projected outward. Recall is per-bridge delivery bookkeeping (`identity.md` §6.3), not a property of |
| 298 | the record. |
| 290 | 299 | |
| 291 | 300 | --- |
| 292 | 301 | |
| … | … | @@ -438,9 +447,9 @@ content one shape, and an inbound edge is the same idea applied to relationships |
| 438 | 447 | 2. ~~**The native URI scheme**~~ **CLOSED 2026-09-05** — `favela://<identity-root>/…`, §3.4. The |
| 439 | 448 | remaining work is the fail-closed minting rule (§3.4.1), not a decision. |
| 440 | 449 | 3. **Inbox admission** (§6) — rate limiting, and how long an unverified claim is retained. |
| 441 | | 4. ~~**Where an edge's `reach` defaults from.**~~ **CLOSED 2026-09-05** — the meet of the edge's own |
| 442 | | maxReach and the subject's, fail-closed to `{favela}` when the subject is unknown; `reply` |
| 443 | | inherits. §4.5. What remains open is *recall* after a subject is restricted later (§4.5 limit). |
| 450 | 4. ~~**Where an edge's `reach` defaults from.**~~ **CLOSED 2026-09-05, then RESOLVED STRUCTURALLY** — |
| 451 | an edge's audience is the room it was written in (§4.5); no computed bound is needed. `reach` (which |
| 452 | networks) remains a field. What remains open is *recall* after a room's membership shrinks. |
| 444 | 453 | 5. **Multi-DID id purity.** `records.js:72` warns the AP id functions stop being pure *"the moment we |
| 445 | 454 | front more than one DID"*, and favela DIDs are co-owned communities. Edges make this sharper, |
| 446 | 455 | because an edge names a subject that may belong to another fronted DID. |