The hash is there to ensure very long passwords contribute entropy to the final hash instead of being truncated. It also ensures the entropy is evenly distributed - every bit of the password affects every bit of the hash.
> the "security" code only needs to handle 64-byte random strings
You can't feed any typical BCrypt implementation a raw SHA-512 hash because it's not binary safe - it truncates at the first NULL byte.
Well, you can, and it'll appear to work, but it'll be laughably easy to break. It's a pretty stupid sharp edge IMO.
> which are truncated to 54-byte strings for `bcrypt`
72 bytes, because that's the size of the key array. 56 bytes is just where extra entropy helps less, because the last 16 bytes don't affect every bit of the output.
> That removes all sorts of stupid edge cases that come with variable-length strings.
It's just treated as a circular buffer. And what are we doing here, implementing our own version of BCrypt? Yeah, that certainly simplifies things :P