This splits out validation into two separate passes. One if the
read-only validation. The other is the "post-processing" step, that
applies defaults and also converts to python representation of enums.
This allows us to clean up the validate step even more and also a more
sensible, structured place to plug in "post-validatoion processing"
(We'll name apply_default_values to post_process_config or something
in a subsequent diff).
Users will be able to inject their own logic into the post-processing
step to do things like further validation beyond the type system (e.g.
what we currently did with custom scalars)
This also exposed a pretty problematic thing that we were actually
maintaining two code paths for managing defaults.
Depends on D1672