               rel)
         ; t REL rhs
         entry-time (:entry-time ha)
+        ; _ (println (:id ha) simple-guard "et" entry-time "push up" time-unit rhs "to" (+ entry-time time-unit) (+ entry-time rhs))
         min-t (+ entry-time time-unit)
         rhs (+ entry-time rhs)]
     (assert (not (nil? v10))
             "V1 must be a valid variable reference")
     (assert (not (nil? v20))
             "V2 must be a valid variable reference")
-    (assert (and (not= rhs -Infinity)
-                 (not= rhs Infinity)
-                 (not (js/Number.isNaN rhs)))
-            "RHS was not a valid number. How?")
-    ; if t is bounded from above by a number less than time-unit...
-    (if (and (< rhs min-t)
-             (#{:lt :leq} rel))
-      ;return an interval which will become empty during intersection
-      [-Infinity rhs]
-      ; being bounded from above by a number less than time-unit is no problem. all intervals are open.
-      (case rel
-        ;  < : t  < rhs --> guard is true until t exceeds rhs
-        :lt [min-t (- rhs (/ time-unit 16))]
-        ; <= : t <= rhs --> guard is true until t exceeds or equals rhs
-        :leq [min-t rhs]
-        ; >= : t >= rhs --> guard becomes true once t exceeds or equals rhs
-        :geq [(.max js/Math rhs min-t) Infinity]
-        ;  > : t  > rhs --> guard becomes true once t exceeds rhs
-        :gt [(.max js/Math (+ rhs (/ time-unit 16)) min-t) Infinity]))))
+    (cond
+      ;if RHS is +-infinity, then the guard will never flip truth value
+      (or (= rhs Infinity) (= rhs -Infinity)) (if (guard-satisfied? rel v10 v20 c)
+                                                [-Infinity Infinity]
+                                                [Infinity Infinity])
+      ; if t is bounded from above by a number less than time-unit, return an interval which will become empty during intersection
+      (and (< rhs min-t) (#{:lt :leq} rel)) [-Infinity rhs]
+      ; being bounded from below by a number less than time-unit is no problem. all intervals are open.
+      :else (case rel
+              ;  < : t  < rhs --> guard is true until t exceeds rhs
+              :lt [min-t (- rhs (/ time-unit 16))]
+              ; <= : t <= rhs --> guard is true until t exceeds or equals rhs
+              :leq [min-t rhs]
+              ; >= : t >= rhs --> guard becomes true once t exceeds or equals rhs
+              :geq [(.max js/Math rhs min-t) Infinity]
+              ;  > : t  > rhs --> guard becomes true once t exceeds rhs
+              :gt [(.max js/Math (+ rhs (/ time-unit 16)) min-t) Infinity])
+      )))
 
 (defn transition-interval [has ha transition]
-  ; TODO: handle cases where transition is also guarded on states
-  {:interval   (intersect-all (map #(simple-interval has ha %) (:guard transition)))
-   :id         (:id ha)
-   :transition transition})
-
-(defn extrapolate [ha now]
-  (let [req (:next-required-transition ha)
-        ;_ (assert (or (nil? req) (<= now (first (:interval req)))) "Extrapolating beyond next transition of HA")
-        s (:state ha)
-        flows (:flows (get ha s))
-        delta (- now (:entry-time ha))
-        new-vals (map (fn [[variable flow]]
-                        [variable (+ (get ha variable) (* flow delta))])
-                      flows)]
-    (merge ha (into {} new-vals))))
+  ;(println "Transition" (:id ha) (:x ha) (:target transition) (:guard transition))
+  (let [intervals (map #(simple-interval has ha %) (:guard transition))
+        interval (intersect-all intervals)]
+    ; (println "interval:" intervals "->" interval)
+    ; TODO: handle cases where transition is also guarded on states
+    {:interval   interval
+     :id         (:id ha)
+     :transition transition}))
 
 (defn required-transitions [ha]
   (filter #(:required (:label %)) (:edges (current-state ha))))

             :right                                         ;name
             {:x speed}                                     ;flows
             ;edges
             ; x < 16 && x + dx*frame >= 16 --> x >= 16 - dx*frame
             (make-edge :left [[:lt :x 64] [:geq :x '(- 64 [:d :x])]] #{:required})
             ; x + 16 < x2 + dx2*frame && x + dx*frame + 16 >= x2 + dx2*frame
             ; x - x2 < -16 + dx2*frame && x - x2 >= dx2*frame - dx*frame - 16
             (map #(make-edge :left [[:lt :x [% :x] (list '+ -16 [:d % :x])]
                                     [:geq :x [% :x] (list '- [:d % :x] [:d :x] 16)]]
                              #{:required}) others))
           (make-state

             ;edges
             ; x > 8 && x + dx*frame <= 8 --> x <= 8 - dx*frame
             (make-edge :right [[:gt :x 8] [:leq :x '(- 8 [:d :x])]] #{:required})
             ; x > x2 + 16 && x + dx*frame <= x2 + dx2*frame + 16 --> x - x2 > 16 + dx2 && x - x2 <= dx2*frame + 16 - dx*frame
             ; x - x2 > 16
             (map #(make-edge :right [[:gt :x [% :x] 16]
                                      [:leq :x [% :x] (list '+ [:d % :x] 16 (list '- [:d :x]))]]
                              #{:required}) others))))

(defn make-scene-a [x] (let [objects [(goomba :a x 8 8 :right #{:b}) (goomba :b (+ x 18) 8 8 :left #{:a})]
                             obj-ids (map :id objects)
                             obj-dict (zipmap obj-ids objects)
                             ; got to let every HA enter its current (initial) state to set up state invariants like
