source: Klonkt/docs/ward-outbound-follows-design.md@ af035e6

main
Last change on this file since af035e6 was af035e6, checked in by Bart <bart@…>, 5 weeks ago

Ontwerp: uitgaande follows van een ward

Inkomend is gated (FEP-633c 5.3), uitgaand niet: ingestOutboxActivity roept bij
case 'Follow' meteen followActor() aan. Een ward met een vastgelegde guardian
kan vandaag iedereen volgen zonder dat iemand het ziet.

De regel wordt per geval goedkeuring, met automatische goedkeuring bij
wederkerigheid: wie de ward al volgt is al door de inkomende poort gekomen, dus
daar heeft een guardian al ja tegen gezegd.

Vastgelegd: eigen tabel (ap_pending_follows is gesleuteld met de ward als doel),
ap_following krijgt pas een rij bij goedkeuring (status 'pending' betekent daar
al iets anders), de wachtrij splitst in follows/outgoingFollows, en een
tegengehouden follow mag er niet uitzien als een gelukte.

Grootste open vraag: followers van vóór de adoptie zijn nooit door een guardian
gezien en worden onder deze regel wel automatisch goedgekeurde doelen.

Co-Authored-By: Claude Opus 5 <claude@…>

  • Property mode set to 100644
File size: 6.1 KB
Line 
1# Uitgaande follows van een ward — ontwerp
2
3FEP-633c §5.3 houdt follows *naar* een ward tegen tot de guardians beslissen.
4Follows *van* een ward gaan ongehinderd de deur uit. `ingestOutboxActivity`
5roept bij `case 'Follow'` meteen `followActor()` aan: geen ward-check, geen
6guardian, geen wachtrij. `mee` heeft een vastgelegde guardian en kan vandaag
7iedereen op de fediverse volgen zonder dat iemand het ziet.
8
9De asymmetrie is half te verdedigen. `Block` (Shaers "Orbit") is uitgaand ook
10ongated, en dat is de veilige richting: een kind dat zijn eigen wereld kleiner
11maakt heeft geen toestemming nodig. Volgen is de richting die hem opent.
12
13Er staat hierover niets in de docs of de FEP-notities. Dit is dus een gat in het
14ontwerp, niet een ongeschreven stuk implementatie.
15
16## De regel
17
18**Per geval goedkeuring, met automatische goedkeuring bij wederkerigheid.**
19
20Volgt de ward iemand die de ward al volgt, dan hoeft er niemand meer naar te
21kijken. Die actor is namelijk al door de inkomende poort gekomen, en dat betekent
22dat een guardian er al ja tegen heeft gezegd. Nog een keer vragen is dezelfde
23vraag twee keer stellen, en elke overbodige vraag is er een die de volgende keer
24minder aandacht krijgt.
25
26Het predicaat is `target_uri ∈ ap_followers(slug)`. Kort, maar het klopt alleen
27zolang lidmaatschap van die tabel écht een guardian-besluit impliceert — zie de
28eerste open vraag.
29
30## Beslissingen
31
32- **Een eigen tabel, niet `ap_pending_follows`.** Die tabel is gesleuteld op
33 `(ward_slug, follower_uri)`: de ward is daar het *doel*. Uitgaand draait dat
34 om. Een `direction`-kolom erbij zou elke bestaande query dubbelzinnig maken,
35 inclusief `listForWard`, die nu simpelweg "wie wil mij volgen" betekent. Dus
36 `ap_pending_outgoing_follows (id, ward_slug, target_uri, target_inbox,
37 target_name, target_handle, target_icon, quorum, status, created_at)` met
38 dezelfde vorm en dezelfde `decide()`-semantiek, maar apart.
39
40- **`ap_following.status` is al bezet en betekent iets anders.** Daar staat
41 `pending` voor "wij hebben de Follow verstuurd, hun Accept moet nog komen".
42 Een guardian-pending follow is nog helemaal niet verstuurd. Twee verschillende
43 wachttoestanden op één kolom is precies het soort dubbelzinnigheid dat later
44 een bug wordt. Daarom: **de `ap_following`-rij ontstaat pas bij goedkeuring**,
45 op het moment dat de Follow daadwerkelijk uitgaat. Vóór die tijd bestaat het
46 verzoek alleen in de nieuwe tabel.
47
48- **Wederkerigheid is een momentopname.** Getoetst bij het verzoek, niet
49 doorlopend bewaakt. Ontvolgt de ander later, dan wordt een al goedgekeurde
50 follow niet met terugwerkende kracht ingetrokken. Anders krijg je een relatie
51 die stilletjes verdwijnt door een actie van een derde.
52
53- **Quorum: `any` hergebruiken, maar het eindelijk ergens vastleggen.** De kolom
54 `quorum` bestaat op `ap_pending_follows`, maar de aanroep in
55 `ActivityPubService.js` geeft hem nooit mee. Alles valt dus terug op de default
56 `'any'`, en `'all'` en `'none'` zijn in de praktijk dood. Een uitgaand beleid
57 heeft een echte plek nodig — per ward, niet per verzoek — en dat is het moment
58 om de inkomende kant dezelfde plek te laten gebruiken.
59
60- **De wachtrij splitsen.** `shaer:queues.follows` staat al op het actor-document.
61 Als beide richtingen daarin landen, kan een guardian "iemand wil Mee volgen"
62 niet onderscheiden van "Mee wil iemand volgen" — twee vragen die in de
63 interface verschillende woorden verdienen. Dus `follows` blijft inkomend
64 (compatibel) en er komt `shaer:queues.outgoingFollows` naast.
65
66 Let op: nieuwe termen moeten in `AP_CONTEXT` of `test/activitypub-as2.test.js`
67 valt om. Die test eist dat elke uitgestuurde sleutel AS2-core is of in de
68 federatie-context staat, en dat is precies de bedoeling ervan.
69
70- **Cross-instance: spiegel het `Offer(Follow)`-patroon.** Een lokale guardian
71 leest `/guardian` rechtstreeks; een guardian op een andere server krijgt een
72 Offer afgeleverd zodat zijn instance een kopie opslaat, net als bij de
73 adoptie-offer en bij `ap_follow_reviews`. Voor `mee` (ward op `loop`) en
74 `boiert` (guardian op `boiert`) zijn dat twee instances op dezelfde machine,
75 dus die weg wordt meteen echt gelopen en niet gesimuleerd.
76
77- **Een tegengehouden follow mag er niet uitzien als een gelukte.** Dit is
78 dezelfde les als in de bestaande `case 'Follow'`: *"De error REACHT de app
79 (Robins melding, 31-7): het wegslikken maakte een mislukte follow precies
80 gelijk aan een gelukte."* Een verzoek in de wacht is een derde uitkomst en de
81 app moet die kunnen tonen. Voorstel: `202` met een expliciete status in de body
82 (`{ ok: true, status: 'awaiting_guardian', id }`), zodat Shaer "wacht op
83 toestemming" kan laten zien in plaats van een tegel die er al volgend uitziet.
84
85## Open vragen
86
871. **Wat doen we met followers van vóór de adoptie?** Was de ward eerst een vrije
88 actor, dan zijn zijn bestaande followers nooit door een guardian gezien. Bij de
89 regel hierboven worden dat stuk voor stuk automatisch goed te keuren doelen.
90 Ofwel we accepteren dat, ofwel `ap_followers` krijgt een markering "door de
91 poort gekomen" en alleen die telt mee. Dit is de belangrijkste vraag van dit
92 document.
93
942. **Mag de ward zijn eigen verzoek intrekken** zolang het in de wacht staat? Lijkt
95 vanzelfsprekend ja, maar het is een Undo op iets dat nooit verstuurd is.
96
973. **De guardian zelf als doel.** Een ward die zijn eigen guardian volgt, hoort
98 niet te hoeven wachten. Dat is dezelfde uitzondering als inkomend, waar de
99 Follow van een vastgelegde guardian de poort overslaat.
100
1014. **Interactie met Block/Orbit.** Blokkeert de ward iemand terwijl er nog een
102 verzoek voor die persoon open staat, dan moet dat verzoek verdwijnen.
103
1045. **Emancipatie.** Wat gebeurt er met openstaande verzoeken als de
105 guardianship eindigt? Automatisch goedkeuren of laten vervallen.
106
107## Daemon-pariteit
108
109De daemon-README is er stellig over: de apps moeten zich tegen beide backends
110hetzelfde gedragen, en als daemon en Klonkt uit elkaar lopen is de UI die je
111lokaal test een leugen. Wat hier landt, landt dus ook in `shaer-daemon`
112(`gate.rs` heeft nu alleen de inkomende kant), en de wachtrij-namen en de
113`awaiting_guardian`-status moeten letterlijk gelijk zijn.
Note: See TracBrowser for help on using the repository browser.