Right -- OpenSCAD is an object compiler. You give it code, it gives you an object.
Your object is not something that can then be used to iterate on, except by placing it in space and adding or subtracting other stuff to/from it.
Have you looked at Build123D or CadQuery?
Both are Python packages (different API styles, compatible underpinnings) that do OpenSCAD-type things, but using the OpenCASCADE bRep kernel, so it is less "counterfeit" -- if you want to do something based on a face or edge or vertex that was the product of a previous operation, you can. Both have some constraints support.
In many ways they are both just a prettier alternative to the FreeCAD Python APIs -- indeed there was a CadQuery workbench for CadQuery 1.x.
The problem with anything other that OpenSCAD is it's somewhat nonstandard and often has sandboxing issues.
It's like the BASH of 3D, if I'm doing anything with code CAD, it's probably trivial enough that just using what everyone else uses makes sense, even if almost any other alternative is much nicer.
I agree that it's more difficult to manage Build123D or CadQuery due to their status as Python packages with heavier dependencies. (Less of a problem with Replicad, which is a client-side JS package)
This is a little bit of why I jumped to FreeCAD from OpenSCAD -- the existence of prebuilt distributions of FreeCAD, and the realisation that I'd always be able to script FreeCAD if I needed it.
Though I think Build123D has the beginnings of momentum (I also think it's not hard to see why):
It's much more of a one way conversation, if you can't imagine all the rotations to make a part do something, trial and error is very slow.
Whereas in GUI CAD you mostly only have to be able to think in 2D.
And without a constraint solver, you have to have a much deeper understanding of all the spatial relationships involved.