;; lib/mod/temporal.sx — burst detection over a time window.
;;
;; A plain report count can't tell a burst (N reports in minutes) from slow
;; accumulation (N reports over months). mod/decide-temporal takes a `now` tick
;; and a `window`, counts reports about the subject with :at within [now-window,
;; now], asserts it as burst_count/2, and lets a `(:burst-at-least K)` rule fire
;; only on a genuine burst. Time is supplied (deterministic), never clock-read.

(define
  mod/window-count
  (fn
    (subject reports now window)
    (reduce
      (fn
        (acc r)
        (if
          (if
            (= (mod/report-about r) subject)
            (<= (- now window) (mod/report-at r))
            false)
          (+ acc 1)
          acc))
      0
      reports)))

(define
  mod/build-temporal-program
  (fn
    (r count bcount rules)
    (str
      (mod/report-facts r count)
      "\n"
      "burst_count("
      (mod/pl-quote (mod/report-about r))
      ", "
      bcount
      ").\n"
      (mod/rules->program rules))))

(define
  mod/decide-temporal
  (fn
    (r reports rules now window)
    (let
      ((about (mod/report-about r))
        (id (mod/report-id r))
        (kinds (mod/classify-keywords r)))
      (let
        ((count (mod/report-count about reports))
          (bcount (mod/window-count about reports now window)))
        (let
          ((program (mod/build-temporal-program r count bcount rules)))
          (let
            ((db (pl-load program)))
            (let
              ((sol (pl-query-one db (str "policy_action(" id ", Action, Rule)"))))
              (if
                (nil? sol)
                {:action "keep" :proof {:burst bcount :goals (list) :evidence kinds :conditions (list) :rule "none" :count count} :report-id id :rule "none" :strategy "temporal"}
                (let
                  ((rule (mod/find-rule rules (dict-get sol "Rule"))))
                  {:action (mod/rule-action rule) :proof {:burst bcount :goals (mod/proof-goals db id (mod/rule-when rule)) :evidence kinds :conditions (mod/rule-when rule) :rule (mod/rule-name rule) :count count} :report-id id :rule (mod/rule-name rule) :strategy "temporal"})))))))))
