Parece que encontrei a causa do problema.
Para detectar o erro, eu tive que pegar stderr no meu log personalizado. Aconteceu que era útil fazer isso porque alguns erros não foram enviados para o root e não foram escritos em outros logs.
Para pegar o stderr no meu log, eu primeiro mudei a tarefa do cron para:
52 15 * * * apt-get -y upgrade >> /var/log/my-apt-upgrade.txt 2>&1
Hoje o pacote "wlibgcrypt11" deve ser atualizado. Desta vez, meu log detectou um erro. Foi mais explícito do que a vaga mensagem de erro que apareceu anteriormente em /var/log/apt/history.log.
Em /var/log/my-apt-upgrade.txt hoje:
Reading package lists...
Building dependency tree...
Reading state information...
The following packages will be upgraded:
libgcrypt11
debconf: unable to initialize frontend: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
dpkg-preconfigure: unable to re-open stdin:
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/300 kB of archives.
After this operation, 35.8 kB of additional disk space will be used.
dpkg: warning: 'ldconfig' not found in PATH or not executable
dpkg: warning: 'start-stop-daemon' not found in PATH or not executable
dpkg: error: 2 expected programs not found in PATH or not executable
Note: root's PATH should usually contain /usr/local/sbin, /usr/sbin and /sbin
E: Sub-process /usr/bin/dpkg returned an error code (2)
Então, foi um erro PATH.
O PATH da raiz no meu sistema contém todos os diretórios necessários. O mesmo acontece com a variável secure_path no visudo. É por isso que tudo funciona quando eu executo o sudo apt-get manualmente.
Mas o cron não define as variáveis de ambiente. Então, adicionei uma variável de ambiente PATH para cada uma das tarefas do cron.
$ sudo crontab -e
22 16 * * * PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' apt-get -y update >> /var/log/my-new-apt-update.txt 2>&1
32 16 * * * PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' apt-get -y upgrade >> /var/log/my-new-apt-upgrade.txt 2>&1
E funcionou! O pacote foi atualizado com sucesso pela tarefa Cron.