Question on the Design of Macro Hygiene

This seems like an instance of what I wanted to talk about as problem. The eval searches for df from the global scope. Admittedly this might not be the best usage of eval but intuitively to users who know not that much detail of its impl, it should have worked (at least that’s my understanding of eval in Lispy things (like Python))
(Edit: i was wrong, in Python eval is also defaulted to global scope, but the workaround (that seems general enough) is to actually specify the scope by adding the output of built in function locals())

Your example of nexprs, my first thought being, belongs to the case that needs special treatment. They are to me more like C preprocessor style than the all powerful Lisp macro, emphasizing on the textual part of meta programming. And the users who are calling this macro are obviously actively seeking a shortcut to declare variables (as such, what they want is a textual macro), thus there will be much less confusion.

In contrast, when it comes to eval, upon hearing its functionality, we would have expected it to operate on the expression level. Evaluation of expression at here there should be equivalent to directly running that expression here there. The default behavior of such macro seems natural to comply to such intuition. We should not have needed to change df to Thisfunction.df or the like to refer the exact same thing.

Another thought is that it is easier to inspect outwards than inwards in scope, due to the arborescent nature of code (the out direction is always unique while the in one is not). It seems better to have the innermost scope information preserved by default. Otherwise it would require hard-coding the inner scope as workaround and thus lose generality and reusability.

That said, am I overlooking something about eval or is it just not well designed as built-in macro, or there is some merit in this design choice? I would love to see examples that make me learn more about this.