This turns out to be a known issue:
The require_in requisite does not support everything that require does, mainly id does not support sls or state_id without specifying a state module.
So by modifying our SLS file to include the state module (specifying file: /root/b as the require_in target instead of simply /root/b), we get the correct result.
I don't know if the other requisite injectors (watch_in, etc.) have the same limitations, so I will likely standardize my coding style on explicitly including module names in such identifiers.