; lib/artdag/federation.sx — Phase 6: shared content-addressed cache across
; instances (the L2-registry analog). Because content-ids are global, a result
; computed on one instance is reusable on another by id. Imports are trust-gated
; and carry provenance so a peer's results can be invalidated when trust is
; withdrawn. Transport is injected (mock in tests). Depends on dag.sx, execute.sx
; (the cache is a lib/persist/ kv backend) — federation tracks provenance beside it.

; an instance: a persist kv cache + a provenance map {cid -> origin-peer}.
(define artdag/fed-open (fn () {:cache (persist/open) :prov {}}))
(define artdag/fed-cache (fn (fed) (get fed :cache)))
(define artdag/fed-prov (fn (fed) (get fed :prov)))

(define
  artdag/-dict-remove
  (fn
    (d key)
    (reduce
      (fn (acc k) (if (= k key) acc (assoc acc k (get d k))))
      {}
      (keys d))))

; export every cached result as a bundle of {:cid :result :peer}, tagged with
; the exporting instance's peer id (the result's origin/provenance).
(define
  artdag/fed-export
  (fn
    (fed peer-id)
    (map (fn (cid) {:peer peer-id :cid cid :result (persist/kv-get (get fed :cache) cid)}) (persist/kv-keys (get fed :cache)))))

; import a bundle, accepting only records from trusted peers (trust gating) and
; recording each accepted result's provenance. Returns the updated instance.
(define
  artdag/fed-import
  (fn
    (fed bundle trusted?)
    (reduce
      (fn
        (f rec)
        (if
          (trusted? (get rec :peer))
          (begin
            (persist/kv-put (get f :cache) (get rec :cid) (get rec :result))
            {:cache (get f :cache) :prov (assoc (get f :prov) (get rec :cid) (get rec :peer))})
          f))
      fed
      bundle)))

; pull from a peer through an injected transport (fetch-fn peer-id -> bundle).
(define
  artdag/fed-pull
  (fn
    (fed fetch-fn peer-id trusted?)
    (artdag/fed-import fed (fetch-fn peer-id) trusted?)))

; invalidate: drop every cached result provenanced to a peer (trust withdrawn),
; from both the cache and the provenance map. Locally-computed results (no
; provenance) are untouched. Returns the updated instance.
(define
  artdag/fed-invalidate
  (fn
    (fed peer-id)
    (reduce
      (fn
        (f cid)
        (if
          (= (get (get f :prov) cid) peer-id)
          (begin (persist/kv-delete (get f :cache) cid) {:cache (get f :cache) :prov (artdag/-dict-remove (get f :prov) cid)})
          f))
      fed
      (keys (get fed :prov)))))

; convenience: run a dag against an instance's cache.
(define
  artdag/fed-run
  (fn (fed dag runner) (artdag/run dag runner (artdag/fed-cache fed))))
