We tracked down our missing Xbee packets months ago, but it took me a while to write this up. We no longer rely on the hex-to-string hack to keep the Xbee message payload limited to ASCII letters and numbers. That hack did not completely solve the problem and took more bandwidth to transmit a message.
Working with my hunch that pre-processing was still being performed on the serial data, I found the solution poking through the serial code of the IMU driver we use, which was forked from KumarRobotics imu_3dm_gx4. I only set the c_lflag member of the termios structure for the serial port, but I also need the following line to disable all output pre-processing using the c_oflag member:
port_settings.c_oflag &= ~OPOST;
All packets received by the Xbee are now successfully received by our serial interface with this addition to the serial interface code. Next up for the serial interface code will be a cleanup and update of the documentation.