OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-social commits / 8772851

docs: holding and telling — who keeps a copy, and who gets told
Written after an outage on 2026-09-08: tabertron held five pointers from ashatron and could read none of them, because ashatron — a laptop — was the only machine holding the bytes and had gone offline. Nothing was broken. Bytes are fetched only when a reader asks, nobody had asked, so no second copy existed. The document settles two questions that turn out to be one design. WHO HOLDS A COPY. Everything is pull; a fingerprint is a capability, and you can only name one if a pointer reached you. Three tiers differing only in how long you keep what you pulled: browse holds while you look, follow holds durably, interaction holds while the thread matters. Serving on is already automatic — the overlay re-seeds on fetch — so several people reading one profile is what keeps that profile available, not a cost. ⛔ autoSync is NOT the lever and must stay off. It is path-based push from an earlier design, and the overlay attaches to every swarm connection regardless of which feed justified it, so an offer broadcast crosses every scope boundary the room and follow model maintains. ★ Mirror mode already exists and is unwired: fetchFile's mirrorSpool writes blobs content-addressed, syncBaseDirs serves them straight back from that spool, and unlike the in-memory serve map it needs no boot-time rehydration. Only the trigger is missing. Per-file concurrency is likewise already solved by the chunk scheduler and must not be re-implemented. WHO GETS TOLD. An interaction is written in its author's own feed, so a like from someone who does not follow you never arrives — not late, never. The doorbell is the missing half, and knock is the working example of its shape. What is pushed is a POINTER, never content. That reconciles a reply being a post: it lives in its author's feed like any other, and only the announcement travels. Storage is uniform; reach varies. Two consequences elsewhere. "Notification" stops being one large open item — from people you follow it already works as a projection, from people you do not it is the doorbell. And the doorbell is the same problem as inbound ActivityPub, which today has nowhere to land because its author has no feed. §10 marks every claim measured or decided, per SOCIAL-MODEL §2.5. Open: bounding the doorbell, retention per tier, which feeds mirror, and whether a peek spools or scratches. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
87728512a3caee5f81e2c59c092d3bb7deaf151b
by plankatron <fleeky@gmail.com> · 2026-09-08T18:05:07.000Z

Changed files (1) +173 -0

