                      transitions))))
 
 (defn enter-state [has ha state now]
+  (println "enter state" (keys has) (:id ha) state now)
   (let [now (floor-time now time-unit)
+        _ (assert (>= now (:entry-time ha)) "Time must be monotonic")
         ; set the current state to this state
         ; set ha's entry-time to the current moment
         ha (assoc (extrapolate ha now) :entry-time now

      ; we prioritize the first-defined optional transition. this policy could change later, e.g. to be an error.
      (first opts))))

(defn ha-dependencies [_ha] #{})

(defn follow-transitions [has transitions]
  (let [t (first (:interval (first transitions)))
        _ (assert (every? #(= t (first (:interval %))) transitions) "All transitions must have same start time")
        ; simultaneously transition all the HAs that can transition.
        transitioned-has (map (fn [{id :id {target :target update :update} :transition}]
                                (enter-state has (update (get has id)) target t))
                              transitions)
        transitioned-ids (into #{} (map :id transitioned-has))

             ;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
