OverviewFilesCommitsIssuesDocsReleasesPeers

favela-markdown commits / 8a92439

spec/record-vocabulary: embeds resolved (3.5), and 1b closed as stale
Embeds: a blob ref is a content hash because a blob is immutable - favela://blob/<oid>, naming the level MANIFEST always. The atproto blob CID is a different hash, resolved at projection time via __blob__/<cid>, exactly as a mention's DID is. Link cards are NOT authored (a consumer's rendering choice does not belong in the author's bytes) and a quote is a link, not new syntax. 1b asked what signs a markdown record; design.md 4 answered it on 08-31 (attested autobase + $oid). Was hyper-social #57 B3, never fixed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
8a924394399ab7f97127cf4570ce363d8993691e
by plankatron <fleeky@gmail.com> · 2026-09-05T23:33:58.000Z

Changed files (1) +55 -8

spec/record-vocabulary.md +55 -8
……@@ -197,6 +197,54 @@ The DID is resolved at **projection** time; with no designated atproto credentia
197197dropped and the text kept, fail-closed. `did:` targets remain accepted as legacy (§8 is
198198forward-only). See `markdown-strip.md` §3.4.
199199
200### 3.5 Embeds — one URI form, and quotes are just links
201
202`markdown-strip.md` §3.5 already settles that `![alt](…)` produces **no text and no facet** and that
203the embed pipeline consumes images separately, in source order. What was open is what the reference
204*is*, and how it maps outward.
205
206**A blob reference is a content hash, because a blob is immutable.** Records are mutable and so are
207addressed by position (§3.1); a blob is not, so it is addressed by its bytes — the same split
208`NAMING.md` §2 makes between keys and names.
209
210```markdown
211![a cat](favela://blob/<oid>)
212```
213
214- **`<oid>`** is the **hyper-overlay** hash, ours. The atproto blob **CID** is a *different hash*
215 (raw codec vs blake2b) and is resolved at **projection** time through the `__blob__/<cid>` pointer,
216 exactly as a mention's DID is resolved at projection time (§3.4). Canonical names ours; the
217 projection resolves theirs.
218- **The oid names the LEVEL MANIFEST, always** — not a level (`SOCIAL-MODEL.md` §6.6.1). A
219 single-level image gets a one-entry manifest of ~100 bytes. Uniform beats conditional: a shape that
220 is *sometimes* a manifest costs every consumer a branch, forever, to save one small file once.
221- **Alt text is already in the markdown** and maps directly: atproto `embed.images[].alt`, AS2
222 `attachment[].name`.
223
224**The three representations:**
225
226| | atproto | ActivityPub |
227|---|---|---|
228| image | `embed.images[]` — `{$type:'blob', ref:{$link:cid}, mimeType, size}` + `alt`, **bsky caps at 4** → `embed-truncated` in `loss[]` | `attachment[]` — `{type:'Document', url, mediaType, name}` |
229| level choice | the bridge **selects** the level nearest its ceiling (§6.6.1) and reports it | same |
230| quote | `embed.record` | a link in `content` (AS2 has no quote) |
231| link card | `embed.external`, **derived by the consumer** | — |
232
233**Two things deliberately have no canonical form:**
234
235- ⛔ **Link cards are not authored.** `embed.external` is a *rendering* choice made by whoever
236 displays a link; inventing a canonical representation would put a consumer's presentation decision
237 into the author's bytes.
238- ⛔ **A quote is a link, not a new syntax.** `[see this](favela://<roomKey>/<collection>/<position>)`
239 is a quote; the bsky projection turns a link to a record into `embed.record`. `recordWithMedia`
240 falls out of having both and needs no rule of its own.
241
242⚠ **Extraction is `parse()`'s job, not `strip()`'s.** The strip is specified to *ignore* images
243(§3.5), so embeds are yielded by the parse alongside `text`/`facets` — there is nothing for the strip
244vectors to cover here.
245
246---
247
200248---
201249
202250## 4. The P2P side is the rich side
……@@ -645,14 +693,13 @@ Honest gaps. This design is not complete until these are closed.
645693 written afterwards. `test/strip-vectors.test.mjs` validates the vectors themselves; no stripper
646694 exists yet.
647695
6481b. **What signs a markdown record.** With the canonical record no longer a DAG-CBOR entry in a
649 signed atproto commit chain (§0), authorship and integrity need their own mechanism — a detached
650 per-record signature, or a native append-only log of `{rkey, contentHash, sig}` that peers
651 replicate. Mutability is not an obstacle: the signature covers the current bytes and is
652 re-issued on edit, exactly as atproto re-signs a commit on edit. **This is the next thing to
653 settle; everything in §9 (read path) hangs off it.**
6542. **Embed/attachment mapping** across three representations (atproto blob refs, AS2 `attachment`,
655 markdown image syntax) is not worked through.
6961b. ~~**What signs a markdown record.**~~ **CLOSED — see `design.md` §4** (was hyper-social #57 B3,
697 stale since 2026-08-31). Nothing new is required: **authorship** is the pointer written into an
698 attestation-gated multi-writer autobase, **integrity** is the pointer's `$oid`, and `ensureLocal`
699 already refuses bytes that mismatch it. No detached per-record signature, no second log. The
700 atproto commit signature stays exactly where it is, as a projection artifact for consumers who
701 cannot see the room.
7022. ~~**Embed/attachment mapping**~~ **CLOSED 2026-09-05 — §3.5 below.**
6567033. ~~**The extension dialect** (§4.1) names candidates but does not pin a set.~~ **CLOSED** —
657704 pinned in `markdown-strip.md` §2.1 (CommonMark 0.31.2 + six named extensions).
6587054. **Community/list URIs** — ~~the URI form for a favela community room~~ **ANSWERED 2026-09-05**