; Phase 6 — federation: shared content-addressed cache, trust gating, invalidation.

(define fed-BASE (artdag/op-table-runner {:in (fn (params inputs) (get params :v)) :add (fn (params inputs) (+ (nth inputs 0) (nth inputs 1))) :inc (fn (params inputs) (+ 1 (first inputs)))}))

(define
  fed-D
  (artdag/build
    (list
      (list "p" "in" (list) {:v 10})
      (list "q" "in" (list) {:v 20})
      (list "b" "inc" (list "p") {})
      (list "c" "inc" (list "q") {})
      (list "d" "add" (list "b" "c") {} true))))

(define fed-trust-A (fn (p) (= p "A")))
(define fed-trust-none (fn (p) false))

; a warmed instance A and its export bundle (origin peer "A").
(define fed-A (artdag/fed-open))
(define fed-warm (artdag/fed-run fed-A fed-D fed-BASE))
(define fed-bundle (artdag/fed-export fed-A "A"))

; ---- export ----

(artdag-test
  "export: bundle covers every cached node"
  (len fed-bundle)
  5)

; ---- remote cache hit ----

(artdag-test
  "trusted import enables remote cache hit (no recompute)"
  (artdag/recompute-count
    (artdag/fed-run
      (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A)
      fed-D
      fed-BASE))
  0)

(artdag-test
  "trusted import: every node is a hit"
  (artdag/hit-count
    (artdag/fed-run
      (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A)
      fed-D
      fed-BASE))
  5)

(artdag-test
  "remote hit yields correct result"
  (artdag/result-of
    (artdag/fed-run
      (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A)
      fed-D
      fed-BASE)
    (artdag/dag-id fed-D "d"))
  32)

; ---- trust gating ----

(artdag-test
  "untrusted peer is rejected (recompute everything)"
  (artdag/recompute-count
    (artdag/fed-run
      (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-none)
      fed-D
      fed-BASE))
  5)

(artdag-test
  "trust gating: untrusted records never enter the cache"
  (let
    ((B (artdag/fed-import (artdag/fed-open) (cons {:peer "C" :cid "node:foreign" :result 99} fed-bundle) fed-trust-A)))
    (persist/kv-has? (artdag/fed-cache B) "node:foreign"))
  false)

(artdag-test
  "trust gating: trusted records still admitted alongside rejected"
  (let
    ((B (artdag/fed-import (artdag/fed-open) (cons {:peer "C" :cid "node:foreign" :result 99} fed-bundle) fed-trust-A)))
    (persist/kv-has? (artdag/fed-cache B) (artdag/dag-id fed-D "d")))
  true)

; ---- provenance ----

(artdag-test
  "provenance is recorded for imported results"
  (get
    (artdag/fed-prov
      (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A))
    (artdag/dag-id fed-D "d"))
  "A")

(artdag-test
  "locally computed results carry no provenance"
  (len (keys (artdag/fed-prov fed-A)))
  0)

; ---- injected transport ----

(artdag-test
  "fed-pull imports via an injected fetch transport"
  (artdag/recompute-count
    (artdag/fed-run
      (artdag/fed-pull
        (artdag/fed-open)
        (fn (peer) fed-bundle)
        "A"
        fed-trust-A)
      fed-D
      fed-BASE))
  0)

; ---- invalidation ----

(artdag-test
  "invalidation drops a peer's results (recompute again)"
  (let
    ((B (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A)))
    (artdag/recompute-count
      (artdag/fed-run (artdag/fed-invalidate B "A") fed-D fed-BASE)))
  5)

(artdag-test
  "invalidation: recomputed result still correct"
  (let
    ((B (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A)))
    (artdag/result-of
      (artdag/fed-run (artdag/fed-invalidate B "A") fed-D fed-BASE)
      (artdag/dag-id fed-D "d")))
  32)

(artdag-test
  "invalidation: provenance map is cleared for that peer"
  (let
    ((B (artdag/fed-import (artdag/fed-open) fed-bundle fed-trust-A)))
    (len (keys (artdag/fed-prov (artdag/fed-invalidate B "A")))))
  0)

(artdag-test
  "invalidation is peer-scoped: other peers' results survive"
  (let
    ((B (artdag/fed-import (artdag/fed-open) (cons {:peer "C" :cid "node:fromC" :result 7} fed-bundle) (fn (p) true))))
    (persist/kv-has?
      (artdag/fed-cache (artdag/fed-invalidate B "A"))
      "node:fromC"))
  true)

(artdag-test
  "invalidation is peer-scoped: target peer's results removed"
  (let
    ((B (artdag/fed-import (artdag/fed-open) (cons {:peer "C" :cid "node:fromC" :result 7} fed-bundle) (fn (p) true))))
    (persist/kv-has?
      (artdag/fed-cache (artdag/fed-invalidate B "A"))
      (artdag/dag-id fed-D "d")))
  false)
