     (#{:ref/js :ref/step :ref/page} (:type x)) (ref! x)
     :else false)))
 
+(defn constant! [x]
+  (check (= :constant (:type x))
+         (data! (:data x))))
+
 (defn pattern! [x]
   (check
    (cond

  (:require [clojure.walk :refer [postwalk]]
            aurora.util)
  (:require-macros [aurora.macros :refer [check]]))

;; id = random 128bit string ;; either a notebook, page or step
;; js = string
;; ref = {:type :ref/step :step id} | {:type :ref/page :page id :notebook id} | {:type :ref/js :js js}
;; tag = {:type :tag :id id :name string} ;; like a namespaced keyword
;; call = {:type :call :ref ref :args [ref*]}
;; data = number | string | tag | [data*] | {data* data*} | ref
;; pattern = number | string | tag | [pattern*] | {data* pattern*} | ref ;; if ref is a step, check equality. if page, treat as predicate
;; action = call | data
;; branch = {:type :match/branch :pattern pattern :action action}
;; match = {:type :match :arg ref/step :branches [branch*]}
;; step = {:id id & (call | data | match)}
;; page = {:type :page :id id :steps [step*]}
;; notebook = {:type :notebook :id id :pages [page*]}

(defn id! [x]
  (check (string? x)))

(defn js! [x]
  (check (string? x)))

(defn ref-id! [x]
  (check (= :ref/id (:type x))
         (id! (:id x))))

(defn ref-js! [x]
  (check (= :ref/js (:type x))
