Incidente: el drop en la vista Back moría en un TypeError silencioso (targetU const)
Cuándo
Introducido en el commit 68762d85 (v1.80.0, 21-08-2026, PR #414 “Front/Back emparejados”), persistió durante v1.81.0 (PR #415, commit b4ddf3a6) y se corrigió el mismo día en el commit 9b921565 (v1.81.1, PR #416). Dos releases — y dos PRs con CI en verde — con el bug vivo en producción hasta que Edu lo cazó a mano.
Síntomas visibles
Soltar un stencil de trasera sobre una trasera genérica (o sobre otra trasera ya montada, para reemplazarla) en la vista Back del editor de racks no hacía nada: sin toast de error, sin nada en la consola visible del navegador. El drop simplemente no surtía efecto. El emparejado automático Front/Back (arrastrar en la vista Front) funcionaba con normalidad — el camino roto era únicamente la adopción/reemplazo manual en la cara Back.
Edu lo detectó haciendo click-test sobre un rack real (RackM0-IT) y, antes de teorizar, verificó contra la base de datos de PROD que ese rack solo tenía dispositivos frontales — descartando que lo que él veía como “reflejos” fueran traseras reales ya rotas; eran genéricas, y el camino que fallaba era justo el de sustituirlas.
Causa raíz
En static/js/editor/devices.js, dentro de initCanvasDropListener(), la variable targetU se calculaba y se declaraba con const:
const targetU = Math.round(distFromBottom / STATE.CONFIG.U_HEIGHT) + 1;
La feature de adopción/reemplazo de traseras (introducida en v1.80.0 y ampliada en v1.81.0) necesita reasignar targetU más adelante, dentro de applyGeo, para ajustarlo a la geometría del par Front/Back. Reasignar una const lanza un TypeError en JavaScript — y ese error reventaba el handler del evento drop entero, en silencio: sin captura, sin toast, sin log visible.
El motivo por el que esto pasó desapercibido en dos PRs verdes es que la red de lint no lo cazaba: Biome corría con recommended: false en biome.json, y la única regla de correctness activa antes de este fix era noUselessEscapeInString. La regla que detecta precisamente esto — reasignar una const — (correctness/noConstAssign) estaba apagada.
Fix aplicado (commit 9b921565)
static/js/editor/devices.js:const targetU→let targetU, con un comentario explicando por qué (la adopción/reemplazo la reasigna).biome.json: se activacorrectness.noConstAssign: "error". Se hizo un barrido de los 234 ficheros JS del árbol para confirmar que no había más reasignaciones deconstlatentes — no se encontraron más casos.
Lecciones
- Un
TypeErrordentro de un event handler de drop-and-drop puede morir completamente en silencio si no hay untry/catchni un canal de error visible (toast/consola) — el síntoma en producción fue “no pasa nada”, el peor tipo de fallo para diagnosticar a distancia. recommended: falseen el linter no es gratis: dejar solo 1-2 reglas activas a mano deja huecos exactamente en los checks más básicos (una reasignación deconstes de los errores más triviales de cazar con lint, y aun así se coló en dos PRs).- Verificar el estado real (la BD de PROD) antes de teorizar sobre qué mostraba la UI evitó una pista falsa (asumir que había traseras reales ya rotas cuando eran genéricas).
Preventivos futuros
correctness.noConstAssignqueda activa enbiome.jsonde forma permanente — cualquier reasignación deconstfutura falla el pre-commit y el CI antes de llegar a producción.- El editor de racks (JS) sigue sin cobertura de tests automatizados para el drag & drop — la detección de este tipo de bug depende del click-test manual de Edu. Sigue siendo la brecha de fondo del módulo (ya señalada en el plan DCIM Fase 1).
Véase también
- [[concept—racks—editor]]
- [[crearack-tech—backend—rack-editor]]
- [[crearack-tech—agents—dev-rack-editor]]
- [[entity—racks—model—device]]
- [[entity—racks—model—rack]]
- [[crearack—conceptos—rack-editor-conceptos]]
- [[crearack—racks—dispositivos]]