Update:
When I saved the notebook, completely closed Mathematica, and reopened it, the code gave the correct output once re-evaluated, but I have no idea what went wrong initially, or how to prevent it happening again. So, presumably it was some lasting remnant of a previous action - but if it was, I have no idea how I could have fixed it or even found out what the difference was. (As you can see, I tried clearing everything I could, but the incorrect behavior persisted until I started a completely new session.)
I seem to have issues of this nature quite frequently, where some invisible bit of state will end up mucking up my work and leading to unexpected behavior, and I have no idea what the actual problem is, let alone how to undo it. I can't imagine Mathematica is supposed to feel like you're constantly walking through an invisible minefield where at any moment some forgotten bit of code from a deleted cell in a closed notebook could break stuff without warning ...
Is there some window or panel I've missed where I can view what symbols are active in a session, like how Matlab lets you see all the variables currently defined in your workspace? MATLAB has a similar tradeoff between having a global workspace where variables stay defined and can potentially cause old code from one program to interfere with another, but having a view like that makes it much easier to deal with; I'm almost sure such a thing exists, and it would be extremely helpful, but I can't find it. I know there must be some way to find out what I've added to a session.
Also, how can I get a fresh session again without having to close and reopen Mathematica, given that even Clear["Global`*"] and ClearAll don't seem to be able to get rid of everything?