After much fiddling around and thinking I've got my AO working on my game engine as intended; except one specific case.
When a block is nestled between others on two sides, but the corner block is missing, that corner doesn't get occluded. This isn't too shocking, because there's no logic to do otherwise. However, I can't think of a way to neatly solve that case. If I make it detect a block on each pair of sides, then check for the corner piece, we will end up with lots of broken AO in various scenarios, and that will be a lot of checks to boot.
Here's the table I came up with today which finally solved the missing bits of my AO algorithms:
The logic in my code (C# MonoGame) essentially enforces this table.
If nobody comes up with anything better, I'll put a series of booleans in the checks for each side, then run through each combination and adjust as though a pair of side block were the corresponding corner block.