Part of the difficulty is that custom types contain master and agent logic in the same file, e.g. lib/puppet/type/foo.rb. For example, newproperty/newparam/newvalues define the "shape" of the custom type and are needed during compilation. But methods like validate, munge, etc are evaluated at catalog application time. Plus there has historically been some confusion about what code is evaluated where, for a variety of reasons.
To help shed some light on that, I've created the following document in the form of a PR to the puppet-specifications repo:
https://github.com/puppetlabs/puppet-specifications/pull/72. The goal is to specify the current behavior for custom types, and especially understand which parts of the types affect catalog compilation. Feedback is welcome.