The stack state is either busy or free depending on whether it is actually in the middle of performing some operation (e.g. receive or transmit). It isn't necessarily busy before a CyBle_ProcessEvents() call, and it isn't necessarily free afterwards.
However, this is different from whether the internal packet transmission queue is full or not, which is not directly detectable with an API method. You have to rely in this case on the return value from API calls which would add a new packet to the transmission queue, such as CyBle_GattsNotification().
EDIT: It seems the stack state is at least intended to provide exactly this information. However, I haven't yet been able to identify all cases where the state is actually marked "busy," other than when you initiate an indication (acknowledged data push) with CyBle_GattsIndication().
I believe there is a pending internal BLE component update which addresses an issue where this API method incorrectly returns CYBLE_INVALID_OPERATION in some cases where it should return CYBLE_MEMORY_ALLOCATION_FAILED instead. I suggest that you treat either error as an indication that you need to retry sending the same packet again.
Gotcha. Thank you so much!