CreaRack-SL

Cache stale de base.js/alpine-components.js por versionado manual olvidado (v1.73.1)

Cuándo

20-08-2026, detectado y arreglado el mismo día en el commit 5d927b6 (v1.73.1, PR #403). La ventana de exposición real es más larga: cubre las 5 PRs anteriores del día que tocaron base.js o alpine-components.js sin subir su ?v=.

Síntomas visibles

Edu vio en producción comportamiento desactualizado pese a que el deploy en el servidor ya tenía el código correcto:

  • El backup completo salía directamente, sin el diálogo de selección de vídeos de Signage (feature de la v1.72.0/#399).
  • El modal de restore aparecía sin el inventario completo ni la opción de restaurar solo dominios (feature de la v1.73.0/#402).

Ambas features estaban bien desplegadas en el servidor — el fallo era que el navegador de Edu, con caché caliente, seguía sirviendo la copia anterior de base.js/alpine-components.js en vez de descargar la nueva.

Causa raíz

templates/base.html versiona a mano los dos scripts principales del frontend legacy con un querystring (?v=N) que actúa como cache-buster:

<script defer src="{% static 'js/alpine-components.js' %}"></script>   <!-- sin versión -->
<script src="{% static 'js/base.js' %}?v=3" defer></script>

Nadie subió ese número en ninguna de las 5 PRs del día que modificaron esos ficheros — el paso es manual y no lo fuerza ningún check de CI ni pre-commit. Como el querystring no cambiaba, el navegador consideraba la URL idéntica a la ya cacheada y no volvía a pedir el archivo.

Es una causa raíz distinta pero de la misma familia que el incidente previo v1.63.2 (CHANGELOG.md, edge de Cloudflare cacheando una respuesta CSS rota durante un deploy) — ambos son fallos de la clase “deploy verificado en servidor ≠ código ejecutándose en el cliente”.

Matiz arquitectónico sin resolver: el proyecto ya tiene cache-busting automático por hash de fichero en producción vía [[entity—core—service—forgiving-manifest-storage]] (ForgivingManifestStaticFilesStorage, que cachea 1 año con immutable y cambia de nombre solo cuando cambia el contenido). El ?v=N manual en base.html es una capa aparte, redundante con ese mecanismo y con el mismo modo de fallo que pretendía evitar (versión olvidada = caché stale). El CHANGELOG deja explícito que la mitigación de fondo (querystring automático ligado a APP_VERSION, o depender solo del hashing ya existente) queda pendiente de decisión de Edu.

Fix aplicado (commit 5d927b6a)

Bump manual de los dos querystrings — alpine-components.js pasa de sin versión a ?v=2, base.js de ?v=3 a ?v=4 — más el bump de rutina de APP_VERSION a 1.73.1 en config/settings/base.py.

Lecciones

  • El versionado manual de assets es tan fiable como acordarse de hacerlo: sin automatismo, falla con el tiempo suficiente (5 PRs en un solo día bastaron).
  • Un deploy “correcto” en el servidor no garantiza que el cliente ejecute ese código — hay que verificar también el lado del navegador, no solo el lado del servidor.
  • Footgun ya anotado en memoria del proyecto: tocar static/js obliga a subir su ?v= en el mismo PR.

Preventivos futuros

  • Decisión pendiente de Edu (anotada en el CHANGELOG de este commit): automatizar el ?v= ligándolo a APP_VERSION, o retirarlo y confiar en el hashing de [[entity—core—service—forgiving-manifest-storage]] que ya cubre este caso en producción.

Véase también

  • [[entity—core—service—forgiving-manifest-storage]]
  • [[entity—frontend—service—escape-helpers]]
  • [[feature—infra—fix-flash-tipografia-cache]]
  • [[feature—core—help-widget-i4]]
  • [[feature—core—help-widget-it-tutor]]