[QA] Proceso de verificación automática del sitio (crawler + i18n + review LLM local) — OSS, coste cero #130

Closed
opened 2026-06-28 19:15:13 +00:00 by rafa · 0 comments
Owner

Labels: area:infra, improvement

Motivación

Tras desplegar el multiidioma (#120), aparecen bugs dispersos (enlaces rotos, páginas que salen en español, redirecciones de idioma incorrectas, layout roto). Hace falta un proceso de verificación automática y repetible que recorra el sitio entero, valide enlaces/idiomas/maquetación y reporte qué no tiene sentido — sin depender de revisión manual.

Principios / restricciones (IMPORTANTES)

  • Open source y self-hosted. Nada de SaaS de pago (Screaming Frog Pro, Percy, Checkly, etc.). Solo herramientas libres.
  • LLM local = Gemma (LM Studio, google/gemma-4-e4b, endpoint http://172.19.128.1:1234/v1). Coste cero.
  • Evitar costes. La web no genera ingresos. Minimax (API de pago, barata) solo como último recurso y de forma muy acotada/muestreada; por defecto NO usarla.
  • No mandar el LLM a navegar a ciegas. El grueso son comprobaciones deterministas; el LLM solo se dispara sobre lo que esas comprobaciones marcan.

Principio de diseño (cómo lo hacen los profesionales)

Separar en capas: lo determinista (barato, exhaustivo, sobre TODOS los enlaces) primero; la IA (cara) solo sobre lo que las capas baratas marcan como sospechoso.

Capa 0 — Crawler de enlaces (determinista, todas las URLs)

Recorre cada URL: status HTTP (200/3xx/4xx/5xx), redirecciones inesperadas (sobre todo cross-idioma: /en/x/ que acaba en /it/x/ = bug), enlaces internos rotos, páginas huérfanas, bucles.

  • Herramientas OSS: lychee (Rust, rapidísimo) o linkchecker (Python) para el barrido de status; Playwright (ya instalado en tools/e2e) para seguir redirecciones y comparar URL final vs pedida.

Capa 1 — Aserciones i18n (determinista, dirigido) — LA DE MÁS ROI

  • ¿/en/X/ sirve un post EN o redirige? Comparar URL final.
  • ¿El <html lang> y el selector de idioma son coherentes?
  • Detección de idioma del texto visible con librería offline → marcar cualquier página cuyo idioma detectado ≠ esperado (caza «sin traducir», «fragmentos en español», «widget en español»).
    • OSS recomendado: lingua-language-detector (Python, muy preciso, offline) o langdetect/fasttext lid.176. Cero coste.

Capa 2 — Regresión visual (determinista)

Screenshots por página/idioma + diff de píxeles para detectar roturas de layout (como el multimedia descentrado).

  • OSS: Playwright screenshots + pixelmatch/odiff. Guardar baseline y comparar.

Capa 3 — Juicio semántico con LLM local (muestreado / solo sobre flags)

Solo sobre las páginas que la Capa 1 marcó, o una muestra pequeña:

  • Texto: mandar el texto visible a Gemma local → veredicto estructurado (JSON): {coherente: bool, idioma_ok: bool, problemas: [...]} (mistraducciones, trozos sin traducir, sin sentido).
  • Visión: mandar el screenshot a Gemma visión (ya usado en tools/e2e/ask-vision.js) → «¿se ve bien / algo roto?».
  • Minimax: NO por defecto. Solo si Rafa lo autoriza para un lote concreto donde Gemma se quede corto.

Capa 4 — (opcional, futuro) Monitorización programada

Cron local que corre un subconjunto y avisa (Telegram/WhatsApp via Hermes) si hay regresiones. Sin SaaS.

Dónde ejecutar

Contra el LOCAL (https://farmer.taild3aaf6.ts.net/fea/...), que no tiene Cloudflare bloqueando headless. Verificar AQUÍ antes de desplegar a prod. (Prod wp-nuevo.feadulta.com está tras Cloudflare → 403 a curl/Playwright; no sirve para crawl headless.)

Enumeración de URLs (no crawlear a ciegas)

Generar la lista desde la BD de WordPress (más fiable que el sitemap):

  • Todos los posts/páginas publicados por idioma (Polylang: term taxonomy language; 5 idiomas es/en/fr/it/pt).
  • Menús (wp_navigation IDs 1 y 26525-26528) y sus URLs.
  • Categorías con contenido.
  • Credenciales BD local y endpoints: ver memoria/infra (no se pegan aquí). DB local Docker: contenedor wordpress-mysql, wordpress_db/wordpress_user/wordpress_pass.

Recursos existentes a reutilizar

  • tools/e2e/ — Playwright + helper de visión ask-vision.js (Gemma). Ver project-feadulta-e2e / wiki E2E-Visual-Testing.
  • Endpoint Gemma: http://172.19.128.1:1234/v1/chat/completions, modelo google/gemma-4-e4b (texto) — multimodal para visión.
  • Patrón de URL local: https://farmer.taild3aaf6.ts.net/fea/{lang}/{slug}/ (ES sin prefijo de idioma).

Salida esperada

Un informe único (CSV + JSON) por ejecución con, por URL: idioma esperado, status, URL final (¿redirige?), idioma detectado, nº enlaces rotos salientes, flags (SPANISH_LEAK, CROSS_LANG_REDIRECT, BROKEN_LINK, LAYOUT_DIFF, LLM_FLAGGED). Ordenable por gravedad. Que de un vistazo se vea qué arreglar.

Implementación por fases (entregables en tools/e2e/)

  1. Fase A (máxima prioridad): crawler (Capa 0) + lang-detect (Capa 1) → informe CSV. Determinista, coste cero. Ya caza la mayoría de bugs actuales.
  2. Fase B: regresión visual (Capa 2) con baseline.
  3. Fase C: review LLM local (Capa 3) solo sobre flags, con Gemma (texto+visión). JSON estructurado.
  4. Fase D (opcional): cron + aviso.

Criterios de aceptación

  • node tools/e2e/<crawler>.js (o python) recorre TODAS las URLs de los 5 idiomas contra el local y genera el informe sin intervención manual.
  • Detecta correctamente: enlace roto (caso navidad-3→404 antes del fix), redirección cross-idioma (caso slug duplicado /en/colaboradores//it/...), y página EN con texto español (caso widget/menú sin traducir).
  • Coste monetario por ejecución: 0 € (todo local/OSS). Documentado en README.

Notas para el implementador (Codex / Minimax)

  • Lenguaje libre (Node ya está en tools/e2e; Python también disponible en WSL con las libs OSS citadas).
  • No introducir dependencias de pago ni servicios cloud.
  • Empezar por Fase A (es lo que más bugs caza con menos esfuerzo). Las capas IA son aditivas y opcionales.
  • Dejar un README en tools/e2e/ explicando cómo ejecutarlo y cómo leer el informe.
  • Probar contra LOCAL, nunca asumir que prod es accesible por headless.
**Labels:** area:infra, improvement ## Motivación Tras desplegar el multiidioma (#120), aparecen bugs dispersos (enlaces rotos, páginas que salen en español, redirecciones de idioma incorrectas, layout roto). Hace falta un **proceso de verificación automática y repetible** que recorra el sitio entero, valide enlaces/idiomas/maquetación y reporte qué no tiene sentido — sin depender de revisión manual. ## Principios / restricciones (IMPORTANTES) - **Open source y self-hosted.** Nada de SaaS de pago (Screaming Frog Pro, Percy, Checkly, etc.). Solo herramientas libres. - **LLM local = Gemma** (LM Studio, `google/gemma-4-e4b`, endpoint `http://172.19.128.1:1234/v1`). Coste cero. - **Evitar costes.** La web no genera ingresos. Minimax (API de pago, barata) solo como *último recurso* y de forma muy acotada/muestreada; por defecto NO usarla. - **No mandar el LLM a navegar a ciegas.** El grueso son comprobaciones **deterministas**; el LLM solo se dispara sobre lo que esas comprobaciones marcan. ## Principio de diseño (cómo lo hacen los profesionales) Separar en capas: lo determinista (barato, exhaustivo, sobre TODOS los enlaces) primero; la IA (cara) solo sobre lo que las capas baratas marcan como sospechoso. ### Capa 0 — Crawler de enlaces (determinista, todas las URLs) Recorre cada URL: status HTTP (200/3xx/4xx/5xx), redirecciones inesperadas (sobre todo **cross-idioma**: `/en/x/` que acaba en `/it/x/` = bug), enlaces internos rotos, páginas huérfanas, bucles. - **Herramientas OSS:** `lychee` (Rust, rapidísimo) o `linkchecker` (Python) para el barrido de status; **Playwright** (ya instalado en `tools/e2e`) para seguir redirecciones y comparar URL final vs pedida. ### Capa 1 — Aserciones i18n (determinista, dirigido) — LA DE MÁS ROI - ¿`/en/X/` sirve un post EN o redirige? Comparar URL final. - ¿El `<html lang>` y el selector de idioma son coherentes? - **Detección de idioma del texto visible** con librería offline → marcar cualquier página cuyo idioma detectado ≠ esperado (caza «sin traducir», «fragmentos en español», «widget en español»). - **OSS recomendado:** `lingua-language-detector` (Python, muy preciso, offline) o `langdetect`/`fasttext lid.176`. Cero coste. ### Capa 2 — Regresión visual (determinista) Screenshots por página/idioma + diff de píxeles para detectar roturas de layout (como el multimedia descentrado). - **OSS:** Playwright screenshots + `pixelmatch`/`odiff`. Guardar baseline y comparar. ### Capa 3 — Juicio semántico con LLM **local** (muestreado / solo sobre flags) Solo sobre las páginas que la Capa 1 marcó, o una muestra pequeña: - **Texto:** mandar el texto visible a **Gemma local** → veredicto estructurado (JSON): `{coherente: bool, idioma_ok: bool, problemas: [...]}` (mistraducciones, trozos sin traducir, sin sentido). - **Visión:** mandar el screenshot a **Gemma visión** (ya usado en `tools/e2e/ask-vision.js`) → «¿se ve bien / algo roto?». - Minimax: NO por defecto. Solo si Rafa lo autoriza para un lote concreto donde Gemma se quede corto. ### Capa 4 — (opcional, futuro) Monitorización programada Cron local que corre un subconjunto y avisa (Telegram/WhatsApp via Hermes) si hay regresiones. Sin SaaS. ## Dónde ejecutar **Contra el LOCAL** (`https://farmer.taild3aaf6.ts.net/fea/...`), que **no tiene Cloudflare** bloqueando headless. Verificar AQUÍ antes de desplegar a prod. (Prod `wp-nuevo.feadulta.com` está tras Cloudflare → 403 a curl/Playwright; no sirve para crawl headless.) ## Enumeración de URLs (no crawlear a ciegas) Generar la lista desde la **BD de WordPress** (más fiable que el sitemap): - Todos los posts/páginas publicados por idioma (Polylang: term taxonomy `language`; 5 idiomas es/en/fr/it/pt). - Menús (`wp_navigation` IDs 1 y 26525-26528) y sus URLs. - Categorías con contenido. - Credenciales BD local y endpoints: ver memoria/infra (no se pegan aquí). DB local Docker: contenedor `wordpress-mysql`, `wordpress_db`/`wordpress_user`/`wordpress_pass`. ## Recursos existentes a reutilizar - `tools/e2e/` — Playwright + helper de visión `ask-vision.js` (Gemma). Ver `project-feadulta-e2e` / wiki `E2E-Visual-Testing`. - Endpoint Gemma: `http://172.19.128.1:1234/v1/chat/completions`, modelo `google/gemma-4-e4b` (texto) — multimodal para visión. - Patrón de URL local: `https://farmer.taild3aaf6.ts.net/fea/{lang}/{slug}/` (ES sin prefijo de idioma). ## Salida esperada Un **informe único** (CSV + JSON) por ejecución con, por URL: idioma esperado, status, URL final (¿redirige?), idioma detectado, nº enlaces rotos salientes, flags (`SPANISH_LEAK`, `CROSS_LANG_REDIRECT`, `BROKEN_LINK`, `LAYOUT_DIFF`, `LLM_FLAGGED`). Ordenable por gravedad. Que de un vistazo se vea qué arreglar. ## Implementación por fases (entregables en `tools/e2e/`) 1. **Fase A (máxima prioridad):** crawler (Capa 0) + lang-detect (Capa 1) → informe CSV. Determinista, coste cero. Ya caza la mayoría de bugs actuales. 2. **Fase B:** regresión visual (Capa 2) con baseline. 3. **Fase C:** review LLM local (Capa 3) solo sobre flags, con Gemma (texto+visión). JSON estructurado. 4. **Fase D (opcional):** cron + aviso. ## Criterios de aceptación - `node tools/e2e/<crawler>.js` (o `python`) recorre TODAS las URLs de los 5 idiomas contra el local y genera el informe sin intervención manual. - Detecta correctamente: enlace roto (caso `navidad-3`→404 antes del fix), redirección cross-idioma (caso slug duplicado `/en/colaboradores/`→`/it/...`), y página EN con texto español (caso widget/menú sin traducir). - Coste monetario por ejecución: **0 €** (todo local/OSS). Documentado en README. ## Notas para el implementador (Codex / Minimax) - Lenguaje libre (Node ya está en `tools/e2e`; Python también disponible en WSL con las libs OSS citadas). - **No** introducir dependencias de pago ni servicios cloud. - Empezar por **Fase A** (es lo que más bugs caza con menos esfuerzo). Las capas IA son aditivas y opcionales. - Dejar un `README` en `tools/e2e/` explicando cómo ejecutarlo y cómo leer el informe. - Probar contra LOCAL, nunca asumir que prod es accesible por headless.
rafa closed this issue 2026-06-28 19:15:13 +00:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rafa/feadulta#130