Thanks. Your change works for me.

I'd also like to fix this problem that equivalent formulations
of (NOT hairy-array) aren't TYPE=.

(TYPE= (SPECIFIER-TYPE '(NOT (AND ARRAY (NOT SIMPLE-ARRAY))))
             (SPECIFIER-TYPE '(OR (NOT ARRAY) SIMPLE-ARRAY)))
=> NIL and NIL, should be T and T.

What do you think of this patch which achieves that?
Nothing breaks, and the above test passes.

--- a/src/code/late-type.lisp
+++ b/src/code/late-type.lisp
@@ -2424,7 +2424,17 @@ used for a COMPLEX component.~:@>"
   ;; FIXME (and hint to PFD): we're vulnerable here to attacks of the
   ;; form "are (AND ARRAY (NOT (ARRAY T))) and (OR (ARRAY BIT) (ARRAY
   ;; NIL) (ARRAY CHAR) ...) equivalent?" -- CSR, 2003-12-10
-  (make-negation-type :type type))
+  (if (and (eq (array-type-dimensions type) '*)
+           (eq (array-type-complexp type) 't)
+           (eq (array-type-element-type type) *wild-type*))
+      ;; not hairy-array = either simple array or (not array)
+      ;; This is deliberately asymmetric - trying to say that
+      ;; NOT simple-array is hairy-array|(not array) leads to infinite recursion.
+      (type-union (make-array-type '* :complexp nil
+                                   :element-type *wild-type*)
+                  (make-negation-type
+                   :type (make-array-type '* :element-type *wild-type*)))
+      (make-negation-type :type type)))