; feed/dedupe — collapse duplicate items, keeping first occurrence per key. ; Each verb may want its own key (see briefing): "alice posted X" keys on ; (actor verb object) — distinct per actor; "alice liked X / bob liked X" ; collapse on (verb object) so the cross-actor likes fold into one. ; ; Requires: lib/feed/normalize.sx, lib/feed/stream.sx, lib/feed/fanout.sx ; (feed/-elem? lives in fanout.sx). ; generic: dedupe a stream by key-fn, first occurrence wins (stable) (define feed/-dedup-by (fn (items key-fn) (get (reduce (fn (st x) (let ((k (key-fn x))) (if (feed/-elem? k (get st :seen)) st {:seen (append (get st :seen) (list k)) :out (append (get st :out) (list x))}))) {:seen (list) :out (list)} items) :out))) (define feed/dedupe (fn (stream key-fn) (feed/stream (feed/-dedup-by (feed/items stream) key-fn)))) ; --- keys ------------------------------------------------------------------- (define feed/activity-key (fn (a) (list (get a :actor) (get a :verb) (get a :object)))) ; collapse cross-actor duplicates of the same verb+object (e.g. likes) (define feed/collapse-key (fn (a) (list (get a :verb) (get a :object)))) ; per-receiver inbox key — one inbox event per (receiver, actor, verb, object) (define feed/event-key (fn (ev) (let ((a (get ev :activity))) (list (get ev :to) (get a :actor) (get a :verb) (get a :object))))) ; verbs whose duplicates collapse across actors (reactions, not authorship). ; rebindable: callers can (set! feed/collapse-verbs ...) to tune the policy. (define feed/collapse-verbs (list "like" "favourite" "follow" "boost" "repost")) ; per-verb key: collapse-verbs fold on (verb object); the rest key on ; (actor verb object). (define feed/smart-key (fn (a) (if (feed/-elem? (get a :verb) feed/collapse-verbs) (feed/collapse-key a) (feed/activity-key a)))) ; --- ready-made dedupers ---------------------------------------------------- (define feed/dedupe-activities (fn (s) (feed/dedupe s feed/activity-key))) (define feed/dedupe-collapse (fn (s) (feed/dedupe s feed/collapse-key))) ; verb-aware: reactions collapse cross-actor, posts stay distinct per actor (define feed/dedupe-smart (fn (s) (feed/dedupe s feed/smart-key))) ; dedupe an inbox: at most one event per receiver per (actor verb object) (define feed/dedupe-inbox (fn (inbox) (feed/dedupe inbox feed/event-key)))