Changeset af5b79b in Klonkt


Ignore:
Timestamp:
07/25/2026 08:37:24 AM (7 weeks ago)
Author:
Robin <roboburr@…>
Branches:
main
Children:
2b4252c
Parents:
8f520e0
Message:

FEP-633c §2.2: shaer:hasGuardians (outbound stempelen, inbound registreren)

Objecten van een ward krijgen nu de advies-hint shaer:hasGuardians, zodat een
remote server interacties met de post naar de guardians kan routen zonder eerst
de actor op te halen. Veilig te negeren door wie geen shaer spreekt.

Outbound: elke Note die een ward publiceert wordt gestempeld (alle drie de
buildNote-paden: gewone post, paid-teaser, reply/direct), dus ook via buildCreate
in de outbox. Inbound: de hint wordt alleen GEREGISTREERD op het opgeslagen object
(ap_timeline.has_guardians / ap_mentions.has_guardians), nog geen actie. Wordt
later bekendgemaakt bij reddings-boei / escalatie-routing (Robins besluit).

Changed files:
src/services/guardianship/notes.js

  • hasGuardiansProps(slug) (stempel als de site guardians heeft) + objectHasGuardians(o)

src/services/guardianship/index.js

  • beide geexporteerd

src/services/ActivityPubService.js

  • buildNote stempelt in alle drie de return-paden; inbound zet has_guardians op timeline + mention

src/config/database.js

  • ap_timeline.has_guardians + ap_mentions.has_guardians

test/has-guardians.test.js

  • ward stempelt wel, free niet; objectHasGuardians leest de hint

remarks: npm test 170/170. Alleen ward-objecten dragen de hint; niks acteert er nog
op (register-only). Daemon heeft de constante al (dead_code); wiren kan later.

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

Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • src/config/database.js

    r8f520e0 raf5b79b  
    563563  ensureColumn('ap_outbox', 'wave', 'INTEGER');    // FEP-633c shaer:wave (guardian -> ward nudge)
    564564  ensureColumn('ap_mentions', 'wave', 'INTEGER');  // inbound guardian wave
     565  // FEP-633c §2.2: object hint that the author is a ward. Register-only for now;
     566  // used later at reddings-boei / escalation routing.
     567  ensureColumn('ap_timeline', 'has_guardians', 'INTEGER');
     568  ensureColumn('ap_mentions', 'has_guardians', 'INTEGER');
    565569  ensureColumn('ap_followers', 'name', 'TEXT');    // cached display name (shaer-aa3)
    566570  ensureColumn('ap_followers', 'handle', 'TEXT');  // @user@host
  • src/services/ActivityPubService.js

    r8f520e0 raf5b79b  
    278278      ...Guardianship.helpRequestProps(post),
    279279      ...Guardianship.waveProps(post),
     280      // FEP-633c §2.2: object hint that the author is a ward.
     281      ...Guardianship.hasGuardiansProps(site.slug),
    280282      tag: [
    281283        ...mentionTags(post.content),
     
    312314      tag: [...hashtagTags(base, post.content)],
    313315      replies: `${id}/replies`,
     316      ...Guardianship.hasGuardiansProps(site.slug),
    314317    };
    315318  }
     
    488491    sensitive: !!post.nsfw,
    489492  };
     493  // FEP-633c §2.2: object hint that the author is a ward (safely ignorable).
     494  Object.assign(note, Guardianship.hasGuardiansProps(site.slug));
    490495  if (post.nsfw) note.summary = post.content_warning || 'Gevoelige inhoud';
    491496  if (attachment.length) note.attachment = attachment;
     
    15041509        for (const s of subs) {
    15051510          tlStmts().ins.run(o.id, s.slug, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.url || null, o.published || null, media, o.sensitive ? 1 : 0, o.summary || null);
     1511          // FEP-633c §2.2: register the ward hint on the stored object (no action yet).
     1512          if (Guardianship.objectHasGuardians(o)) { try { db.prepare('UPDATE ap_timeline SET has_guardians = 1 WHERE id = ? AND slug = ?').run(o.id, s.slug); } catch { /* ignore */ } }
    15061513          if (poll) { try { db.prepare('UPDATE ap_timeline SET poll_json = ? WHERE id = ? AND slug = ?').run(JSON.stringify(poll), o.id, s.slug); } catch { /* ignore */ } }
    15071514        }
     
    15221529        const help = Guardianship.isHelpRequest(o);
    15231530        const wave = Guardianship.isWave(o);
     1531        const hasG = Guardianship.objectHasGuardians(o);   // §2.2 hint, register-only
    15241532        for (const slug of slugs) {
    15251533          try {
    1526             const r = db.prepare('INSERT OR IGNORE INTO ap_mentions (slug, object_uri, note_url, actor_uri, actor_name, actor_handle, actor_icon, actor_url, content, published, help_request, wave, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)')
    1527               .run(slug, o.id, safeUrl(o.url) || null, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.published || null, help ? 1 : 0, wave ? 1 : 0);
     1534            const r = db.prepare('INSERT OR IGNORE INTO ap_mentions (slug, object_uri, note_url, actor_uri, actor_name, actor_handle, actor_icon, actor_url, content, published, help_request, wave, has_guardians, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)')
     1535              .run(slug, o.id, safeUrl(o.url) || null, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.published || null, help ? 1 : 0, wave ? 1 : 0, hasG ? 1 : 0);
    15281536            if (r.changes) {
    15291537              console.log('[AP] mention', actorUri, '→', slug, help ? '(help request)' : '');
  • src/services/guardianship/index.js

    r8f520e0 raf5b79b  
    1616 */
    1717export { SHAER_CONTEXT, GUARDIAN_RELATIONSHIP, GUARDIAN_RELATIONSHIP_COMPACT, isGuardianRelationship } from './context.js';
    18 export { helpRequestProps, isHelpRequest, waveProps, isWave } from './notes.js';
     18export { helpRequestProps, isHelpRequest, waveProps, isWave, hasGuardiansProps, objectHasGuardians } from './notes.js';
    1919export { wireDelivery, c2sVisibility, deliverDirectNote } from './delivery.js';
    2020export { wireHandshake, handleOutbox as handleGuardianshipOutbox, handleInbox as handleGuardianshipInbox, parseRelationship } from './handshake.js';
  • src/services/guardianship/notes.js

    r8f520e0 raf5b79b  
    55 * on direct notes. Everyone who does not speak shaer can ignore it.
    66 */
     7import { listGuardians } from './relations.js';
     8
     9/**
     10 * shaer:hasGuardians (§2.2): an advisory OBJECT hint that the author is a ward,
     11 * so a remote server can route interactions to the guardians WITHOUT fetching
     12 * the actor. Stamped on every object a ward publishes; MUST be safely ignorable.
     13 */
     14export function hasGuardiansProps(slug) {
     15  try { return (slug && listGuardians(slug).length) ? { 'shaer:hasGuardians': true } : {}; }
     16  catch { return {}; }
     17}
     18
     19/** True when an incoming object carries the ward hint (§2.2). Register-only for
     20 *  now; acted on later at reddings-boei / escalation routing. */
     21export function objectHasGuardians(o) {
     22  return !!o && (o['shaer:hasGuardians'] === true || o.hasGuardians === true);
     23}
    724
    825/** Extra JSON-LD properties for an outgoing note built from an ap_outbox row. */
     
    3148}
    3249
    33 export default { helpRequestProps, isHelpRequest, waveProps, isWave };
     50export default { helpRequestProps, isHelpRequest, waveProps, isWave, hasGuardiansProps, objectHasGuardians };
Note: See TracChangeset for help on using the changeset viewer.