Ignore:
Timestamp:
08/06/2026 09:19:49 AM (5 weeks ago)
Author:
Claude (agent) <aiclaude@…>
Branches:
main
Children:
7842ca1
Parents:
68a4d1b
git-author:
Robin <roboburr@…> (08/06/2026 09:19:48 AM)
git-committer:
Claude (agent) <aiclaude@…> (08/06/2026 09:19:49 AM)
Message:

Interact-pagina toonde geen reactie: twee sleutelruimtes samengetrokken

Robins melding: sound-fabrics.com/effortlesseffect is geliket EN geboost, maar
de knoppen op de interact-pagina lichtten niet op.

Een post heeft twee URI's. Zijn AP-object-id (.../ap/notes/<uuid>), die de Krant
en het C2S-pad spreken, en zijn leesbare permalink (.../effortlesseffect), waar
de interact-pagina mee binnenkomt. De tussentabel stond vol object-URI's -- alle
zestien rijen -- en de interact-pagina zocht op de permalink. De reactie bestond
dus wel; we keken op de verkeerde sleutel.

Dit is de naad die ik in fase 1 bewust open liet met de opmerking dat
samentrekken werk voor fase 2 was. Dat uitstel was fout: zodra het leespad de
tussentabel volgde, werd een bestaande reactie onzichtbaar in plaats van
inconsistent. canonicalReactionUri vertaalt nu bij zowel lezen als schrijven naar
de object-URI, met de permalink als ingang. Kennen we de post niet, dan blijft de
invoer de sleutel, zodat een reactie op iets buiten je tijdlijn blijft werken.

setReaction gebruikt daarmee EEN sleutel voor beide bronnen in plaats van de
gestuurde voor de tussentabel en de opgeloste voor de vlag.

Drie tests erbij, waaronder Robins geval bij naam: liken via de object-URI en
uitlezen via de permalink, en andersom.

LET OP BIJ UITROL ELDERS: op dev staan alle tussentabel-rijen al op de
object-URI, dus daar viel niets te migreren. Op een instance waar de
interact-pagina eerder is gebruikt kunnen rijen op de permalink staan; die worden
na deze wijziging niet meer gevonden. Meet dat vóór de uitrol:

SELECT COUNT(*) FROM ap_my_reactions r

WHERE NOT EXISTS (SELECT 1 FROM ap_timeline t

WHERE t.slug=r.site_slug AND t.id=r.target_uri);

Suite 434/434.

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r68a4d1b r6bc5ebd  
    34393439 */
    34403440/**
     3441 * Van wat de client stuurde naar de canonieke sleutel voor een reactie.
     3442 *
     3443 * Een post heeft twee URI's: zijn AP-object-id (.../ap/notes/<uuid>) en zijn
     3444 * leesbare permalink (.../effortlesseffect). De Krant en het C2S-pad spreken de
     3445 * eerste, de interact-pagina de tweede. Werden reacties onder allebei opgeslagen,
     3446 * dan bestond dezelfde like twee keer -- en erger: een like uit de Krant was op
     3447 * de interact-pagina onzichtbaar, want daar werd op de permalink gezocht.
     3448 *
     3449 * Dit was de naad die fase 1 bewust open liet ("samentrekken is werk voor fase
     3450 * 2"). Robin liep er meteen tegenaan: een geboost en geliket bericht toonde geen
     3451 * highlight. Vandaar hier, en niet later.
     3452 *
     3453 * De object-URI wint, want dat is waar ap_timeline op sleutelt en waar de
     3454 * backfill op is gebaseerd. Kennen we de post niet, dan blijft de invoer staan:
     3455 * een reactie op iets buiten je tijdlijn moet gewoon werken.
     3456 */
     3457export function canonicalReactionUri(slug, uri) {
     3458  if (!slug || !uri) return uri;
     3459  try {
     3460    if (db.prepare('SELECT 1 FROM ap_timeline WHERE slug = ? AND id = ?').get(slug, uri)) return uri;
     3461    const row = db.prepare('SELECT id FROM ap_timeline WHERE slug = ? AND url = ? LIMIT 1').get(slug, uri);
     3462    return (row && row.id) || uri;
     3463  } catch { return uri; }
     3464}
     3465
     3466/**
    34413467 * Wat heb IK met dit object gedaan? Leest de tussentabel, de bron van waarheid
    34423468 * sinds shaer-9e9 fase 2. Vervangt getMyReactions en getTimelineReaction, die
     
    34453471export function getReaction(slug, uri) {
    34463472  try {
    3447     const rows = (slug && uri)
    3448       ? db.prepare('SELECT kind FROM ap_my_reactions WHERE site_slug = ? AND target_uri = ?').all(slug, uri)
     3473    const key = canonicalReactionUri(slug, uri);
     3474    const rows = (slug && key)
     3475      ? db.prepare('SELECT kind FROM ap_my_reactions WHERE site_slug = ? AND target_uri = ?').all(slug, key)
    34493476      : [];
    34503477    return { liked: rows.some((r) => r.kind === 'like'), boosted: rows.some((r) => r.kind === 'boost') };
     
    34783505export function setReaction(slug, uri, kind, on, opts = {}) {
    34793506  if (!slug || !uri || (kind !== 'like' && kind !== 'boost')) return;
    3480   setMyReaction(slug, uri, kind, !!on);
    3481   const flagUri = opts.flagUri || uri;
     3507  // EEN sleutel voor beide bronnen. opts.flagUri is de opgeloste object-URI van
     3508  // de aanroeper (het C2S-pad kent die uit resolveRemoteNote en dat is
     3509  // betrouwbaarder dan onze cache); anders leiden we hem af. Vroeger kreeg de
     3510  // tussentabel de URI die de client stuurde en de vlag de opgeloste -- dat
     3511  // maakte dezelfde like onvindbaar vanaf de andere pagina.
     3512  const flagUri = opts.flagUri || canonicalReactionUri(slug, uri);
     3513  setMyReaction(slug, flagUri, kind, !!on);
    34823514  if (kind === 'boost') {
    34833515    if (!on) unmarkBoosted(slug, flagUri);
     
    48564888  gateOutgoingFollow, performApprovedFollow,
    48574889  parseOwnPoll, pollTally, ownPollView, deliverPollUpdate, maybeCrawlThread, sendReport, localMentionSlugs,
    4858   autoBoostCount, boostedCount, setReaction, getReaction, getReactionsFor, upsertBoostedNote, getCirkelPosts, getCirkelMembers, selfHealTimeline,
     4890  autoBoostCount, boostedCount, setReaction, getReaction, getReactionsFor, canonicalReactionUri, upsertBoostedNote, getCirkelPosts, getCirkelMembers, selfHealTimeline,
    48594891  getNotifications, listBlocks, isBlockedAny, blockTarget, unblock,
    48604892  deliverWithRetry, enqueueDelivery, processDeliveryQueue, startDeliveryWorker,
Note: See TracChangeset for help on using the changeset viewer.