I was doing other stuff today, so I got one thing done: switched Action and ActionName. This simplified code all over the place, although unfortunately some of the code wasn't covered, so I only have Mypy output to work with.
I guess this was an object lesson in, sometimes you just have to try things, because I don't think I'd have anticipated just how much logic got untangled by slightly changing one data structure. It's also an illustration of how helpful good type coverage can be, since I would not have felt confident changing the type definition without type coverage; tests can (sometimes) show that there's a problem, but it can be somewhat tricky to discern what the solution is based on a test failure. When tests failed, I barely looked at the details of what went wrong, and just skipped to looking for API changes that needed to be accounted for.
Anyway, that was all pretty good, but I still want to work on tweaking the configuration interface. I'll get on that in the next few days. For now, as usual, I should get ready for bed.
(Quick note, it makes more sense to create an output folder and pass the path to Actions than it does to create specific file handles outside the Action. That way, a custom Action has complete control over how it logs.)