OverviewFilesCommitsIssuesDocsReleasesPeers

favela-markdown commits / 19e8f06

spec: store the atproto projection — three mechanisms dissolve
Criterion (user): store a projection when the target network commits to its BYTES, derive it when the network merely receives them. atproto commits (the MST holds its CID); AP and every hyper-social bridge-* merely receive. So the cost is 1 canonical + 1 stored projection, not one per network - adding a bridge adds zero files. Derivation is not pure: 300-grapheme truncation depends on the runtime's Unicode tables, so deriving at every sign makes the signed history a function of the runtime. A stored projection is a receipt, not a cache. Closes per-record dialect (#43), grapheme pinning as a consensus hazard, and STRIP_VERSION as an in-band signer gate. The strip leaves the signing path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
19e8f069218955d14263337ae42ac83e8d4a37bf
by plankatron <fleeky@gmail.com> · 2026-09-05T23:12:01.000Z

Changed files (1) +58 -0

spec/record-vocabulary.md +58 -0
……@@ -419,6 +419,64 @@ design does not pretend otherwise.
419419 tracked relationship: one rkey, two collections, cascade on delete and edit.
420420- **It is confined to public posts.** Fediverse-only and local-only posts write one record.
421421
422### 7.1 ★ The criterion — and it is not N×
423
424**Decision (user, 2026-09-05).** The question was never "two records or one", it is **which
425projections are stored at all**:
426
427> **Store a projection when the target network commits to its BYTES. Derive it when the network
428> merely receives them.**
429
430| network | what it does with the projection | stored? |
431|---|---|---|
432| **atproto** | its CID goes in the **signed MST** — the repo *is* the published artifact | **yes** |
433| **ActivityPub** | an AS2 object **delivered** to inboxes; no signature over the body, no content address | no — derived |
434| IRC / Discord / Matrix / email (`hyper-social/bridge-*`) | a message **delivery** | no — derived |
435
436So the cost is **1 canonical + 1 stored projection**, not one per bridged network. Adding a bridge
437adds **zero** files. Measured on wj62's live store: 188 posts today → 376 files after the pivot, not
438eight times that.
439
440The criterion generalises rather than special-casing atproto: a future network that content-addresses
441what it publishes would store too.
442
443### 7.2 Why STORED and not derived on every sign
444
445Derivation is **not** a pure function of the record. Truncation at 300 graphemes (§4.3) needs
446grapheme segmentation, which `markdown-strip.md` §9 leaves unpinned and which depends on **the
447Unicode tables of whatever runtime is executing**. Derive on every sign and:
448
449- two peers on different Node/Bare versions derive different bytes → different CIDs → **a fork**;
450- the same peer after a runtime upgrade re-derives different bytes → **the signed history silently
451 rewrites**. Nobody decided that; it arrives with a package upgrade.
452
453⇒ **A stored projection is a RECEIPT, not a cache.** Once bytes are signed and published they are a
454fact, not a derivation. Re-deriving them later is not reconstruction, it is re-guessing — §8's *"never
455re-encode a record you did not author"*, applied across **time** rather than across authors.
456
457**One choice closes three mechanisms**, all of which existed only to make *repeated derivation* agree:
458
459| closed | it existed because |
460|---|---|
461| per-record `dialect` versioning (hyper-social #43) | a dialect bump re-stripped every record |
462| pinned grapheme segmentation as a **consensus** hazard (`library.md` §10.4) | two runtimes truncate differently |
463| `STRIP_VERSION` as an in-band **signer gate** (`library.md` §10.3) | *"the lease-holder must strip before it encodes"* |
464
465The strip now runs **once, at authoring, on the author's device**, and leaves the signing path
466entirely. A signer materialises the projection from a file and strips nothing.
467
468Re-derivation still happens in exactly three places, and all three are **authored acts**: an edit, a
469deliberate migration of legacy records, and a new bridge building its own projection.
470
471⚠ **Residual, and it is minor.** A user editing from a second device with a different Unicode version
472may truncate differently than the original. That is an authored act, not a fork — surprising, not
473corrupting.
474
475⚠ **The weaker AP variant is accepted, not solved.** Bump the dialect and a server re-fetching
476`/ap/objects/<rkey>` gets different text than it cached. No signature, no content address, and
477Mastodon largely will not refetch without an `Update` carrying `updated`. If it ever matters the fix
478is the same one applied selectively; it is not worth paying for now.
479
422480**What the implementation MUST guarantee:**
423481
4244821. Delete of a canonical record deletes its projection in the same batch. A tombstone for one and