    :hash   s/Str})
 
 (def OptsEmail
-  {(s/required-key :from              ) s/Str
-   (s/required-key :host              ) s/Str
-   (s/required-key :max-failure-notify) s/Num
-   (s/required-key :pass              ) s/Str
-   (s/required-key :port              ) (s/cond-pre s/Num s/Str)
-   (s/required-key :template-html     ) (s/cond-pre s/Str java.io.File)
-   (s/required-key :template-txt      ) (s/cond-pre s/Str java.io.File)
-   (s/required-key :text-only         ) s/Bool
-   (s/required-key :tls               ) s/Bool
-   (s/required-key :to                ) (s/cond-pre s/Str [s/Str])
-   (s/required-key :user              ) s/Str})
+  {:from               s/Str
+   :host               s/Str
+   :max-failure-notify s/Num
+   :pass               s/Str
+   :port               (s/cond-pre s/Num s/Str)
+   :template-html      (s/cond-pre s/Str java.io.File)
+   :template-txt       (s/cond-pre s/Str java.io.File)
+   :text-only          s/Bool
+   :tls                s/Bool
+   :to                 (s/cond-pre s/Str [s/Str])
+   :user               s/Str})
 
 (def OptsProcess
-  {(s/required-key :program   ) s/Str
-   (s/required-key :args      ) [s/Str]
-   (s/required-key :cwd       ) s/Str
-   (s/required-key :scriptfile) s/Str
-   (s/required-key :inherit-exit-code ) s/Bool})
+  {:program           s/Str
+   :args              [s/Str]
+   :cwd               s/Str
+   :scriptfile        s/Str
+   :inherit-exit-code s/Bool})
 
 (def OptsElasticsearch
-  {(s/required-key :build-index          ) s/Str
-   (s/required-key :build-index-search   ) s/Str
-   (s/required-key :build-index-write    ) s/Str
-   (s/required-key :failure-index        ) s/Str
-   (s/required-key :failure-index-search ) s/Str
-   (s/required-key :failure-index-write  ) s/Str
-   (s/required-key :max-index-bytes      ) s/Num
-   (s/required-key :conn                 ) Connection
-   (s/optional-key :http-opts            ) {s/Keyword s/Any}
-   (s/optional-key :url                  ) s/Str})
+  {:build-index          s/Str
+   :build-index-search   s/Str
+   :build-index-write    s/Str
+   :failure-index        s/Str
+   :failure-index-search s/Str
+   :failure-index-write  s/Str
+   :max-index-bytes      s/Num
+   :conn                 Connection
+   (s/optional-key :http-opts) {s/Keyword s/Any}
+   (s/optional-key :url)       s/Str})
 
 (def OptsS3
-  {(s/required-key :access-key) s/Str
-   (s/required-key :secret-key) s/Str
-   (s/required-key :bucket    ) s/Str
-   (s/required-key :prefix    ) s/Str})
+  {:access-key s/Str
+   :secret-key s/Str
+   :bucket     s/Str
+   :prefix     s/Str})
 
 (def Opts
-  {(s/required-key :job-name    ) s/Str
-   (s/required-key :version     ) VersionInfo
-   (s/required-key :configfile  ) (s/maybe s/Str)
-   (s/required-key :email       ) OptsEmail
-   (s/required-key :es          ) OptsElasticsearch
-   (s/required-key :process     ) OptsProcess
-   (s/required-key :s3          ) OptsS3})
+  {:job-name   s/Str
+   :version    VersionInfo
+   :configfile (s/maybe s/Str)
+   :email      OptsEmail
+   :es         OptsElasticsearch
+   :process    OptsProcess
+   :s3         OptsS3})
 
 (def BuildSystem
   {:arch                   s/Str

(def StoredFailure
  (merge
   FailedTestCase
   {(s/required-key :build-id ) s/Str
    (s/required-key :time     ) s/Str
    (s/required-key :org      ) s/Str
    (s/required-key :project  ) s/Str
    (s/required-key :branch   ) s/Str}))

(def StoredBuild
  {:id s/Str
   :version VersionInfo
   :build Build
   :sys BuildSystem
   :vcs VcsLog
   :process StoredProcessResult
   :test (s/maybe StoredTestSummary)})


  {s/Str s/Any})

(def Build
  {:org                       s/Str
   :project                   s/Str
   :branch                    s/Str
   :job-name-extra            s/Str
   :job-name                  s/Str
   :org-project-branch        s/Str
   :scheduler-type            s/Str
   :url                       s/Str
   :console-url               s/Str
   :tags                      [s/Str]
   (s/optional-key :number)   s/Str
   (s/optional-key :executor) s/Str
   (s/optional-key :node)     s/Str
   })

(def SchedulerInfo
  {:type (s/maybe s/Str)
   :url  (s/maybe s/Str)
   :node (s/maybe s/Str)})

(def OptsStage2
  (merge Opts {:sys    BuildSystem
               :logger clojure.lang.IFn}))

(def OptsStage3
  (merge OptsStage2 {:env Env}))

(def OptsStage4
  (merge OptsStage3 {:scheduler (s/protocol Scheduler)}))

(def OptsStage5
  (merge OptsStage4 {:id    s/Str
                     :build Build}))

(def OptsFinal
  (merge OptsStage5 {:vcs {s/Keyword s/Any}}))

(def ProcessResult
  {:cmd            [s/Str]
   :cmd-source     s/Str
   :err-accuracy   s/Int
   :err-bytes      s/Num
   :err-file       s/Str
   :err-file-bytes s/Int
   :exit-code      s/Num
   :millis-end     s/Num
   :millis-start   s/Num
   :out-accuracy   s/Int
   :out-bytes      s/Num
   :out-file       s/Str
   :out-file-bytes s/Int
   :status         s/Str
   :time-end       s/Str
   :time-start     s/Str
   :took           s/Num})

(def StoredProcessResult
  (assoc
   (dissoc ProcessResult :err-file :out-file)
   :err-accuracy    s/Num
   :out-accuracy    s/Num))

(def VcsLog
  {
