Ignore:
Timestamp:
08/03/2026 06:38:16 AM (5 weeks ago)
Author:
Bart <bart@…>
Branches:
main
Children:
3d882bd
Parents:
69bd747
Message:

Een handshake blijft een week open, en faalt daarna onder zijn eigen naam

§4.2 leunt erop dat het uitstel begrensd is: als het venster sluit met de
controle nog onbeslist, faalt de beslissing dicht. Alleen had een
guardianship-offer in Klonkt helemaal geen venster, dus "uitgesteld" was
"voor altijd".

Nu een week. Lang genoeg dat niemand wordt opgejaagd — er moeten een ward, een
kandidaat en alle bestaande guardians antwoorden, en dat zijn mensen — en kort
genoeg dat een vergeten aanbod niet een maand in de wachtrij van een kind staat
alsof het nog een keuze is.

Twee eindtoestanden, want het zijn twee verschillende feiten:
'expired' (niemand heeft geantwoord; zegt niets over de kandidaat) en
'unverified' (iedereen heeft geantwoord, maar de kandidaat was nooit op te
halen). Geen van beide is 'void': de partijen mag niet verteld worden dat de
kandidaat geweigerd is, want dat is niet gebeurd — er heeft alleen nooit iemand
kunnen kijken.

Vervallen gebeurt bij het lezen, zoals een lapse dat ook doet: geen sweeper die
niemand draait. En het lezen van de wachtrij is meteen het moment waarop een
uitgestelde commit opnieuw wordt geprobeerd (§4.2 SHOULD) — nodig, want de
laatste Accept kan al binnen zijn en dan port niemand er ooit nog aan. Niet
awaited: een poll toont wat nu waar is.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/guardianship/handshake.js

    r69bd747 r30d0e2c  
    545545}
    546546
     547/**
     548 * §4.2 SHOULD: retry the dereference for handshakes left deferred because the
     549 * candidate could not be read.
     550 *
     551 * Waiting for a further activity from a party is not enough: the commit is
     552 * triggered by the LAST `Accept`, so if that one has already arrived nothing
     553 * will ever poke it again and the handshake would sit until its window closed.
     554 * The ward's dashboard polling its own offers queue is this instance's
     555 * schedule, exactly as a read settles a lapse (§3.6.3).
     556 *
     557 * Deliberately not awaited by the read: a poll should render what is true now,
     558 * not block on someone else's slow server. A retry that succeeds shows up in
     559 * the next poll, which is the same second or two later.
     560 */
     561export async function retryDeferred(slug) {
     562  for (const o of offers.listDeferred(slug)) {
     563    await maybeCommit(slug, o.offer_id).catch(() => { /* next poll tries again */ });
     564  }
     565}
     566
    547567function notify(slug, ev) {
    548568  try { if (deps && typeof deps.onEvent === 'function') deps.onEvent(slug, ev); } catch { /* best-effort */ }
    549569}
    550570
    551 export default { wireHandshake, handleOutbox, handleInbox, parseRelationship, parseUndoRelationship, endGuardianship };
     571export default { wireHandshake, handleOutbox, handleInbox, parseRelationship, parseUndoRelationship, endGuardianship, retryDeferred };
Note: See TracChangeset for help on using the changeset viewer.