As for my half of the answer, major ingredients were...:
- Look at compiler output
- Guess qualifiedly (using knowledge of instruction sets in general and the known part of beam in particular)
- For the instruction parameters which you can't easily explain, look at compiler output for variations of the source
- For the instruction parameters which you still can't explain, look at ops.tab, and possibly the C implementation of the instruction
- Implement and try booting OTP / running small programs using the feature
- Patience and determination (finding the process fun helps nicely).
(A variation of the first step: when your problem is that the booting process has become stuck at some point, or some program fails, then you often know the instruction in question and need to look at the source which produced it.)
Some things, like nested exception handlers and call_fun TCO, were more tricky than others; bitstring operations too, if only by volume.
The rest of the runtime is of course the larger part, or at least the one with more opportunities for lurking bugs.
As for whether documentation would have helped: for the easy parts, probably not. For the hard or surprising parts, certainly yes. For knowing when you have guessed all there is to know, with no surprises or corner cases left, absolutely.