Today's progress: I realized that I had not made quite as much progress as I previously thought!
Less flippantly, I realized that I'd thought the descriptor protocol was more powerful than I now think it reasonably can be, and I can't define an attribute in a base class that controls the behavior of assigning to that name in subclasses.
Which means that I can't define stuff in the base class that makes monkeypatching subclasses "just work". Getting things to "just work" takes metaclass fiddling, and I don't think that's acceptable for a class that I want to allow arbitrary subclassing from. I've dealt with enough nonsense juggling metaclasses in previous iterations of this project, and I'd rather find another way.
What I'm kind of leaning towards is some kind of proxy object that exposes the underlying function objects that the user defines for the specific protocol methods that Product generates, and intercepts sets and deletes to translate them to operations on the class. Therefore: monkeypatch the proxy, and the class updates appropriately.
Hm. Somewhere in here, I forgot how I wanted to handle the case of defining stuff in a class, and then trying to un-define it in a subclass. Probably assigning over the methods from the Product class would work, and the main things I'm missing are: tests of this idea, and special-casing for the specific instance of: __eq__ was overridden, but __ne__ was not.
These tasks are much smaller, and I hope they're all I really need, because the designs I had before were really getting out of hand.
Oh hey, I had tests for some of this behavior already, and they pass. ... This project is too big.
Oh well, I was able to avoid some really unpleasant scope creep. So, next task: translate a bunch of this logic into a form that Mypy can deal with, because, unfortunately, I'm pretty sure I need to mirror this stuff pretty closely to have any chance of getting things to match.
But, regardless, in terms of how much work I think I need to do, this post was excellent for progress.
Tomorrow, I would like to take a break I think, though. And also wind down now. Good night.