I don't see how "typed/untyped" is a meaningful distinction if you consider "dynamic types" to be types. If the only observable effect of the typechecker in a dynamically-typed language is a runtime error, how do we distinguish an arbitrary source of runtime errors (e.g. "throw" or "error" statements) from a dynamic typechecker? Obviously it isn't the presence of the word "type" in error messages, but what
is it? In the presence of the metaprogramming you describe, we can't say it's down to whether checks are inserted automatically either, since non-type dynamic checks may also be inserted pervasively and automatically with metaprogramming.
If Lisp is typed, what's an "untyped" language? One in which the user hasn't done metaprogramming to insert runtime checks? Or is the distinction just about whether it's the end programmer or the language implementor who does the metaprogramming? None of these seem like very useful distinctions.
If it's lispy to actually do a separate typechecking pass, please forgive my ignorance.