The assessment of how this worked or should work was mistaken.
On closer observation, the way it seems to work is:
Allocate a xbits data struct, add it to sigmatch context if there are any commands other than "noalert"
If it's a "noalert" command, set noalert flag on the signature, there is no point or need of alloc'ing any struct in this case.
Since this happens for each and every xbit, if there are multiple xbits defined in a rule, the above two steps will follow for all.
As a result, for a signature like (Example is for flowbits since both work similarly),
alert http $EXTERNAL_NET any -> $HOME_NET any (msg:"ET ACTIVEX winhlp32 ActiveX control attack - phase 1"; flowbits:noalert; flow: to_client,established; file_data; content:"|3C|OBJECT"; nocase; content:"application/x-oleobject"; nocase; within:64; content:"codebase="; nocase; content:"hhctrl.ocx"; nocase; within:15; flowbits:set,winhlp32; reference:url,doc.emergingthreats.net/bin/view/Main/2001622; classtype:web-application-attack; sid:2001622; rev:16; metadata:affected_product Windows_XP_Vista_7_8_10_Server_32_64_Bit, attack_target Client_Endpoint, created_at 2010_07_30, deployment Perimeter, former_category ACTIVEX, signature_severity Major, tag ActiveX, updated_at 2017_05_08;)
First, with flowbits:noalert; , the signature is given a flag to ensure that it does not alert even if it does match.
Then, with flowbits:set,winhlp32;, a flowbit data struct is alloc'd and added to sigmatch table to make sure that it is tracked.
As a result of this, flowbit is set and the sig would not alert as expected.
In conclusion, this already works as expected.