   "Repeatedly refine plans stored at this osn or below."
   [osn min-reward excluded-child-set subproblem output-set]
   (operate-on-best
-   :status    :plans                     #(refine-osn-plan osn %1 %2 subproblem output-set)
-   osp-status #(remove excluded-child-set (:child-pointers %)) #(do (refine-osp! %1 %2) %1)
+   :summary    :plans                     #(refine-osn-plan osn %1 %2 subproblem output-set)
+   full-osp-summary #(remove excluded-child-set (:child-pointers %)) #(do (refine-osp! %1 %2) %1)
    osn identity min-reward))
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Output Set Pointers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-(defrecord OutputSetPointer [subproblem parent-pointer output-set node-atom alt-status])
+(defprotocol OSP
+  (osp-summary [osp excluded-child-set])
+  (osp-output-set [osp]))
+
+(defn full-osp-summary [osp]
+  (osp-summary osp nil))
+
+(defrecord TerminalOutputSetPointer [summary output-set]
+  OSP
+  (osp-summary [osp ecs] (assert (empty? ecs)) summary)
+  (osp-output-set [osp] output-set))
+
+(def +worst-osp+ (TerminalOutputSetPointer. +worst-summary+ state-set/empty-lfss))
+
+(declare active-osp-summary)
+(defrecord OutputSetPointer [subproblem parent-pointer output-set node-atom alt-summary]
+  OSP
+  (osp-summary [osp ecs] (active-osp-summary osp ecs))
+  (osp-output-set [osp] output-set))
+
 
 (defn make-child-osp [parent-osp output-set plans]
-  (OutputSetPointer. (:subproblem parent-osp) parent-osp output-set (OutputSetNode. plans nil) +best-status+))
+  (OutputSetPointer. (:subproblem parent-osp) parent-osp output-set (OutputSetNode. plans nil) +best-summary+))
 
 (defn osp-ancestors [osp]
   (when-let [p (:parent-pointer osp)]
     (cons p (lazy-seq (osp-ancestors osp)))))
 
