| … | … | @@ -0,0 +1,159 @@ |
| 1 | # The Edge Graph — making exchanged data legible |
| 2 | |
| 3 | **Status:** design. Nothing built. |
| 4 | **Date:** 2026-09-05 |
| 5 | **Companion to:** `SOCIAL-GRAPH-NAVIGATION.md`. That document is the **room graph** — nodes are |
| 6 | rooms, edges are MI, statistical and computed, for navigating. This is the **record graph** — nodes |
| 7 | are records and actors, edges are actual interaction records, observed and discrete, for seeing what |
| 8 | was actually exchanged. Same substrate, different graph, and they compose (§7). |
| 9 | **Depends on:** `SOCIAL-MODEL.md` (the room is the container), |
| 10 | `favela-markdown/spec/interaction.md` (edges). |
| 11 | |
| 12 | --- |
| 13 | |
| 14 | ## 1. Why this exists |
| 15 | |
| 16 | hyper-social #30 records the same failure three times in one day and names the shape: |
| 17 | |
| 18 | > **every surface we control reported success.** Tests green, RPC ok, log clean, HTTP 2xx. The truth |
| 19 | > was only visible on the product surface — a Mastodon status, a running process's env, a deploy log |
| 20 | > that was *quietly empty*. |
| 21 | |
| 22 | **The edge layer has no product surface at all.** A like that never projected, an alias that never |
| 23 | resolved, an inbound claim that never verified, and one that worked perfectly are — from every log, |
| 24 | test and RPC we have — identical. ap-bridge 0.0.3 shipped `reproject` with green tests, a happy RPC, |
| 25 | a clean log and a 2xx **and changed nothing**; only reading the actual Mastodon status caught it. |
| 26 | |
| 27 | This view is the missing surface. It is a debugging instrument first and a user-facing feature |
| 28 | second, and §5 keeps those two jobs from being merged into one screen that does neither. |
| 29 | |
| 30 | ## 2. It costs nothing architecturally |
| 31 | |
| 32 | Under `SOCIAL-MODEL.md` a graph view is **a projection** — a pure function from records to a view, |
| 33 | the same class of thing as a timeline or a notification list. No new storage, no new replication, no |
| 34 | new state. What makes it different from every other projection is that it renders the **substrate** |
| 35 | rather than the content. |
| 36 | |
| 37 | ## 3. What it renders |
| 38 | |
| 39 | **Nodes** |
| 40 | |
| 41 | | node | is | |
| 42 | |---|---| |
| 43 | | record | a post, or any record an edge points at | |
| 44 | | actor | a user (by `favela://` name; display name resolved for screen only) | |
| 45 | | room | the container — drawn as the enclosing region, not a node | |
| 46 | | foreign object | a subject named by an `at://` or `https://` URI we do not hold | |
| 47 | |
| 48 | **Edges** — one per interaction record: `like`, `repost`, `follow`, `block`, `reply`, `alias` |
| 49 | (`interaction.md` §5.4–5.5). Each edge is drawn **inside the room it was written in**, because that |
| 50 | is what determines its audience (`interaction.md` §4.5). A room boundary on screen is a real |
| 51 | boundary, not decoration. |
| 52 | |
| 53 | ## 4. ★ The four states — this is the whole diagnostic value |
| 54 | |
| 55 | An edge is not delivered or undelivered. It passes four independent steps, each of which fails |
| 56 | differently and **all of which currently look identical**: |
| 57 | |
| 58 | ``` |
| 59 | ① WRITTEN the pointer is in the author's writer core |
| 60 | │ fails: not writable, role missing, admission never granted |
| 61 | ▼ |
| 62 | ② CONVERGED it linearized into the room's view |
| 63 | │ fails: no indexer ack, N=2 quorum stall, fork |
| 64 | ▼ |
| 65 | ③ RESOLVED the bytes are locally available (ensureLocal returned) |
| 66 | │ fails: no peer served the oid, superseded local copy |
| 67 | ▼ |
| 68 | ④ PROJECTED a bridge emitted it — and for AP, got a 2xx that MEANT something |
| 69 | fails: no designated credential, unknown verb, reach excludes, |
| 70 | Update without `updated` (silent discard) |
| 71 | ``` |
| 72 | |
| 73 | **Render the state on the edge itself.** A dashed edge at ② is a quorum problem; a dashed edge at ③ |
| 74 | is a byte-availability problem; a dashed edge at ④ is a bridge problem. Today all three are "the |
| 75 | like didn't show up." |
| 76 | |
| 77 | ### 4.1 Bidirectionality is TWO edges, and that is the point |
| 78 | |
| 79 | An edge is one-directional. Everything that feels bidirectional — a follow-back, a DM, an `alias`, |
| 80 | a reply-and-its-acknowledgement — is **a pair of independent edges**, each with its own four states. |
| 81 | |
| 82 | **The common bug is one direction landing and the other not**, and a view that draws the pair with |
| 83 | each direction's state separately makes that visible at a glance. Drawing it as a single |
| 84 | double-headed arrow would hide exactly the failure the view exists to catch. |
| 85 | |
| 86 | ### 4.2 `alias` edges are the cross-network truth |
| 87 | |
| 88 | `alias` never projects (`interaction.md` §5.5) — it is how a node knows two names denote one thing. |
| 89 | Rendering alias edges is the only way to see whether cross-network identity actually resolved. A |
| 90 | foreign object with no alias edge is why `projectLike` returned `null` and the like silently did not |
| 91 | happen (`ap-bridge/lib/as2-project.js:165-168`). |
| 92 | |
| 93 | ## 5. Two renderings, opposite requirements |
| 94 | |
| 95 | They must not be one screen. |
| 96 | |
| 97 | | | **debug view** | **discovery view** | |
| 98 | |---|---|---| |
| 99 | | shows | every edge, including failed ones | computed structure | |
| 100 | | layout | raw, unclustered, ordered by state | force-directed, clustered | |
| 101 | | labels | verbatim URIs, oids, rkeys | display names | |
| 102 | | naming | none | ⛔ **never auto-names a cluster** | |
| 103 | | audience | operator | everyone | |
| 104 | |
| 105 | The discovery view is `SOCIAL-GRAPH-NAVIGATION.md`'s Graph View and inherits its rules — in |
| 106 | particular `COMMUNITY-EMERGENCE.md`'s: *"the observation is an intervention."* The system may surface |
| 107 | a cluster; **naming it is a political act reserved for humans.** |
| 108 | |
| 109 | The debug view has the opposite duty: show the ugly truth, unclustered, including things that failed, |
| 110 | because a tidy picture is what let six versions of prod run ahead of git for ten days. |
| 111 | |
| 112 | ## 6. Honesty rules |
| 113 | |
| 114 | Inherited from the model, not invented here: |
| 115 | |
| 116 | 1. **It shows what THIS node knows, not what is true.** Label it as such. Different peers legitimately |
| 117 | compute different graphs (`SOCIAL-MODEL.md` §5). |
| 118 | 2. **Never sum local and network counts.** favela-web already refuses to (hyper-social #45 §2); the |
| 119 | graph view must not quietly reintroduce a total. |
| 120 | 3. **An absent edge is not a negative.** It means "not replicated to me yet" unless there is a |
| 121 | tombstone — the same ambiguity the signer's forward-only gate exists to respect. |
| 122 | 4. **⛔ No aggregation, ever.** No export, no "share your graph", no combining views across peers. |
| 123 | `COMMUNITY-EMERGENCE.md` names the aggregation attack and its mitigation is **no mechanism**, not |
| 124 | a permission check. A graph view with an export button is that mechanism. |
| 125 | |
| 126 | ## 7. How it composes with the room graph |
| 127 | |
| 128 | ``` |
| 129 | SOCIAL-GRAPH-NAVIGATION ←→ EDGE-GRAPH |
| 130 | room graph ←→ record graph |
| 131 | MI, statistical ←→ observed, discrete |
| 132 | map ←→ wiring diagram |
| 133 | "where am I" ←→ "did that actually land" |
| 134 | ``` |
| 135 | |
| 136 | Click a room in the map, get its wiring diagram. Click an edge in the wiring diagram, get the record. |
| 137 | Two projections of one substrate — which is the claim `SOCIAL-MODEL.md` makes about every view. |
| 138 | |
| 139 | ## 8. Open |
| 140 | |
| 141 | 1. **Scale.** A busy room's edge count dwarfs its record count. Filtering, and what the default |
| 142 | filter is, is unaddressed. |
| 143 | 2. **Where the four states come from.** ① and ② are readable from the autobase; ③ from |
| 144 | `ensureLocal`; ④ needs the bridge's **delivery bookkeeping**, which is node-local and not |
| 145 | replicated (`identity.md` §6.3). So the debug view is only complete on a node that runs its own |
| 146 | bridges. |
| 147 | 3. **Whether ④ can be trusted.** A 2xx from Mastodon is not evidence of anything (#30). The state may |
| 148 | need a fifth step — *confirmed on the product surface* — which cannot be derived and must be |
| 149 | fetched. |
| 150 | 4. **Where it lives** — favela-web (SSR, no-JS reading path) versus a separate operator tool. A graph |
| 151 | is the one thing the no-JS path cannot render. |
| 152 | 5. **Whether the debug view ships to users at all**, or stays an operator surface. |
| 153 | |
| 154 | ## 9. What this does not claim |
| 155 | |
| 156 | - It is not the room graph, and does not compute MI or clusters. That is `SOCIAL-GRAPH-NAVIGATION.md`. |
| 157 | - It does not make an edge more reliable. It makes its failure visible, which is a different thing. |
| 158 | - It cannot show what this node has not replicated — an absent edge and an unreplicated one look the |
| 159 | same, and §6 #3 says to render that ambiguity rather than resolve it. |