Well, I let it stay in the "stuck" state that I describe above for a
good hour, watching it slowly eat my CPU, then I finally purged my
queue, removed all the tracker objects from the datastore, totally
wiped the datastore in the target app (which had had some fraction of
the data transferred to it), and tried again. Same result. Then I
set about randomly changing things to see if it would behave any
differently. Eventually I wrote a task that scanned through all
entities of a given kind, about half of which I knew were orphans.
The task simply looked up the entity's key's parent key, and if the
parent key didn't correspond to a datastore object then the task
deleted the entity. After this, when I tried the transfer again it
completed in a few minutes.