First of all, let's recall if necessary that the apostrophe ' character is a reader macro that reads the next form F and produces a regular Lisp form (quote F). That's why there is a quote symbol below.
So, in the following form:
(defproto-1 mls-proto '(id upper lowers logs histories)))
defproto-1 is given two unevaluated values:
the symbol mis-proto
a body, ie. a list of all remaining arguments; here there is only one, so the value bound to body is a list like this:
((quote (id upper lowers logs histories)))
Here above I wrote the list as it is at read-time, not how you need to write it if you want Lisp to evaluate it.
This is important to make this distinction because forms that are in parentheses are usually evaluated and we need to put quotes before them to evaluate them as literal lists.
The reason body is bound to this list is because macros don't evaluate their arguments. In the macro call you have '(id upper lowers logs histories), which is thus literally the first element of the list in body.
When you splice the body in the resulting code, all its elements are placed one after the other in the parent form, and you reintroduce the (quote ...) form inside defclass.
If you change the macro as follows:
(defmacro defproto-2 (name slots)
...)
Then you remove one layer of complexity: you expect the caller to give only one argument to defproto-2 instead of a &body. Then, in the following call:
(defproto-2 mls-proto '(id upper lowers logs histories)))
The slots variable would be bound to:
'(id upper lowers logs histories)
aka.
(quote (id upper lowers logs histories))
You still cannot splice it directly, because there's a quote in front of your list, but you could access the list by calling (second slots), skipping the first element and using the quoted list (which you can splice).
However, if you do so, you are assuming the callers always gives you a quoted list. This could be a problem if there are instances of defproto in your code that are as follows:
(defproto name some-list-var)
or
(defproto name (f x y z))
... where some-list-var is a symbol (bound to a list of slot names) and (f x y z) some function call.
In that case, your macro would never be able to work, since a variable has a value at runtime, not earlier (this might work if the expression can be evaluated at compile time, in which case you could (eval slots) in your macro, but this is a special case).
I'm also assuming you are working with some existing code where you cannot change all the calls, otherwise you could simplify them a bit and write the macro as:
;; &body version, body is bound to a list of symbols
(defproto mis-proto id upper lowers logs histories)
or
;; slots version, where the variable is a literal list
(defproto mis-proto (id upper lowers logs histories))
If indeed there are instances of calls where the list of slots is not a quoted list but a different form that needs to be evaluated to obtain a list, then your macro needs to expand into code that can create a class given a dynamic list of slots.
In Common Lisp, with the Meta-Object Protocol, that would be mop:ensure-class. In your case you might need to expand into a form that looks like (eval (list 'defclass ...)), where the defclass body contains as many slots as necessary.