← Volver a proyectos

Un dry-run contó unos 3,400 paquetes de servicio cuando existían 11,934. Rastrear la diferencia hasta una paginación sin orden y unos nulos descartados hizo segura una corrección masiva de costos.

Rol: Responsable de la corrección y su verificación (puesto actual) Periodo: may – jun 2026 Estado: delivered

TypeScriptMySQLClaude Code AI: Claude Code
unos 3,400 vs 11,934

Paquetes que contó el ensayo vs el total real (veía menos de un tercio)

La diferencia se detectó antes de cambiar datos, así que la corrección masiva nunca corrió sobre un conteo equivocado.

Dry-run vs conteo en producción, jun 2026

unos 8,506

Registros que un filtro dejaba fuera sin avisar porque su valor estaba vacío

La corrección alcanzó todos los registros afectados, no solo la mayoría.

Verificación en producción, jun 2026

unos 21,539

Registros de costo de mano de obra corregidos en una sola actualización masiva controlada

Los talleres con costos incorrectos los recibieron arreglados sin que nadie editara miles de registros a mano.

Validación en producción, 4 jun 2026

unos 11,934

Paquetes de servicio corregidos, igual al total real

El conteo final coincide con la cifra real, así que no se omitió nada.

Validación en producción, 4 jun 2026

Arquitectura

ARQUITECTURA / PAGINATION-ROOT-CAUSE 01 Dry-run ~3,400 encontrados 02 Investigación conteo 3.5x menor 03 ORDER BY clave 11,934 págs. estables 04 Manejo de nulos +8,506 registros 05 Script de un uso cuenta opcional 06 Producción validado, 4 jun 2026 El dry-run dijo 3,400; el conteo real fue 11,934, unas 3.5 veces más.
Causa raíz: paginación ordenada y manejo de nulos corrigieron un conteo 3.5 veces menor.

Contexto

Un SaaS B2B para talleres automotrices (mi puesto actual) cambió la fórmula que calcula el costo de mano de obra. Los talleres que usaban el campo de cantidad para ajustar el costo quedaron con costos incorrectos, y hacía falta una corrección masiva sobre miles de registros. Una escritura masiva es tan segura como el conteo en el que se apoya, así que lo primero era asegurar que el dry-run dijera la verdad. Este caso es anónimo y la demo reproduce el bug con datos sintéticos.

Mi rol

  • Decidí: que la corrección no correría hasta poder explicar el conteo del dry-run, las reglas de filtrado explícitas y que el script es de una sola ejecución.
  • Verifiqué: la salida del dry-run, la diferencia que llevó a la causa raíz y los conteos finales en producción.
  • Delegué a la IA: escribir el script de corrección y las consultas de investigación con Claude Code. La IA escribió el código; yo noté que los números no cuadraban y pedí la investigación.

Investigación

El dry-run reportó unos 3,400 paquetes de servicio. La cifra real era 11,934, unas 3.5 veces más. Un número así no es ruido, así que pedí una investigación en lugar de ajustar el filtro hasta que la cifra pareciera razonable.

La causa fue una paginación sin orden estable. Una consulta que lee página tras página sin un ORDER BY sobre una clave única le da permiso a la base de datos de devolver las filas en cualquier orden de una página a la siguiente, así que las páginas pueden repetir u omitir registros y el total se encoge en silencio. Arreglar el orden fue la primera corrección. Justo después apareció una segunda: unos 8,506 registros con valor nulo eran excluidos por el primer filtro, aunque el front-end del taller los trataba como válidos.

Decisiones

DecisiónAlternativas descartadasPor qué
Paginar con ORDER BY sobre una clave establePaginar sin ordenSin orden estable las páginas se traslapan y omiten filas, así que el conteo y el conjunto de escritura quedan mal.
Tratar los nulos igual que el front-endExcluirlos con el filtroExcluirlos dejaba unos 8,506 registros sin corregir, y la corrección habría quedado incompleta.
Marcar el script como de una sola ejecución, con opción para restringirlo a una cuentaUn script reejecutableUna segunda corrida duplicaría el efecto. Hacerlo imposible es más seguro que confiar en que nadie lo corra dos veces.

Validación y QA

Las reglas de corrección fueron explícitas: solo registros anteriores al cambio de fórmula, activos y con costo. Revisé el dry-run antes de cualquier escritura, y los conteos finales se validaron en producción el 4 de junio de 2026.

El marcador de una sola ejecución y la restricción por cuenta salen del mismo criterio que el resto de mi estándar para cambios de datos: dry-run, QA, producción, verificación posterior y scripts idempotentes siempre que se pueda. Aquí la idempotencia no era posible por la naturaleza del cambio, así que el control se movió al propio script.

Resultados

  • El conteo del dry-run pasó de unos 3,400 a los 11,934 paquetes reales una vez que la paginación tuvo orden.
  • Se incluyeron unos 8,506 registros con valor nulo que el primer filtro excluía.
  • Unos 21,539 conceptos de mano de obra y unos 11,934 paquetes de servicio corregidos (unos 17,799 conceptos embebidos), validados en producción el 4 de junio de 2026.

Qué resuelve y dónde más sirve

Antes de cambiar miles de registros de golpe, el conteo de lo que va a cambiar tiene que ser correcto. Un bug de lectura hizo que el ensayo viera menos de un tercio de los datos reales. Buscar la causa, en vez de ajustar el filtro hasta que la cifra pareciera razonable, evitó que una escritura masiva dejara mal la mayoría de los registros.

Dónde más aplica el mismo patrón:

  • Cualquier actualización masiva de datos de clientes, precios o facturación, donde no se debe escribir nada hasta explicar el conteo esperado.
  • Reportes y exportaciones que leen por páginas, en finanzas, catálogos de e-commerce o expedientes de salud, donde los totales pueden encogerse sin ningún mensaje de error.
  • Revisiones de calidad de datos antes de migrar un ERP o una base de datos.

Qué haría distinto

Haría que el dry-run afirmara su propio conteo: compararlo, en el mismo script, con un conteo independiente sin paginación y negarse a continuar si difieren. Aquí encontré la diferencia mirando; debió fallar sola. También agregaría la revisión de “paginación sin orden” a cualquier script que lea por páginas, porque el bug es fácil de escribir e invisible cuando la tabla es chica.

Evidencia

Versión completa: repositorio privado, disponible bajo solicitud.

Basado en mi puesto actual; todos los datos son ficticios.