| … | … | @@ -237,9 +237,14 @@ plus resolved target, so facets are *derived from the parse* when projecting (§ |
| 237 | 237 | hand-maintained. |
| 238 | 238 | |
| 239 | 239 | **The one exception: addressing.** Getting a spoiler wrong makes a post render plainly. Getting |
| 240 | | "who can see this" wrong sends it to the wrong people. So `audience` is a **typed field, never |
| 241 | | parsed out of loose text** — a spelling quirk must not be able to change who receives a post. |
| 242 | | Everything else may be casual. |
| 240 | "who can see this" wrong sends it to the wrong people. |
| 241 | |
| 242 | **Revised 2026-09-05 — the answer is now stronger than a typed field.** This section argued that |
| 243 | `audience` must be a typed field, never parsed out of loose text, so that a spelling quirk could not |
| 244 | change who receives a post. Correct about the danger, and superseded by a better fix: **addressing is |
| 245 | not a field at all.** Who can see a record is the **room it was written in**, enforced by |
| 246 | replication. A parse error cannot widen an audience that was never parsed |
| 247 | (`SOCIAL-MODEL.md` §4, `design.md` §5.1). Everything else may be casual. |
| 243 | 248 | |
| 244 | 249 | ### 4.2 The strip — must be specified, not merely implemented |
| 245 | 250 | |
| … | … | @@ -305,7 +310,8 @@ must not conceal it. |
| 305 | 310 | **Not writing a bsky projection means bsky does not INDEX the post. It does not mean the fediverse |
| 306 | 311 | or anyone else cannot read it.** The canonical record still rides the firehose and is fetchable by |
| 307 | 312 | anyone who fronts the DID. This is the same caveat DESIGN §10.2 already makes about local-only |
| 308 | | ("unindexed by bsky, not unreplicated"), and it MUST be surfaced wherever audience is chosen. |
| 313 | ("unindexed by bsky, not unreplicated"), and it MUST be surfaced wherever a **room** is chosen — |
| 314 | which is now the moment addressing is decided. |
| 309 | 315 | |
| 310 | 316 | Composer copy must never imply erasure or privacy. Until encryption lands, the honest phrasing |
| 311 | 317 | remains "community, not secret". |
| … | … | @@ -340,8 +346,8 @@ Which yields the same four combinations, described honestly: |
| 340 | 346 | **Why the framing matters, and why the earlier "four scopes" table was wrong.** Enumerating scopes |
| 341 | 347 | implies a named scope per combination, so adding a third network would mean **eight** scopes and a |
| 342 | 348 | UI listing all of them. Toggles do not: a new network adds **one** toggle and nothing else changes — |
| 343 | | which is the same reason `audience` is a list of URIs rather than a field per protocol (§5.1). The |
| 344 | | combinatorial explosion was hiding in the vocabulary, not in the mechanism. |
| 349 | which is the same reason **`reach` names networks rather than carrying a field per protocol** |
| 350 | (§5.1). The combinatorial explosion was hiding in the vocabulary, not in the mechanism. |
| 345 | 351 | |
| 346 | 352 | It also names the thing correctly for the UI. The question a composer should ask is not "what scope |
| 347 | 353 | is this post" but "who is this for", and the answer is always "me and my peers, plus whoever else I |
| … | … | @@ -362,8 +368,9 @@ concrete gap this design closes: |
| 362 | 368 | *that*. The only such collection today is `net.favela.local.post`, and teaching ap-bridge to |
| 363 | 369 | project it would make local-only posts federate — destroying the single guarantee that scope has. |
| 364 | 370 | |
| 365 | | Both therefore require the record to carry the intent. That is `audience`, and it is the reason this |
| 366 | | document exists. |
| 371 | Both therefore require the record to carry the intent — **which half of it is `reach`**, the |
| 372 | operational field that survives the room model (§5.1). The other half, *who* may see the post, moved |
| 373 | out of the record entirely and became the room. This document exists for that split. |
| 367 | 374 | |
| 368 | 375 | --- |
| 369 | 376 | |
| … | … | @@ -388,7 +395,7 @@ container key mirroring NSID authority: |
| 388 | 395 | ⛔ **Never `$`-prefixed** — `$type`, `$link`, `$bytes` are atproto's reserved space. |
| 389 | 396 | |
| 390 | 397 | **The constraint is narrower than it first appears.** Namespacing only matters when attaching extras |
| 391 | | to *someone else's* lexicon. On `net.favela.post` we own the namespace outright, so bare `audience` |
| 398 | to *someone else's* lexicon. On `net.favela.post` we own the namespace outright, so a bare `reach` |
| 392 | 399 | is correct and cannot collide. |
| 393 | 400 | |
| 394 | 401 | ⛔ **Never hang favela data on `app.bsky.feed.post`.** The projection is bsky's view; anything bsky |
| … | … | @@ -435,8 +442,12 @@ the atproto spec warns about precisely this: *"when deserializing and re-seriali |
| 435 | 442 | fields risk being stripped away."* |
| 436 | 443 | |
| 437 | 444 | **Legacy rule:** an `app.bsky.feed.post` with **no** canonical counterpart at the same rkey is a |
| 438 | | legacy post. It is read as `audience: [Public]`, `source.mediaType: text/plain`, no extensions. It |
| 439 | | renders, federates and threads exactly as it does today. Nothing rewrites it. |
| 445 | legacy post. It is read as living in the author's **public room**, `source.mediaType: text/plain`, |
| 446 | no extensions. It renders, federates and threads exactly as it does today. Nothing rewrites it. |
| 447 | |
| 448 | ⚠ **Revised 2026-09-05.** This previously said a legacy record "is read as `audience: [Public]`". |
| 449 | Under the room model there is no such field to synthesise: a legacy record is resolved *forward* into |
| 450 | the public room, the same attrition rule §8 already applies to everything else. |
| 440 | 451 | |
| 441 | 452 | **Two canonical vocabularies must not coexist indefinitely.** New writes go to `net.favela.post` |
| 442 | 453 | from the cutover. Legacy records age out by attrition and are never converted. The end state is one |
| … | … | @@ -453,7 +464,9 @@ buried. |
| 453 | 464 | |
| 454 | 465 | Affected in favela-web: |
| 455 | 466 | |
| 456 | | - `lib/scopes.js` — `SCOPE_COLLECTION` stops being a scope→collection map; audience replaces it. |
| 467 | - `lib/scopes.js` — `SCOPE_COLLECTION` stops being a scope→collection map. **The room replaces it** |
| 468 | for addressing, and `reach` for which networks; a scope was doing both jobs at once, which is why |
| 469 | it had to be a map in the first place. |
| 457 | 470 | - `lib/appview.js` — ingest folds `net.favela.post` **and** legacy collections, deduplicating by |
| 458 | 471 | rkey with canonical preferred. `INGEST_VERSION` bumps; a full re-index is required. |
| 459 | 472 | - `lib/render.js` — renders `source.content` as markdown when present, falling back to |
| … | … | @@ -463,7 +476,8 @@ Affected in favela-web: |
| 463 | 476 | - `lib/writer.js` — authors canonical + projection. |
| 464 | 477 | |
| 465 | 478 | Affected elsewhere: hpp's sign/materialize path (§7.4), ap-bridge's `POST_COLLECTION` and its |
| 466 | | projection rule (audience-driven rather than collection-driven), atproto-store's `POST_COLLECTIONS`. |
| 479 | projection rule (**room-driven** rather than collection-driven — a public room projects, others do |
| 480 | not), atproto-store's `POST_COLLECTIONS`. |
| 467 | 481 | |
| 468 | 482 | --- |
| 469 | 483 | |
| … | … | @@ -496,7 +510,7 @@ The tell is an inconsistency, not an error: **`getRecord` and `getPosts` reflect |
| 496 | 510 | `getPostThread` does not.** It is described there as *"a specification unique to bsky post"* — an |
| 497 | 511 | application policy, not a protocol limit. |
| 498 | 512 | |
| 499 | | This is the SAME shape as the audience problem (§5), arriving independently: bsky's application |
| 513 | This is the SAME shape as the addressing problem (§5), arriving independently: bsky's application |
| 500 | 514 | constraints became ours because its lexicon is our storage format. |
| 501 | 515 | |
| 502 | 516 | | surface | edit visible? | why | |
| … | … | @@ -581,8 +595,13 @@ Honest gaps. This design is not complete until these are closed. |
| 581 | 595 | markdown image syntax) is not worked through. |
| 582 | 596 | 3. ~~**The extension dialect** (§4.1) names candidates but does not pin a set.~~ **CLOSED** — |
| 583 | 597 | pinned in `markdown-strip.md` §2.1 (CommonMark 0.31.2 + six named extensions). |
| 584 | | 4. **Community/list audience URIs** — the URI form for a favela community room is unspecified. |
| 585 | | 5. **`audience` semantics for replies** — does a reply inherit its parent's audience? Almost |
| 598 | 4. **Community/list URIs** — ~~the URI form for a favela community room~~ **ANSWERED 2026-09-05** |
| 599 | for rooms: `favela://<roomKey>/…` (`interaction.md` §3.4). What a *list* is under the room model |
| 600 | is still unspecified. |
| 601 | 5. ~~**`audience` semantics for replies**~~ **RESOLVED STRUCTURALLY 2026-09-05** — a reply is |
| 602 | written in the room its parent lives in, so it inherits the audience by construction rather than |
| 603 | by a rule that could be forgotten (`design.md` §5.1). Superseded text follows: does a reply |
| 604 | inherit its parent's audience? Almost |
| 586 | 605 | certainly yes, but the failure mode of getting it wrong is publishing to the wrong people. |
| 587 | 606 | 6. **Whether the AP projection should carry `source.mediaType: text/markdown`** and let Mastodon |
| 588 | 607 | render it, or continue sending pre-rendered HTML. Live output currently sends both. |
| … | … | @@ -591,7 +610,8 @@ Honest gaps. This design is not complete until these are closed. |
| 591 | 610 | |
| 592 | 611 | ## 12. What this design does *not* claim |
| 593 | 612 | |
| 594 | | - It does not make `audience` enforceable on atproto. Nothing can. |
| 613 | - It does not make addressing enforceable on atproto. Nothing can — atproto has none, which is why |
| 614 | only a public room projects at all (§5.2). |
| 595 | 615 | - It does not remove the double-write. It bounds it. |
| 596 | 616 | - It does not improve deliverability, availability or performance. It is a vocabulary decision. |
| 597 | 617 | - Its forcing function is thin today: one fediverse follower, one enforcement point. It is |