Haha, you guys remind me of what we used to do at ITA, when we dynamically defined types for strings of known size (exact, up to max, or arbitrary interval) and use that for our ORM.
We tried to define the predicate functions directly in the deftype... except
(1) the deftype can be expanded within an arbitrarily deep scope, the wrong place to expand into a function definition.
(2) the deftype is never guaranteed to be expanded at either compile-time or runtime, and can be expanded many times, so it is the wrong place to define the function by side-effect, especially if you want it compiled.
(3) the side-effects from deftype will NOT be persisted into the FASL anyway, so next time you build your system and load the FASL, the function will be referenced but not defined. Oops.
At first, we used the discipline of requiring programmers to manually check that their functions are defined, if not, define them by hand, and de-duplicate by hand also.
Eventually, I took over ASDF, added the :around-compile hook, could implement the asdf-finalizers extension, and then the deftypes would be able to add forms to FINAL-FORMS in eval-when's as well as evaluating them immediately, and all the developer would have to do is write (expand-final-forms) at the end of the file—and the compiler would warn him if he needed to and failed to do it. See the list-of example in asdf-finalizers.
Sadly, QRes was discontinued by Google not long afterwards. Sad. The infrastructure (QUUX and the ORM, QUAKE) was eventually open-sourced, but remains unmaintained with few bits scavenged.