docs/HOLDING-AND-TELLING.md +173 -0
……@@ -0,0 +1,173 @@
1# Holding and Telling
2
3**Status:** design. Mechanism verified in shipped code; policy undecided.
4**Date:** 2026-09-08
5**Sits under:** `SOCIAL-MODEL.md` (the room, the record, visibility as a place).
6**Answers two questions:** who holds a copy of what, and who gets told about it.
7
8---
9
10## 0. The outage that produced this
11
122026-09-08, measured. Tabertron held five pointers from ashatron's feed and could read
13none of them. Ashatron — a laptop — had gone offline, and it was the only machine holding the
14bytes. The surface said so honestly: *"5 record(s) could not be read — the log arrived, the bytes
15did not."* When ashatron came back, all five resolved.
16
17Nothing was broken. Every layer did what it was built to do. **The bytes were only ever fetched
18when somebody tried to read them**, and nobody had, so no second copy existed.
19
20## 1. Every post is two things
21
22A **note** — "this post exists, here is its fingerprint" — and the **text** itself.
23
24Notes travel automatically: they live in the log, and the log replicates to anyone holding the
25feed. Text does not travel automatically. A machine fetches text by fingerprint, on demand, when a
26reader asks for it.
27
28Like a library. You receive everyone's catalogue cards automatically, and you order a book only
29when somebody asks to read it. If the library shuts while you are holding only cards, you are
30holding nothing you can read.
31
32## 2. The one idea
33
34**Everything is pull. The only thing that is pushed is a doorbell ring.**
35
36Pull is what makes the fingerprint a capability: you can only fetch bytes you can name, and you can
37only name them if a pointer reached you, which membership already governs. Push inverts that — it
38lets a stranger decide what lands on your disk.
39
40⛔ **`autoSync` is not the lever.** hyper-overlay carries an older path-based mode where peers
41broadcast their file lists and push files at each other. It is off by construction and must stay
42off: the overlay attaches to *every* swarm connection regardless of which feed justified it, so a
43path-based offer crosses every scope boundary the room and follow model exists to maintain.
44
45## 3. Three tiers, one mechanism
46
47The tiers differ only in **how long you keep what you pulled**.
48
49| | you pull | you keep it | you serve it on |
50|---|---|---|---|
51| **browse** (peek) | one profile, on demand | while you are looking | yes — this is the network-health case |
52| **follow** | everything, on arrival | durably | yes |
53| **interaction** | one record, because you were told | while the thread matters | yes |
54
55★ **Serving on is free and already automatic.** hyper-overlay re-seeds by default: a node that
56fetches a blob registers it and becomes a source for it. *"A file held by N peers then gets faster
57as more peers fetch it."* So browsing is not merely tolerated — several people reading the same
58profile is how that profile stays available.
59
60★ **The browse/follow line already exists in code.** `timeline` skips peeked feeds deliberately:
61putting them in *"would make reading a stranger's page indistinguishable from following them,
62which is the whole thing peek exists to avoid."* This document makes that distinction mean
63something about storage too.
64
65⇒ **Following becomes a storage decision, not only a display one.** To follow is to say: keep their
66bytes, durably, and serve them to others. That is the blind-mirror the outage in §0 needed.
67
68## 4. Mirror mode already exists
69
70Verified in `hyper-overlay` 0.3.13, unwired in favela-peer.
71
72- **Fetching:** `fetchFile` takes a `mirrorSpool` option that stores the verified blob
73 content-addressed at `<spool>/<hash>` — *"the mirror path — a node with no working tree of its own
74 fetches files into a content-addressed spool so it durably re-serves them."*
75- **Serving:** `syncBaseDirs` makes the serve path resolve a request straight from that spool —
76 *"a pure function of the hash + dir, like a git object store. This is what lets a node keep serving
77 its spooled files across restarts with no rehydration step."*
78
79★ The spool needs no boot-time repair. The existing serve map is in-memory and has to be rebuilt at
80startup — a gap that once cost 75+ silent hours — because it maps paths. The spool derives its path
81from the hash, so a restart loses nothing.
82
83**What is missing is only the trigger.** Nothing fetches on arrival; the fetch happens when a reader
84asks. Wiring is: pass a spool, pass `syncBaseDirs`, and fetch in the background when a followed
85feed's log gains entries, with a cap on concurrent files.
86
87⚠ Per-file concurrency is already solved and should not be re-implemented: the chunk scheduler holds
88a dynamic RTT-scaled inflight window per peer, modelled on hypercore's replicator, with stall
89hotswap and reassignment on disconnect. What is unbounded is the number of *files* in flight.
90
91## 5. The doorbell — the half that does not exist
92
93An interaction is written in its author's own feed. A like on your post is a record in **my** diary.
94You learn of it only if you happen to hold my feed.
95
96⛔ **So an interaction from someone who does not follow you never arrives.** Not late — never. That
97is true today of likes, replies and mentions alike. The claim that interactions need no delivery
98holds only between people who already hold each other's feeds, and the peer's own notes admit the
99remainder: *"what is genuinely left is a stranger you hold nothing of."*
100
101There is one working example of the shape: `knock`, the doorbell, *"the ONE op a not-yet-member can
102usefully send."* It is bounded structurally — keyed by feed, so a flood is one row, not thousands —
103which matters because a rate limit inside apply would make the view non-deterministic.
104
105**What is pushed is a pointer, never content.** "There is a reply to your post, over here." Small,
106countable, bounded. You then fetch the reply itself — which is browsing, one record.
107
108## 6. A reply is a post that rings a doorbell
109
110A reply does not live in two places. It lives in its author's feed like any other post; only the
111announcement travels.
112
113- **A post:** I wrote this. Anyone holding my feed sees it.
114- **A reply:** I wrote this *and it points at you*. Anyone holding my feed sees it, **and you need
115 telling**, because you probably do not hold my feed.
116
117The code already says this — *"A reply IS a post that names a target"* — and this is what reconciles
118it with being a post. Storage is uniform; **reach is what varies**.
119
120## 7. Announcing a post is not, by itself, an interaction
121
122- **To your followers:** their subscription already carries it. Following means their machine
123 replicates your log; a new post is a new log entry. An announcement on top would duplicate it.
124- **To anyone else:** it is an interaction only if the post *names* them — a mention, a reply, a
125 quote. If it does not name them, an unsolicited announcement is what the network exists to refuse.
126
127⇒ **Following is a standing subscription; the doorbell is one-off and addressed.** "Tell me
128everything you write" versus "this particular thing concerns you."
129
130⚠ **Waking a sleeping device is a third thing** and must not be folded into either. Whether the
131doorbell rang is a data question; whether a phone lights up is a transport question. The peer's own
132notes already draw this line: *"waking a sleeping device, which is a separate job entirely."*
133
134## 8. What this changes elsewhere
135
136★ **"Notification" stops being one large unsolved item.** It has been carried as the biggest open
137thing for four sessions. It is two:
138
139- from people you follow — **already works**, a projection over feeds you hold
140- from people you do not — **the doorbell**, small and specific
141
142★ **The doorbell and the fediverse inbound problem are the same problem.** Inbound ActivityPub
143activity currently has nowhere to go in the peer, because its author has no feed — so it is merged
144at the view layer as a second source. The doorbell is that place. With it, a reply from Mastodon and
145a reply from a favela stranger stop being two mechanisms.
146
147## 9. Open
148
1491. **Bounding the doorbell.** `knock` gets away with one row per feed because it is a single
150 yes/no. Likes and replies are per-post and per-person, so "one row" does not hold, and unbounded
151 means anyone may write into your feed for ever. Bounding by *relationship* is the likely shape —
152 whose ring is accepted is a choice, as following is.
1532. **Retention per tier.** §3 names three lifetimes and nothing implements any of them. Mirror mode
154 without retention is a disk-filler; `evictContent` and `compact` exist and nothing calls them.
1553. **Which feeds mirror.** All followed, or own-devices-only? Own-devices is bounded by construction
156 and fixes §0 on its own.
1574. **Does browsing spool or scratch?** A peek that spools becomes a durable mirror by accident.
158
159## 10. What is measured and what is decided
160
161Following `SOCIAL-MODEL.md` §2.5's rule — a claim about the lower layers must cite a measurement.
162
163| | claim | status |
164|---|---|---|
165| §0 | five records unreadable, resolved when the author returned | ✅ measured |
166| §3 | re-seed on fetch is on by default | ✅ read in source |
167| §3 | `timeline` excludes peeked feeds | ✅ read in source |
168| §4 | `mirrorSpool` + `syncBaseDirs` exist and are unwired here | ✅ read in source |
169| §4 | the chunk scheduler bounds per-peer inflight | ✅ read in source |
170| §5 | an interaction from a non-follower never arrives | ✅ read in source |
171| §2 | pull is the security model, push is not | ⚠ decided |
172| §3 | follow means mirror durably | ⚠ decided |
173| §6 | a reply is a post plus a ring | ⚠ decided |