I’ve solved the same problem in a different way.
1) Submit a transaction
2) Collect all reject messages (that have matching txid in the reject data)
3) Wait 16 seconds after first error message received (chosen semirandomly from trial and error) before processing errors
4) Wait for our txid to be submitted back to us through the mempool, if we get it notify success and delete all pending error events
5) Signal failure with the given reject code if present (after the 16 seconds have elapsed)
6) If no error or success after 20 seconds, signal timeout failure
This works fairly well in testing. Newer transaction types seem to generate reject codes 100% of the time (from at least one node when sending to 4 nodes) so this culling / time delay approach is essentially required.
On a related note: One issue is that RBF attempts with too small a fee and accidental double spends (with enough fee for 1 tx but not a RBF) both generate the same reject code: not enough fee.
A new reject code for RBF based too small of fee would definitely make for a better user experience as I’ve seen this exact problem create confusion for users.
Removing reject codes would make for a much worse user experience. “Your tx failed and we have no idea why” would be the only message and it would require waiting for a full timeout.