-(defn osp-plan-status [osp] (osn-plan-status @(:node-atom osp)))
-
-(defn osp-status [osp excluded-child-set]
-  (min-status (:alt-status osp)
-              (apply max-status
-                     (osn-status @(:node-atom osp) excluded-child-set)
-                     (map osn-plan-status (osp-ancestors osp)))))
+(defn osp-plan-summary [osp] (osn-plan-summary @(:node-atom osp)))
+
+(defn active-osp-summary [osp excluded-child-set]
+  (min-summary (:alt-summary osp)
+              (apply max-summary
+                     (osn-summary @(:node-atom osp) excluded-child-set)
+                     (map osn-plan-summary (osp-ancestors osp)))))
 
 (defn refine-osp!
   "Repeatedly refine an ancestor or descendent of this node."
   [osp min-reward excluded-child-set]
   (operate-on-best
-   osp-plan-status osp-ancestors refine-osp!
-   osp-status [osp] #(swap! (:node-atom osp) refined-osn %2 excluded-child-set (:subproblem osp) (:output-set osp))))
+   osp-plan-summary osp-ancestors refine-osp!
+   #(osp-summary % excluded-child-set) [osp] #(swap! (:node-atom osp) refined-osn %2 excluded-child-set (:subproblem osp) (:output-set osp))))
 
 (defn add-plans-osp!
   "Add plans from map and return map with them removed"
   [osp plans-by-output-set]
   (if-let [plans (get plans-by-output-set (:output-set osp))]
-    (do (swap! (:node-atom osp) update-in [:plans] concat plans)
+    (do (swap! (:node-atom osp) osn-add-plans plans)
         (dissoc plans-by-output-set (:output-set osp)))
     plans-by-output-set))
 
 (defn split-osp
   "Return new-child-osps.  Currently splits children < min-reward when parent >= min-reward."
   [osp min-reward excluded-child-set]
-  (when (> (:max-reward (osp-plan-status osp)) min-reward)
-    (filter #(<= (:max-reward (osp-status %)))
+  (when (> (max-reward (osp-plan-summary osp)) min-reward)
+    (filter #(<= (max-reward (full-osp-summary %)))
             (remove excluded-child-set
-                    (:child-pointers @(:node-atom osp))))))
+                    (osn-child-pointers @(:node-atom osp))))))
 
 
 
 ;;;;;;;;;;;;;;;;;;;;;;; Making and Splitting Subproblems ;;;;;;;;;;;;;;;;;;;;;;;
+
+;; TODO: terminal (solution) if concrete & primitive,
+;;       termianl (blocked) if primitive or cannot refine from current set.
+(defn make-subproblem [logged-input-set state-context action reward-bound-fn]
+  (let [prim?        (env/primitive? action)]
+    (if-let [s (and prim? (state-set/singleton logged-input-set))]
+      (if (env/applicable? action s)
+        (let [[ss rew] (env/successor action s)]
+          (TerminalOutputSetPointer.
+           (make-solved-summary rew [action])
+           (state-set/make-logging-factored-state-set [ss])))
+        +worst-osp+)
+      (let [[opt rew]    (angelic/optimistic-set-and-reward action logged-input-set)
+            rew          (min rew (reward-bound-fn))]
+        (if (or prim? (not (angelic/can-refine-from-set? action logged-input-set)))
+          (TerminalOutputSetPointer. (make-blocked-summary rew) opt)
+          (let [subproblem   (Subproblem. logged-input-set state-context action (HashMap.))
+                init-node    (make-initial-output-set-node logged-input-set action rew)
+                init-pointer (OutputSetPointer. subproblem nil opt (atom init-node) (make-blocked-summary rew))]
+;           (.put ^HashMap (:output-set-cache subproblem) opt init-pointer)
+            init-pointer))))))
+
 
 (defn get-subproblem-root-pointer [input-set action reward-bound-fn]
   (let [context (env/precondition-context action input-set)
         state-context (state/extract-context input-set context)]
     (util/cache-with *subproblem-cache* [state-context (env/action-name action)]
-      (let [logged-input (state/get-logger input-set context)
-            subproblem   (Subproblem. logged-input state-context action (HashMap.))
-            [opt rew]    (angelic/optimistic-set-and-reward action logged-input)
-            rew          (min rew (reward-bound-fn))
-            init-node    (make-initial-output-set-node logged-input action rew)
-            init-pointer (OutputSetPointer. subproblem nil opt (atom init-node) (Status. rew :blocked))]
-        (.put ^HashMap (:output-set-cache subproblem) opt init-pointer)
-        init-pointer))))
+      (make-subproblem (state/get-logger input-set context) state-context action reward-bound-fn))))
 
 (defn refine-osp-input [osp new-input-set]
   (let [root-osp         (-> osp osp-ancestors last)
         refined-root-osp (get-subproblem-root-pointer new-input-set (-> osp :subproblem :action)
-                                                      #(root-osp osp-status :max-reward))]
+                                                      #(-> root-osp full-osp-summary max-reward))]
     (if (identical? root-osp refined-root-osp)
       osp
       refined-root-osp)))
 
 
-;; TODO: where does old reward bound go?  Wrapped-osp?
-
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Plans ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
-(defrecord PlanNode [sub-output-set-pointer excluded-child-set output-constraint status-bound output-set output-status])
+(defrecord PlanNode [sub-output-set-pointer excluded-child-set output-constraint summary-bound output-set output-summary])
 
 (defn compute-plan-node-output-set [input-set sub-output-set-pointer output-constraint]
-  (state-set/constrain (state/transfer-effects input-set (:output-set sub-output-set-pointer)) output-constraint))
-
-(defn compute-plan-node-output-status [input-status sub-output-set-pointer status-bound]
-  (add-statuses input-status (min-status status-bound (osp-status sub-output-set-pointer))))
-
-(defn make-plan-node [input-set input-status sub-output-set-pointer excluded-child-set output-constraint status-bound]
-  (PlanNode. sub-output-set-pointer excluded-child-set output-constraint status-bound
+  (state-set/constrain (state/transfer-effects input-set (osp-output-set sub-output-set-pointer)) output-constraint))
+
+(defn compute-plan-node-output-summary [input-summary sub-output-set-pointer summary-bound]
+  (add-summaries input-summary (min-summary summary-bound (full-osp-summary sub-output-set-pointer))))
+
+(defn make-plan-node [input-set input-summary sub-output-set-pointer excluded-child-set output-constraint summary-bound]
+  (PlanNode. sub-output-set-pointer excluded-child-set output-constraint summary-bound
              (compute-plan-node-output-set input-set sub-output-set-pointer output-constraint)
-             (compute-plan-node-output-status input-status sub-output-set-pointer status-bound)))
-
-(defn make-initial-plan-node [action [input-set input-status]]
-  (let [sub (get-subproblem-root-pointer input-status action (constantly is/pos-inf))]
-    (make-plan-node input-set input-status sub #{} {} +best-status+)))
-
-
-(defn plan-node-output-set-and-status [pn]
-  [(:output-set pn) (:output-status pn)])
-
-(defn viable-output-set-and-status? [[set status]]
+             (compute-plan-node-output-summary input-summary sub-output-set-pointer summary-bound)))
+
+(defn make-initial-plan-node [action [input-set input-summary]]
+  (let [sub (get-subproblem-root-pointer input-set action (constantly is/pos-inf))]
+    (make-plan-node input-set input-summary sub #{} {} +best-summary+)))
+
+
+(defn plan-node-output-set-and-summary [pn]
+  [(:output-set pn) (:output-summary pn)])
+
+(defn viable-output-set-and-summary? [[set summary]]
   (and (not (state-set/empty? set))
-       (viable-status? status)))
-
-
-(defn refine-pn [pn input-status min-reward]
-  (let [{:keys [sub-output-set-pointer excluded-child-set status-bound]} pn]
+       (viable-summary? summary)))
+
+
+(defn refine-pn [pn input-summary min-reward]
+  (let [{:keys [sub-output-set-pointer excluded-child-set summary-bound]} pn]
     (refine-osp! sub-output-set-pointer min-reward excluded-child-set)
-    (assoc pn :output-status (compute-plan-node-output-status input-status sub-output-set-pointer status-bound))))
-
-
-(defn split-pn-output [pn input-set input-status min-step-reward]
+    (assoc pn :output-summary (compute-plan-node-output-summary input-summary sub-output-set-pointer summary-bound))))
+
+
+(defn split-pn-output [pn input-set input-summary min-step-reward]
   (let [{:keys [sub-output-set-pointer excluded-child-set]} pn]
     (let [split-children (split-osp sub-output-set-pointer min-step-reward excluded-child-set)
           new-ecs        (into excluded-child-set split-children)
-          new-status     (osp-status sub-output-set-pointer new-ecs)]
+          new-summary     (osp-summary sub-output-set-pointer new-ecs)]
       (concat
-       (when (viable-status? new-status) [(assoc pn :excluded-child-set new-ecs :output-status new-status)])
-       (for [child split-children] (make-plan-node input-set input-status child nil {} +best-status+))))))
-
-(defn patch-pn-status-tuple- [pn new-input-status]
-  (let [{:keys [sub-output-set-pointer status-bound output-set]} pn
-        new-output-status (compute-plan-node-output-status new-input-status sub-output-set-pointer status-bound)]
-    (when (viable-status? new-output-status)
-      [[false output-set new-output-status] (assoc pn :output-status new-output-status)])))
-
-
-(defn update-pn-input [[set-changed? new-input-set new-input-status] pn]
-  (let [{:keys [sub-output-set-pointer output-constraint status-bound output-set]} pn]
+       (when (viable-summary? new-summary) [(assoc pn :excluded-child-set new-ecs :output-summary new-summary)])
+       (for [child split-children] (make-plan-node input-set input-summary child nil {} +best-summary+))))))
+
+(defn patch-pn-summary-tuple- [pn new-input-summary]
+  (let [{:keys [sub-output-set-pointer summary-bound output-set]} pn
+        new-output-summary (compute-plan-node-output-summary new-input-summary sub-output-set-pointer summary-bound)]
+    (when (viable-summary? new-output-summary)
+      [[false output-set new-output-summary] (assoc pn :output-summary new-output-summary)])))
+
+
+(defn update-pn-input [[set-changed? new-input-set new-input-summary] pn]
+  (let [{:keys [sub-output-set-pointer output-constraint summary-bound output-set]} pn]
     (if set-changed?
       (let [new-osp (refine-osp-input sub-output-set-pointer new-input-set)]
         (if (identical? new-osp sub-output-set-pointer)
-          (patch-pn-status-tuple- pn new-input-status)
-          (let [new-pn (make-plan-node new-input-set new-input-status new-osp nil
-                                (:output-set sub-output-set-pointer)
-                                (Status. (:max-reward (osp-status sub-output-set-pointer)) :blocked))
-                new-output-pair (plan-node-output-set-and-status new-pn)]
-            (when (viable-output-set-and-status? new-output-pair)
+          (patch-pn-summary-tuple- pn new-input-summary)
+          (let [new-pn (make-plan-node new-input-set new-input-summary new-osp nil
+                                (osp-output-set sub-output-set-pointer)
+                                (make-blocked-summary (max-reward (full-osp-summary sub-output-set-pointer))))
+                new-output-pair (plan-node-output-set-and-summary new-pn)]
+            (when (viable-output-set-and-summary? new-output-pair)
               [(cons (not (= (:output-set new-pn) output-set)) new-output-pair) new-pn]))))      
-      (patch-pn-status-tuple- pn new-input-status))))
-
-
-
-
-(defrecord Plan     [input-constraint input-set plan-nodes output-set status])
+      (patch-pn-summary-tuple- pn new-input-summary))))
+
+
+
+
+(defrecord Plan     [input-constraint input-set plan-nodes output-set summary])
 
 (defn map-state
   "Transform a sequence via a state-machine.  transition-fn takes a state and input item,

        :blocked 1
        :solved  2))

(defrecord Status [max-reward status])


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Common Ops ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(def +worst-status+ (Status. is/neg-inf :live))
(def +best-status+  (Status. is/pos-inf :solved))

(defn better-status? [s1 s2]
  (or (> (:max-reward s1)
         (:max-reward s2))
      (and (= (:max-reward s1)

    (recur cf (if (cf f arg1) f arg1) r)
    arg1))

(defn max-summary [& stats] (apply max-compare better-summary? (cons +worst-summary+ stats) ))
(defn min-summary [& stats] (apply max-compare (complement better-summary?) (cons +best-summary+ stats)))

(def zero-summary (SimpleSummary. 0 :solved []))
(defn add-summaries [s1 s2]
  (SimpleSummary. (+ (:max-reward s1)
              (:max-reward s2))
           (min-key status-val (:status s1) (:status s2))
           (when (and (= (:status s1) :solved) (= (:status s2) :solved))
             (concat (:opt-sol s1) (:opt-sol s2)))))


(defn viable-summary? [summary]
  (> (:max-reward summary) is/neg-inf))

(defn refinable-summary? [stat min-reward]
  (and (= (:status stat) :live)
       (>= (:max-reward stat) min-reward)))

(defn summary-solution [stat]
  (when (= (:status stat) :solved)
    (:opt-sol stat)))


(defn next-min-reward [stat min-reward]
  (min min-reward (:max-reward stat)))



(defn max-thing-summary-and-next [summary-fn & things]
  (if (empty? things)
    [nil +worst-summary+ +worst-summary+]
    (loop [best-thing (first things)
           best-summary (summary-fn (first things))
           next-best-summary +worst-summary+
           more-things (rest things)]
      (if-let [[next-thing & even-more-things] (seq more-things)]
        (let [next-summary (summary-fn next-thing)]
          (if (better-summary? next-summary best-summary)
            (recur next-thing next-summary best-summary even-more-things)
            (recur best-thing best-summary (max-summary next-summary next-best-summary) even-more-things)))))))

(defn one-operation-on-best [summary-fn1 s1 op1 summary-fn2 s2 op2 min-reward default]
  (let [[best1 summary1 ns1] (max-thing-summary-and-next summary-fn1 s1)
        [best2 summary2 ns2] (max-thing-summary-and-next summary-fn2 s2)
        best-summary     (max-summary summary1 summary2)]
    (if (not (refinable-summary? best-summary min-reward))
      default
      (if (better-summary? summary2 summary1)
        (op2 best2 (next-min-reward (max-summary ns2 summary1) min-reward))
        (op1 best1 (next-min-reward (max-summary ns1 summary2) min-reward))))))

(defn operate-on-best [summary-fn1 seq-fn1 op1 summary-fn2 seq-fn2 op2 init next-fn min-reward]
  (last
   (util/iterate-while
    #(when-let [x (one-operation-on-best summary-fn1 (seq-fn1 %) op1 summary-fn2 (seq-fn2 %) op2 min-reward nil)]
       (next-fn x))
    init)))

