Changeset b60cf25 in Klonkt for test


Ignore:
Timestamp:
08/11/2026 04:24:25 PM (3 months ago)
Author:
Robin <roboburr@…>
Parents:
859b1707
Message:

guardianship: §1 is flat in beide richtingen, ook bij accept

Backport van 0261730 op main. Het Offer-pad belet een ward om te offeren
(a_ward_cannot_guard), maar het Accept-pad kende geen spiegelbeeld: een actor
die al wards heeft kon een guardianship-Offer accepteren en werd zo ward én
guardian tegelijk. §1 eist flatheid in beide richtingen.

De fout meldt zich niet. actorProps() kiest met een if/else één rol en
publiceert dan shaer:guardians terwijl shaer:isGuardian wegvalt: lokaal
blijven escalaties van de eigen wards binnenkomen, terwijl elke remote
§4-check de actor als malformed leest en laat vallen.

357 tests groen in een echte 1.6-omgeving (eigen npm ci, nodemailer 6.10.1
zoals stable vraagt, niet main's 9.x). Controleproef gedraaid: zonder de
controle wordt de nieuwe test rood en valt ook 'a guardian leaving sends an
Undo (§3.2)' om, doordat de actor dan werkelijk ward wordt.

Closes shaer-pmo.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • test/guardianship.test.js

    r859b1707 rb60cf25  
    119119  assert.equal(r.status, 403);
    120120  assert.equal(r.error, 'a_ward_cannot_guard');
     121});
     122
     123test('a guardian cannot be guarded either: §1 is flat in both directions', async () => {
     124  // parent guards kid by now, and gran (a guardian, so free to offer) offers
     125  // to guard parent. The offer itself is fine; only parent's accept would
     126  // make one actor ward and guardian at once.
     127  assert.ok(G.listWards('parent').length, 'parent already guards someone');
     128  const off = await G.handleGuardianshipOutbox(gran, {
     129    type: 'Offer', object: { type: 'Relationship', subject: ME, relationship: 'shaer:Guardian', object: GRAN },
     130  });
     131  assert.equal(off.status, 202, 'a guardian may still offer to guard');
     132  const id = offerIdFrom(off);
     133
     134  const r = await G.handleGuardianshipOutbox(parent, { type: 'Accept', object: id });
     135  assert.equal(r.status, 403);
     136  assert.equal(r.error, 'a_guardian_cannot_be_guarded');
     137
     138  // Nothing recorded, and the actor document still reads as a pure guardian.
     139  // Without the check actorProps() would have flipped it to a ward silently.
     140  assert.deepEqual(G.listGuardians('parent'), []);
     141  const doc = AP.buildActor('https://test.example', parent);
     142  assert.equal(doc['shaer:isGuardian'], true);
     143  assert.equal(doc['shaer:guardians'], undefined);
     144
     145  // The candidate and the existing guardians are untouched by the check, so
     146  // the offer is refusable in the ordinary way rather than stuck.
     147  await G.handleGuardianshipOutbox(parent, { type: 'Reject', object: id });
    121148});
    122149
Note: See TracChangeset for help on using the changeset viewer.