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?