That’s more or less true, but there really is no difference between a realized lazy sequence and an ordinary non-lazy list. Once it is realized, that is exactly what you get: the head of a linked list with no laziness left in it, which is the whole purpose of doall. But you get back the head of the same list you started with, for efficiency. It is just no longer lazy.
There would be no benefit to copying everything into new list nodes in doall, and a cost in terms of time, newly allocated structures, and garbage. If you really want to incur those costs, you can (for example) create a vector from the head of the lazy sequence. The unwrap example you give above can be replaced with just this: (into [] items) or even (vec items).
There is really no way around the fact that lazy evaluation confuses and confounds people who are not used to it. There are going to be far more weird surprises in your future until it becomes second nature.
Another thing to consider is that generally the only reason you use doall is if there are side effects that occur during the computation of the lazy elements of the sequence, and you need those side effects to happen now. Otherwise you don’t care when (if ever) the laziness is resolved. But there are many bugs that result from people putting, for example, network operations inside a (for …) and never doing anything with the lazy result that comes back, and then wondering why the network operations never took place. Eventually you learn that the right construct for code like that is (doseq …), not (for …).