Relay 0.7.0: een weg naar binnen, en de melding bij elke klik weg

Vier punten van de gebruiker, opgekomen tijdens het beproeven met de testclient.

De getimede leerstand is eruit; de wachtlijst is de enige weg naar binnen. Zijn
redenering: allebei de wegen vragen iemand die bij de app kan, dus het is
dubbelop, en het venster is de zwakste omdat het iedereen toelaat die er
toevallig in verbindt. Dat weegt zwaarder nu de relay op een publiek wss-adres
kan staan. De oorspronkelijke reden voor de leerstand, dat je je eigen OwnerId
nergens kon aflezen, verviel toen de weigerlijst dat id ging tonen. Daarmee
verdwijnt ook de bug die hij dezelfde dag meldde: een geleerde eigenaar bleef in
de weigerlijst staan terwijl hij al kon schrijven en lezen, want decideOwner
haalde hem niet van die lijst af en de knop allow wel.

"Refused owners" heet "Waiting list", met de badge Waiting en een teller waar de
widget van het tijdvenster stond. Het veld op schijf blijft rejected: hernoemen
zou een migratie zijn voor een woord dat niemand ziet.

Het adres onderaan zei http:// en dat kan nergens werken, want de relay spreekt
WebSocket en nooit HTTP. Nu ws://<host>:3852, met een regel over wss://<domein>
zonder poort achter een reverse proxy. Dat is precies de fout die diezelfde dag
een ronde kostte bij het koppelen van de testclient.

De melding bij elke klik is weg. Die stond in de gewone stroom van de pagina,
dus alles eronder schoof omlaag en weer omhoog. Nu gaan de knoppen in de lijsten
even op slot tot de ronde de nieuwe stand heeft; foutmeldingen blijven wel staan,
want die zeggen iets wat je nergens anders ziet.

STATE_VERSION blijft 1 en een owners.json van 0.6.0 leest door: learning en
learningUntil worden gelezen, genegeerd en niet teruggeschreven. Een verhoging
zou store.js de allowlist van een werkende installatie opzij laten schuiven.

Twee toetsen bewaken dat de leerstand niet terugsluipt: een onbekende eigenaar
wordt geweigerd ook met learning: true in het bestand, en set-learning is een
onbekende actie. Beide mutatie-getest.

De compose staat op 0.7.0 zonder digest, zodat het hard faalt tot de image
bestaat. Bouwen, duwen en pinnen ligt bij de gebruiker.

Suite: 424 goed, 0 fout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Harmen
2026-09-09 15:45:55 +02:00
co-authored by Claude Opus 5
parent 04c20a37f0
commit a092464e4d
13 changed files with 449 additions and 804 deletions
+16 -9
View File
@@ -157,18 +157,19 @@ python tests/test_relay_agent.py
De eerste toetst het toegangsbeleid uit
`tools/evolu-relay/src/policy.js`: wie er op de relay mag schrijven, wat er met een onbekende eigenaar
gebeurt, en of een geblokkeerde eigenaar er niet alsnog in komt doordat de leerstand aanstaat. Node 24 of
gebeurt, en of een geblokkeerde eigenaar er niet alsnog in komt. Node 24 of
hoger, geen afhankelijkheden, en het bestand is met opzet `.mjs`: in de repo-root is er geen `package.json`,
dus een `.js` zou als CommonJS gelezen worden en de import falen.
**Het beleid staat los van de relay en dat is de reden dat dit te testen is.** `policy.js` bevat alleen
pure functies: geen bestanden, geen netwerk, geen klok. Wat wél schijf raakt staat in `store.js`, en de
relay zelf wordt in `index.js` alleen aangeroepen. Houd die scheiding aan; anders is er van deze test niets
meer over. **Ook het tijdvenster heeft geen klok**: `isLearningOpen(state, now)` krijgt het tijdstip mee.
meer over. Twee toetsen erin bewaken dat de leerstand niet terugsluipt: een onbekende eigenaar wordt
geweigerd ook met `learning: true` in het bestand, en `set-learning` is een onbekende actie.
De tweede toetst de agent: de labels en de resterende tijd van het tijdvenster. Dat zijn de twee dingen die
de agent zélf uitrekent in plaats van doorgeeft, en daarmee de enige plek in dit bestand waar hij eigen
logica heeft. De HTTP-laag zit er niet in: die handlers zijn zonder socket niet aan te roepen.
De tweede toetst de agent: de labels. Dat is het enige dat hij zélf uitrekent in plaats van doorgeeft, en
daarmee de enige plek in dat bestand waar hij eigen logica heeft. De HTTP-laag zit er niet in: die handlers
zijn zonder socket niet aan te roepen.
### Architectuurregels
@@ -200,10 +201,16 @@ De verdeling:
| `command.json` | de agent | de postbus. De agent legt erin, het relay-proces past toe en ruimt op |
| `labels.json` | de agent | een label zegt niets over toegang, dus de relay hoeft het niet te weten. Dat het hier staat en niet in `owners.json` is wat labelen meteen laat werken, ook als de relay omgevallen is |
**Het tijdvenster voor nieuwe eigenaars loopt in het relay-proces, nooit in de pagina.** Een teller in een
tabblad dat je sluit, sluit de deur niet. En `decideOwner` kijkt naar `isLearningOpen(state, now)` en niet
naar het veld `learning`: de lus die een verlopen venster opruimt loopt elke twee seconden, en in dat gat
zou een onbekende alsnog binnenkomen.
**Er is één weg naar binnen: de wachtlijst.** Een onbekende eigenaar wordt geweigerd en onthouden; op de
statuspagina laat je hem toe. De getimede leerstand die daarnaast bestond is er in 0.7.0 (09-09-2026) uit,
op voorstel van de gebruiker: allebei de wegen vragen iemand die bij de app kan, dus het was dubbelop, en
het venster was de zwakste omdat het iederéén toeliet die er toevallig in verbond. Zet hem niet terug zonder
het plan **Umbrelapp** te lezen.
De velden `learning` en `learningUntil` worden nog wél gelézen en dan genegeerd. Dat is geen slordigheid:
`STATE_VERSION` verhogen zou `normalizeState` een bestaand `owners.json` laten afwijzen, en dan schuift
`store.js` de allowlist van een werkende installatie opzij en gaat de deur dicht voor eigenaars die er al in
stonden. Het veld op schijf heet nog `rejected`; op de pagina heet het de wachtlijst.
**Het beleid is de enige plek waar staat wie er binnen mag, en `isOwnerAllowed` wordt alleen bij de
WebSocket-upgrade gesteld.** Gevolg om te kennen voordat je iets belooft op de pagina: **blokkeren werkt pas