Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
188 lines
4.7 KiB
Plaintext
188 lines
4.7 KiB
Plaintext
; Phase 2 — fanout via outer product + dedupe. (feed-test name got expected)
|
|
|
|
; ---------- graph ----------
|
|
|
|
; edges: (follower followee). bob,carol follow alice; carol,dave follow bob.
|
|
(define
|
|
G
|
|
(feed/follow-graph
|
|
(list
|
|
(list "bob" "alice")
|
|
(list "carol" "alice")
|
|
(list "carol" "bob")
|
|
(list "dave" "bob"))))
|
|
|
|
(feed-test "followers alice" (feed/followers G "alice") (list "bob" "carol"))
|
|
(feed-test "followers bob" (feed/followers G "bob") (list "carol" "dave"))
|
|
(feed-test "followers unknown" (feed/followers G "zzz") (list))
|
|
(feed-test "audience distinct" (feed/audience G) (list "bob" "carol" "dave"))
|
|
|
|
; ---------- fanout ----------
|
|
|
|
(define
|
|
S
|
|
(feed/stream
|
|
(list
|
|
(feed/activity "alice" "post" "p1" 10 (list))
|
|
(feed/activity "alice" "post" "p2" 20 (list))
|
|
(feed/activity "bob" "like" "p1" 30 (list)))))
|
|
|
|
(define IB (feed/fanout S G))
|
|
|
|
(feed-test "fanout total edges" (feed/count IB) 6)
|
|
(feed-test
|
|
"inbox bob count"
|
|
(feed/count (feed/inbox-for IB "bob"))
|
|
2)
|
|
(feed-test
|
|
"inbox carol count"
|
|
(feed/count (feed/inbox-for IB "carol"))
|
|
3)
|
|
(feed-test
|
|
"inbox dave count"
|
|
(feed/count (feed/inbox-for IB "dave"))
|
|
1)
|
|
(feed-test
|
|
"inbox alice (follows none)"
|
|
(feed/count (feed/inbox-for IB "alice"))
|
|
0)
|
|
(feed-test
|
|
"recipients order"
|
|
(feed/recipients IB)
|
|
(list "bob" "carol" "dave"))
|
|
(feed-test
|
|
"bob inbox objects"
|
|
(map (fn (a) (get a :object)) (feed/inbox-activities IB "bob"))
|
|
(list "p1" "p2"))
|
|
(feed-test
|
|
"dave inbox objects"
|
|
(map (fn (a) (get a :object)) (feed/inbox-activities IB "dave"))
|
|
(list "p1"))
|
|
(feed-test
|
|
"dave inbox verb"
|
|
(map (fn (a) (get a :verb)) (feed/inbox-activities IB "dave"))
|
|
(list "like"))
|
|
|
|
; empty graph → no audience → no edges
|
|
(feed-test
|
|
"empty graph fanout"
|
|
(feed/count (feed/fanout S {}))
|
|
0)
|
|
|
|
; actor nobody follows produces no edges
|
|
(define
|
|
Sghost
|
|
(feed/stream (list (feed/activity "ghost" "post" "g1" 5 (list)))))
|
|
(feed-test
|
|
"unfollowed actor fanout"
|
|
(feed/count (feed/fanout Sghost G))
|
|
0)
|
|
|
|
; ---------- high fanout (popular actor) ----------
|
|
|
|
(define
|
|
Gstar
|
|
(feed/follow-graph
|
|
(list
|
|
(list "u1" "star")
|
|
(list "u2" "star")
|
|
(list "u3" "star")
|
|
(list "u4" "star")
|
|
(list "u5" "star"))))
|
|
(define
|
|
Sstar
|
|
(feed/stream (list (feed/activity "star" "post" "s1" 1 (list)))))
|
|
(feed-test
|
|
"star fanout count"
|
|
(feed/count (feed/fanout Sstar Gstar))
|
|
5)
|
|
(feed-test "star audience size" (len (feed/audience Gstar)) 5)
|
|
|
|
; ---------- mutual follow ----------
|
|
|
|
(define Gmut (feed/follow-graph (list (list "a" "b") (list "b" "a"))))
|
|
(define
|
|
Smut
|
|
(feed/stream
|
|
(list
|
|
(feed/activity "a" "post" "pa" 1 (list))
|
|
(feed/activity "b" "post" "pb" 2 (list)))))
|
|
(define IBmut (feed/fanout Smut Gmut))
|
|
(feed-test "mutual total" (feed/count IBmut) 2)
|
|
(feed-test
|
|
"mutual a gets pb"
|
|
(map (fn (x) (get x :object)) (feed/inbox-activities IBmut "a"))
|
|
(list "pb"))
|
|
(feed-test
|
|
"mutual b gets pa"
|
|
(map (fn (x) (get x :object)) (feed/inbox-activities IBmut "b"))
|
|
(list "pa"))
|
|
|
|
; ---------- dedupe ----------
|
|
|
|
(define
|
|
Sdup2
|
|
(feed/stream
|
|
(list
|
|
(feed/activity "alice" "post" "p1" 1 (list))
|
|
(feed/activity "alice" "post" "p1" 9 (list))
|
|
(feed/activity "alice" "post" "p2" 2 (list)))))
|
|
(feed-test
|
|
"dedupe-activities collapses dup"
|
|
(feed/count (feed/dedupe-activities Sdup2))
|
|
2)
|
|
(feed-test
|
|
"dedupe-activities keeps distinct"
|
|
(map
|
|
(fn (a) (get a :object))
|
|
(feed/items (feed/dedupe-activities Sdup2)))
|
|
(list "p1" "p2"))
|
|
|
|
(define
|
|
Slikes
|
|
(feed/stream
|
|
(list
|
|
(feed/activity "alice" "like" "X" 1 (list))
|
|
(feed/activity "bob" "like" "X" 2 (list))
|
|
(feed/activity "carol" "like" "Y" 3 (list)))))
|
|
(feed-test
|
|
"collapse cross-actor likes"
|
|
(feed/count (feed/dedupe-collapse Slikes))
|
|
2)
|
|
(feed-test
|
|
"collapse keeps distinct objects"
|
|
(map
|
|
(fn (a) (get a :object))
|
|
(feed/items (feed/dedupe-collapse Slikes)))
|
|
(list "X" "Y"))
|
|
|
|
(feed-test
|
|
"activity-key shape"
|
|
(feed/activity-key (feed/activity "a" "post" "o" 0 (list)))
|
|
(list "a" "post" "o"))
|
|
(feed-test
|
|
"collapse-key shape"
|
|
(feed/collapse-key (feed/activity "a" "like" "o" 0 (list)))
|
|
(list "like" "o"))
|
|
|
|
; cross-post: alice posts p1 twice → bob's inbox has it twice → dedupe-inbox → once
|
|
(define
|
|
Scross
|
|
(feed/stream
|
|
(list
|
|
(feed/activity "alice" "post" "p1" 1 (list))
|
|
(feed/activity "alice" "post" "p1" 5 (list)))))
|
|
(define IBcross (feed/fanout Scross G))
|
|
(feed-test
|
|
"cross-post raw bob count"
|
|
(feed/count (feed/inbox-for IBcross "bob"))
|
|
2)
|
|
(feed-test
|
|
"cross-post deduped bob count"
|
|
(feed/count (feed/inbox-for (feed/dedupe-inbox IBcross) "bob"))
|
|
1)
|
|
(feed-test
|
|
"dedupe-inbox keeps distinct receivers"
|
|
(feed/count (feed/dedupe-inbox IBcross))
|
|
2)
|