; feed/acl — per-viewer visibility filtering. The same candidate stream yields
; different timelines for different viewers, so ACL is applied per request and
; pre-ACL timelines are never cached.
;
; permit? is injected: (permit? viewer activity) -> bool. Wire a real acl-sx
; predicate here; feed/permit-acl? is a self-contained default that reads an
; optional :visible-to allowlist on the activity.
;
; Requires: lib/feed/normalize.sx, lib/feed/stream.sx, lib/feed/fanout.sx
; (feed/-elem?), lib/feed/rank.sx (feed/top).

; default permit: actor always sees own activity; absent/nil :visible-to is
; public; otherwise viewer must be in the allowlist.
(define
  feed/permit-acl?
  (fn
    (viewer a)
    (or
      (equal? viewer (get a :actor))
      (let
        ((allowed (get a :visible-to nil)))
        (if (= allowed nil) true (feed/-elem? viewer allowed))))))

(define feed/permit-public? (fn (viewer a) true))

; filter a stream to what viewer may read
(define
  feed/visible
  (fn
    (stream viewer permit?)
    (feed/filter stream (fn (a) (permit? viewer a)))))

; the capstone: candidate stream -> ACL for viewer -> rank -> top-N
(define
  feed/timeline
  (fn
    (stream viewer permit? score-fn n)
    (feed/top (feed/visible stream viewer permit?) score-fn n)))
