Cuándo
29-08-2026. El commit 991773bd (v1.87.0, “papelera de dispositivos”) introdujo el bug; se detectó y corrigió el mismo día con el commit 39900321 (v1.87.1, PR #471). No hubo caída de PROD — la app siguió sirviendo la imagen anterior — pero la v1.87.0 nunca llegó a construirse ni desplegarse como imagen nueva.
Síntomas visibles
La imagen Docker de la v1.87.0 no se construyó. El job Docker Build del CI no se disparaba: su gate (job changes en ci.yml) solo miraba cambios en Dockerfile* / requirements*.txt / compose*.yml. Un cambio en locale/es/LC_MESSAGES/djangojs.po no lo activaba, aunque las traducciones se compilan dentro de esa misma imagen (django-admin compilemessages).
Causa raíz
Doble causa, cada una suficiente por separado para tumbar el build:
- El
.potenía una cadena con saltos de línea reales: elmsgid/msgstrdel texto de confirmación “Delete… everywhere?” (introducido en991773bd, feature de papelera de dispositivos) llevaba un salto de línea literal dentro de las comillas en vez de la secuencia escapada\n. El formato.poexige que un mensaje multilínea vaya como una sola línea de texto con\nescapado — una cadena con salto real rompe el parser demsgfmt. - El gate de
Docker Buildno cubríalocale/*.po: aunque el.pose hubiera corregido a tiempo, el job que reconstruye la imagen (donde vivecompilemessages) no se disparaba por un cambio de traducciones — solo por Dockerfile/requirements/compose.
Fix aplicado
Commit 39900321 (PR #471, v1.87.1):
locale/es/LC_MESSAGES/djangojs.po: la cadena rota se reescribe con\nescapado en una sola línea, tanto enmsgidcomo enmsgstr..github/workflows/ci.yml: el regex del jobchangesañadelocale/.*\.poa los triggers que ponendocker=true.
Lecciones
- Un
.poroto no revienta los jobs de lint/test (no compilan mensajes) — revienta silenciosamente el build de la imagen. Si además ese job ni siquiera se dispara, el fallo queda invisible hasta que alguien nota que el deploy no trae la versión nueva. - Cualquier fichero que la imagen Docker procese en tiempo de build (aquí,
compilemessagessobrelocale/) tiene que estar en el gate deDocker Build, no solo Dockerfile/requirements/compose.
Preventivos futuros
- El gate de CI ya cubre
locale/*.podesde este commit. - Pendiente de valorar (fuera del alcance de este fix): un check de formato en pre-commit/CI que rechace saltos de línea reales dentro de
msgid/msgstrantes de llegar al build — el proyecto ya usacheck_po.pyen otros commits de i18n para validar formato, pero no está confirmado que cubra este caso concreto.
Véase también
- [[ia-tech—automatismos—metodo—ci-workflows]]
- [[crearack—network—device-page]]
- [[incident—20260821—add-rack-doble-post-manifest-hash]]
- [[crearack-tech—admin—dokploy-internals]]
- [[concept—infra—gh-actions-watchdog]]