Yesterday I was able to root-cause the bug where only '0' data would be returned from the PIC16F1455 over USB to the Python module. This turned out to be an interesting bug.
The bug appeared after I made some seemingly unrelated changes to the code. I could not figure out why the data returned was always null. I traced the firmware's execution in the debugger and followed the return data through the various buffers and it was always correct.
Looking through the PIC16F1455 datasheet I was reminded of the special dual-port RAM for the USB controller. Looking at the buffers in the USB stack source code from Microchip there was no annotations to keep them in this special dual-port RAM location. Upon further reading of the spec I found that the USB controller can only read data from the dual-port RAM.
Checking the map file with the compiled addresses of all the variables in the firmware I find that the transmit buffer is not within the dual-port RAM. Bingo. It turns out the firmware worked before because I was lucky and the buffers happened to be allocated in the right location. However, once some extra variables and data structures were added, the compilers allocation algorithm happened to place the USB buffers outside the dual-port RAM.
The solution seemed simple; tell the compiler to assign the USB buffers within this dual-port RAM address range. It turned out not to be so. Even though I could tell the compiler where to put the buffers, I would still get corruption on the transfers. As I dug further into the USB stack I started to replace sections with my own versions of the CDC device class transmit and receive path. This led to a much better understanding of the USB hardware in the PIC as well as fully functional firmware.
I'm not quite ready to order the pre-programmed PICs just yet. Will need some more testing to gain confidence. On a related note, the production PCBs are about half-way finished being fabricated. They could be delivered to me as soon as early next week.