Nevermind - egg on face. There was an exception caught in my code, but it was buried in the middle of the HttpResponseException content so I missed it. The problem turned out to be one where s3 ninja was literally returning success without having written the file due to a previous error where it had run out of file handles and committed a key without having actually written it to disk.
I added code to my client to check the returned etag against my own checksum. I check to be sure both remote and local md5 sums are available before doing this comparison, but most services return an etag, so I'm not worried. Thanks for your patience Andrew. Regards, John