       (fn [block]
         (gen/fmap
           (fn [positions]
-            (vec (cons (:id block) (sort positions))))
+            (let [[start end] (sort positions)]
+              {:id (:id block)
+               :start start
+               :end end}))
           (gen/vector-distinct
             (gen/large-integer* {:min 0, :max (:size block)})
             {:num-elements 2})))))
 
-  (apply
-    [store [id start end]]
+  (apply-op
+    [this store]
     (when-let [block (block/get store id)]
       (let [baos (java.io.ByteArrayOutputStream.)]
         (with-open [content (block/open block start end)]




;; ## Operation Multimethods

(defmulti ^:private apply-op
  "Apply the operation to the store, returning a result value."
  (fn dispatch
    [store [op-key args]]
    op-key))


(defmethod apply-op :default
  [store [op-key args]]
  ; Try to resolve the key as a method in the blocks.core namespace.
  (if-let [method (ns-resolve 'blocks.core (symbol (name op-key)))]
    (method store args)
    (throw (ex-info (str "No apply function available for operation " (pr-str op-key))
                    {:op-key op-key}))))


(defmulti ^:private update-model
  "Apply an update to the model based on the operation."
  (fn dispatch
    [model [op-key args]]
    op-key))


(defmethod update-model :default
  [model _]
  ; By default, ops have no effect on model state.
  model)


(defmulti ^:private check-op
  "Make assertions about an operation given the operation type, the model
  state, and the args/response being tested."
  ; TODO: should this include `is` or return a boolean?
  (fn dispatch
    [model [op-key args result]]
    op-key))


(defmethod check-op :default
  [_ _]
  ; By default, checks make no assertions.
  true)


(defmacro ^:private defop
  "Defines a new specification for a store operation test."
  [op-key & forms]
  (let [form-map (into {} (map (juxt first rest)) forms)]
    `(do
       (defn- ~(symbol (str "gen-" (name op-key) "-op"))
         ~(str "Constructs a " (name op-key) " operation spec generator.")
         ~@(if-let [gen-form (get form-map 'gen-args)]
             (if (= 1 (count gen-form))
               [['blocks]
                `(gen/tuple
                   (gen/return ~op-key)
                   ~(list (first gen-form) 'blocks))]
               [(first gen-form)
                `(gen/tuple
                   (gen/return ~op-key)
                   (do ~@(rest gen-form)))])
             [['blocks]
              `(gen/return [~op-key])]))
       ~(when-let [apply-form (get form-map 'apply)]
          `(defmethod apply-op ~op-key
             [store# [op-key# args#]]
             (let [~(first apply-form) [store# args#]]
               ~@(rest apply-form))))
       ~(when-let [check-form (get form-map 'check)]
          `(defmethod check-op ~op-key
             [model# [op-key# args# result#]]
             (let [~(first check-form) [model# args# result#]]
               ~@(rest check-form))))
       ~(when-let [update-form (get form-map 'update)]
          `(defmethod update-model ~op-key
             [model# [op-key# args#]]
             (let [~(first update-form) [model# args#]]
               ~@(rest update-form)))))))



;; ## Operation Generators

(defn- choose-id

        (.toByteArray baos))))

  (check
    [this model result]
    (if-let [block (get model id)]
      (is (bytes= (.toBuffer ^PersistentBytes @block) result))
      (is (nil? result)))))


(defop OpenBlockRange
  [id start end]

  (gen-args
    [blocks]
