;; lib/mod/explain.sx — human-readable proof explanation.
;;
;; Turns a decision (from mod/decide-report, or any audit entry) into a readable
;; multi-line "why": the action, the rule that fired, the evidence in play, and
;; the derivation goal-by-goal with [proved]/[unproved] marks and the unification
;; bindings that satisfied each goal. Pure SX over the Phase-2 proof tree.

(define
  mod/explain-binds
  (fn
    (binds)
    (mod/join-with
      ", "
      (map (fn (k) (str k "=" (dict-get binds k))) (keys binds)))))

(define
  mod/explain-goal
  (fn
    (g)
    (let
      ((mark (if (get g :solved) "  [proved] " "  [unproved] "))
        (binds (get g :bindings)))
      (if
        (empty? (keys binds))
        (str mark (get g :goal))
        (str mark (get g :goal) "  {" (mod/explain-binds binds) "}")))))

(define
  mod/explain-evidence
  (fn
    (evidence)
    (if
      (empty? evidence)
      "Evidence: (none)"
      (str "Evidence: " (mod/join-with ", " evidence)))))

(define
  mod/explain
  (fn
    (decision)
    (let
      ((id (get decision :report-id))
        (action (get decision :action))
        (rule (get decision :rule))
        (proof (get decision :proof)))
      (let
        ((goals (get proof :goals)) (evidence (get proof :evidence)))
        (mod/join-with
          "\n"
          (append
            (list
              (str "Report " id ": " action " (rule: " rule ")")
              (mod/explain-evidence evidence)
              "Because:")
            (map mod/explain-goal goals)))))))
