; persist/examples/acl — a WORKED MIGRATION REFERENCE. A subsystem (acl grants:
; who may access what) currently hand-rolls an in-memory mutable map that loses
; every grant on restart and keeps no audit trail. This shows the same subsystem
; rebuilt on persist. It is the template other subsystem loops copy; it does NOT
; touch the real lib/acl (out of this loop's scope).
;
; BEFORE — hand-rolled, ephemeral, no history, no concurrency safety:
;   (define acl-grants {})                      ; resource -> principal list (mutable)
;   (define acl-grant!  (fn (r p) (set! acl-grants (assoc acl-grants r (cons p (get acl-grants r))))))
;   (define acl-revoke! (fn (r p) (set! acl-grants (assoc acl-grants r (remove p ...)))))
;   (define acl-can?    (fn (r p) (contains? (get acl-grants r) p)))
;   ;; vanishes on restart; "when/why was X granted?" is unanswerable.
;
; AFTER — on persist. Grants/revokes are EVENTS (history matters), the current
; grant set is a PROJECTION, checks read a materialized VIEW, and the audit trail
; is a time-windowed query. Every fn takes a backend `b`, so the same code runs
; on the in-memory backend today and the durable backend unchanged.
; Requires: lib/persist/log.sx, lib/persist/project.sx, lib/persist/view.sx,
;           lib/persist/query.sx.

(define acl/stream (fn (resource) (str "acl/" resource)))

; write side — grant/revoke append events (the history is the source of truth)
(define
  acl/grant
  (fn
    (b resource principal at)
    (persist/append b (acl/stream resource) "granted" at {:principal principal})))
(define
  acl/revoke
  (fn
    (b resource principal at)
    (persist/append b (acl/stream resource) "revoked" at {:principal principal})))

; fold step: grant adds a principal (once), revoke removes it
(define
  acl/step
  (fn
    (set e)
    (let
      ((p (get (persist/event-data e) :principal)))
      (if
        (equal? (persist/event-type e) "granted")
        (if (contains? set p) set (append set p))
        (filter (fn (x) (not (equal? x p))) set)))))

; read side — current grant set + membership check (replays the log)
(define
  acl/grants
  (fn
    (b resource)
    (persist/project-fold b (acl/stream resource) acl/step (list))))
(define
  acl/can?
  (fn (b resource principal) (contains? (acl/grants b resource) principal)))

; materialized view — attach to a hub for O(1) checks that stay current on write
(define
  acl/view
  (fn
    (resource)
    (persist/view
      (str "acl-current/" resource)
      (acl/stream resource)
      acl/step
      (list))))
(define
  acl/can-fast?
  (fn
    (b resource principal)
    (contains? (persist/view-peek b (acl/view resource)) principal)))

; audit — grants/revokes for a resource in a time window (the new capability the
; hand-rolled version could never answer)
(define
  acl/audit-window
  (fn
    (b resource from to)
    (persist/read-window b (acl/stream resource) from to)))
