Spec: entity id list and entity consistency?

Posting this in case its useful to anyone.

I started running into issues where spec was unable to generate large consistent sets in 100 tries. The solution I found was to use a custom generator with single item set that guaranteed that the manifest and the items would have the same keys. I don’t feel like this is a particularly elegant solution but it does work.

The data format is slightly different to that in my initial question.

{:manifest {:item-order ["b" "c"]},
 :items  [{:id "b" :type "food"}
          {:id "c" :type "drink"}]

Here’s my approach.

(require '[clojure.spec.alpha :as s])
(require '[clojure.spec.gen.alpha :as gen])

(defn large-shuffled-vec-of-ids []
  (->> (range 1000)
       (map (partial str "xid"))
       shuffle
       vec))

(s/def ::id string?)
(s/def ::item-order
  (s/with-gen
    (s/coll-of ::id :distinct true)
    #(s/gen #{(large-shuffled-vec-of-ids)})))
(s/def ::manifest (s/keys :req-un [::item-order]))
(s/def ::type #{"food" "drink"})
(s/def ::item (s/keys :req-un [::id ::type]))

(s/def ::items
  (s/with-gen
    (s/coll-of ::item :distinct true)
    #(s/gen #{(let [ids (large-shuffled-vec-of-ids)]
                (map (fn [item id] (merge item {:id id}))
                     (apply concat (s/exercise ::item (count ids)))
                     ids))})))
                     
(defn consistent-ids? [{:keys [manifest items]}]
  (= (set (manifest :item-order))
     (set (map :id items))))
     
(s/def ::items-with-manifest
  (s/and
   (s/keys :req-un [::manifest ::items])
   consistent-ids?))
   
(comment 
   (gen/generate (s/gen ::items-with-manifest)))   

Is there a better approach that I’m just missing?