# fea-verify — Verificación automática del sitio (issue #121) Proceso por capas para validar el multiidioma del WP local **sin coste** (todo OSS + Gemma local). Se ejecuta **contra el LOCAL** `https://farmer.taild3aaf6.ts.net/fea/` (prod está tras Cloudflare y bloquea headless). ## Principio Lo determinista (barato, exhaustivo) primero; el LLM solo sobre lo que las capas baratas marcan. ## Capas / scripts | Paso | Script | Qué hace | Coste | |------|--------|----------|-------| | Enumerar | `enum_urls.php` (en contenedor `wordpress-web`) | Saca de la BD todas las URLs: menús×5 idiomas, categorías con contenido, contenido no-ES. → `urls.json` | 0 | | Capa 0+1 crawl | `crawl.cjs` (Playwright) | status HTTP, URL final (redirección cross-idioma), ``, texto visible, enlaces salientes. Resumible. → `report.jsonl` | 0 | | Capa 1 análisis | `analyze.py` (lingua, venv) | detección de idioma offline + flags. → `report.json` + `report.csv` | 0 | | Capa 0 enlaces | `link_audit.py` (stdlib) | comprueba status de los enlaces internos hallados. → `broken_links.json` | 0 | | Capa 3 (opcional) | `llm_review.py` (Gemma local) | review semántica SOLO de páginas marcadas. → `llm_review.json` | 0 | ## Requisitos (una vez) - Node + Playwright: ya en `tools/e2e/node_modules`. - venv con lingua: `python3 -m venv verify/.venv && verify/.venv/bin/pip install lingua-language-detector` - Docker WP arriba (`wordpress-web`, `wordpress-mysql`), LM Studio con `google/gemma-4-e4b` (solo Capa 3). ## Ejecutar (todo) ```bash cd tools/e2e/verify # 1) enumerar URLs desde la BD docker cp enum_urls.php wordpress-web:/tmp/ && docker exec wordpress-web php /tmp/enum_urls.php && docker cp wordpress-web:/tmp/verify_urls.json urls.json # 2) crawl (resumible; borra report.jsonl para empezar de cero) CONC=5 node crawl.cjs # 3) análisis + flags .venv/bin/python analyze.py # 4) enlaces rotos python3 link_audit.py # 5) (opcional) review LLM local sobre lo marcado .venv/bin/python llm_review.py ``` ## Leer el resultado - **`report.csv`** — lo accionable, ordenado por gravedad. Columnas: `sev`(3 crítico→1 aviso), `flags`, `lang`, `kind`, `status`, `detected`(idioma detectado), `conf`, `redir`, `url`, `final`. - **`broken_links.json`** — enlaces internos rotos + qué páginas los referencian. - **`report.json`** — todo, en JSON. ### Flags - `HTTP_5XX` / `HTTP_4XX` / `CRAWL_ERROR` — la página falla (p.ej. el 500 de `/en/category/letters-from-other-weeks/`). - `CROSS_LANG_REDIRECT` — pediste `/en/x/` y acabaste en otro idioma (bug de slug duplicado). - `SPANISH_LEAK` — página no-ES cuyo texto detectado es español (sin traducir / widget en ES). - `LANG_MISMATCH` / `HTML_LANG_MISMATCH` — idioma del texto / del `` ≠ esperado. ## Scope de la corrida Por defecto crawlea: menús (5 idiomas), categorías con contenido, y **todo el contenido no-ES** (~3.9k). El contenido ES masivo (~24k) se omite por volumen; añadirlo es cambiar la query de `enum_urls.php`. ## Coste **0 €.** Sin SaaS ni APIs de pago. Detección de idioma offline (lingua) y review con Gemma local. Minimax NO se usa.