QC automático justo antes de publicar en el blog: el secreto detrás de 0 publicaciones erróneas en 6 meses

5 min read · 1,126 words

Consejos prácticos / Gestión de blogs / Python y automatización
Aprox. 2300 caracteres

Cuando gestionas un blog con más de 200 artículos, es inevitable que se pasen detalles por alto, incluso si una persona revisa el texto manualmente. Hablamos de residuos de Markdown (como negrita que se muestra tal cual), infracciones de la lista blanca de emojis, fuentes omitidas, tablas vacías o restos de estilos de cajas. Por eso, creamos un paso independiente para revisar y corregir automáticamente el artículo justo antes de que se envíe a la API del blog.

En este artículo explicamos con qué intención creamos este sistema de QC automático, cómo funciona, qué resultados reales obtuvimos y cómo lo validamos. Hemos resumido los puntos clave para que cualquier administrador que se enfrente al mismo problema pueda implementarlo con tan solo una página de código.

Por qué lo creamos

Durante el primer año, nos encontramos a menudo con dos tipos de incidentes.

El primero son los residuos de la salida del modelo. Al generar contenido con un LLM, a veces quedaban tokens de Markdown como negrita, ## subtítulo o --- sin convertirse a HTML. En el sitio en vivo, los asteriscos se mostraban tal cual.

El segundo son los casos en los que el texto estaba perfecto justo después de escribirlo, pero algún hook lo estropeaba justo antes de la publicación. Por ejemplo, una función que abría un

adicional en el cuerpo del texto pero no lo cerraba, lo que rompía el diseño de las tarjetas o de la barra lateral; la inserción automática de tablas de precios que resultaba en una

Cómo funciona

El punto de control consta de dos etapas.

Etapa 1: Sanitize (Saneamiento) — Corrección incondicional

Recibe el HTML y aplica lo siguiente de manera uniforme:

  • Eliminación de estilos en línea peligrosos (como width:800px, margin-left:-30px, position:absolute, etc.)
  • Eliminación de los atributos fijos width y height en las etiquetas QC automático justo antes de publicar en el blog: el secreto detrás de 0 publicaciones → Preservación del diseño responsivo
  • Conversión de tokens residuales de Markdown a HTML (XX, --- arbitrarios →
    )
  • Eliminación (strip) de caracteres que violan la política de emojis (rango U+2600–27BF, U+1F000–1FAFF)
  • Aplanamiento de estilos de caja (etiquetas
    con border, box-shadow o padding>20px)
  • Inserción obligatoria de una línea de CSS seguro en el contenedor del cuerpo del texto (max-width:100%, overflow-wrap:anywhere)

Esta etapa es un proceso mecánico que no requiere el juicio de una persona. Se diseñó para que produzca el mismo resultado consistente para cualquier artículo.

Etapa 2: Quality Gate (Filtro de calidad) — Bloqueo de publicación en caso de fallo

Comprueba automáticamente las omisiones que una persona habría detectado. Si no supera esta fase, se rechaza la publicación.

  • Menos de 600 caracteres en el cuerpo del texto → fail
  • Menos de 3 etiquetas

    → fail (para artículos de tipo guía o comparativos)

  • 0 imágenes → fail (independientemente del tipo de artículo)
  • Artículos comparativos sin

    Resultados reales

    Resultados tras 6 meses de implementación:

    • Incidentes de exposición de residuos de Markdown: promedio de 4 casos al mes antes de la implementación → 0 casos después
    • Desbordamiento horizontal (recorte lateral): promedio de 7 casos al mes → 0 casos
    • Tablas vacías / gráficos vacíos en el cuerpo del texto: promedio de 3 casos al mes → 0 casos
    • Artículos bloqueados para publicación: 38 artículos acumulados (todos republicados con éxito tras ser corregidos por el autor)

    Los 38 artículos bloqueados no se perdieron. Simplemente, el autor se dio cuenta del error, lo corrigió y volvió a intentarlo, logrando que todos se publicaran correctamente. La distribución de los motivos de bloqueo fue: omisión de fuentes (41%), texto demasiado corto (26%), 0 imágenes (21%) y otros motivos (12%).

    Métodos de validación

    Estas son las validaciones que realizamos tras crear el punto de control:

    Prueba de regresión con un "Golden Set" — Reunimos los borradores originales de 41 artículos que habían presentado fallos en el pasado para crear un "Golden Set". Comparamos automáticamente si los patrones de error desaparecían en los 41 artículos tras pasarlos por el proceso de sanitize + quality gate. Inicialmente, pasaron 39 de 41. Tras analizar los 2 fallidos, reforzamos las expresiones regulares hasta lograr que pasaran los 41 de 41.

    Verificación aleatoria en vivo (Spot-check) — Durante la primera semana de aplicación del nuevo sanitize, seleccionamos al azar 8 de los 18 artículos publicados y realizamos un fetch directo de sus páginas en vivo. Comprobamos si aparecía scroll horizontal, si el texto se salía del contenedor o si las imágenes se rompían en dos anchos de pantalla: desktop (1280px) y mobile (360px). El resultado fue 8 de 8 correctos.

    Idempotencia de doble paso (Double pass) — Verificamos si el resultado de pasar el proceso de sanitize una vez era idéntico al volver a pasarlo por segunda vez. Esta validación sirve para prevenir problemas en caso de que la cadena de hooks de publicación (publish hook chain) se ejecute dos veces. El resultado fue 100 de 100 idénticos.

    Cómo implementarlo

    En lugar de copiar todo el código, es mejor que adopte uno o dos puntos clave adaptándolos a su propio entorno.

    
    import re
    
    def sanitize_pre_publish(html: str) -> tuple[str, list[str]]:
     fixes = []
     # Eliminar anchos en línea peligrosos
     html, n = re.subn(r'width\s*:\s*(?:[4-9]\d{2}|[1-9]\d{3,})px\s*;?', '', html)
     if n: fixes.append('strip_wide_width')
     # Residuos de Markdown → HTML
     html, n = re.subn(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', html)
     if n: fixes.append('md_bold')
     # Eliminar emojis (si es necesario)
     html, n = re.subn(r'[\U0001F300-\U0001FAFF]', '', html)
     if n: fixes.append('strip_emoji')
     return html, fixes
    
    def quality_gate(html: str, post_type: str) -> tuple[bool, list[str]]:
     fails = []
     text = re.sub(r'<[^>]+>', '', html)
     if len(text.replace(' ', '')) < 600: fails.append('too_short')
     if html.count('<h2') < 3 and post_type in ('howto', 'compare'): fails.append('few_h2')
     if '<img' not in html: fails.append('no_image')
     if 'TODO' in html or 'REDACTED' in html: fails.append('placeholder')
     return (len(fails) == 0), fails
    

    Solo necesita llamar a estas dos funciones en un único punto justo antes de la publicación. Si quality_gate devuelve un fallo (fail), detenga la publicación y muestre el motivo al usuario. En cuanto a sanitize, simplemente tome el HTML resultante y envíelo directamente a la API de publicación.

    En resumen, se puede definir en una sola frase: "un único punto de control antes de publicar evita todos los incidentes de forma automática". El tiempo que antes se dedicaba a la revisión manual desaparecerá por completo.

    Category Coverage Notice

    This article follows our label-specific editorial criteria. Details:

ToolSignal Pro Editorial

ToolSignal Pro는 AI·IT·소프트웨어 트렌드를 다루는 종합 IT 인사이트 매거진입니다.

이전 글 다음 글