Commit Graph
3 Commits
Author SHA1 Message Date
ChemaVXandClaude Opus 4.8 7b92079c41 seo_exceptions: ámbito por sitio — los dos blogs, independientes de verdad
Los waivers se indexaban SOLO por slug. Hoy no hay colisiones (los slugs ES
van en español), pero nada lo impedía: un slug repetido entre blogs habría
aplicado en silencio la excepción del sitio equivocado, y ese post habría
dejado de auditarse sin que nadie se enterara. Riesgo latente, no activo — pero
'no pasa hoy' no es lo mismo que 'no puede pasar'.

  EXCEPTIONS[site][familia][slug] = razón
  accepted_reason(rule, slug, site='en')

El default 'en' mantiene funcionando a seo_audit.py sin tocarlo (es EN-only).
seo_watch y seo_finish pasan el sitio activo explícitamente.

Añadido collisions(): lista los slugs waiveados en más de un sitio. Debe estar
siempre vacío; si algo aparece ahí, hay una excepción ambigua que revisar.

Verificado: mismo slug waiveado en EN se audita con normalidad en ES; los 16
waivers EN intactos; seo_audit, seo_watch (ambos sitios) y seo_finish (ambos
sitios) siguen dando los mismos resultados que antes del cambio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 16:16:47 +00:00
ChemaVXandClaude Opus 4.8 34263469e4 seo_finish: soporte para el sitio ES (--site en|es)
El blog ES no tenía forma de llegar desde las herramientas: solo existía el
wrapper ghst-en. Creado ghst-es (gemelo, namespace zona-exclusion, token
efímero del pod, nada en disco) y parametrizado seo_finish.

Ojo al canónico, que va al revés en cada sitio: EN es www, ES es el apex.

seo_rules.SITE_HOST está fijado a EN y NO se parametriza ahí a propósito: ese
fichero se vendoriza byte a byte dentro de ResearchOwl y la CI lo verifica.
Se reasigna en tiempo de ejecución desde use_site(), que deja intacto el
contrato compartido.

Los ficheros de trabajo (imagen convertida, volcado de texto) y los backups
llevan ahora prefijo de sitio, para que un mismo slug en ambos idiomas no se
pise.

Verificado contra los dos sitios: ES detecta las 8 violaciones del borrador
nuevo (todas por dryrun, que ya no escribe SEO) y EN sigue dando 0 en el
artículo belga publicado hoy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 16:06:43 +00:00
ChemaVXandClaude Opus 4.8 162f8032f3 seo_finish: remate SEO posterior a la revisión editorial (Tool E)
El SEO es DERIVADO del artículo. Hoy ResearchOwl lo genera al crear el
borrador, pero la revisión editorial cambia el texto después → el SEO queda
obsoleto y hay que rehacerlo a mano en cada post. La solución no es parchear
sino re-derivarlo del texto FINAL, y ese es el hueco que cubre esta tool.

Además el alt-text SOLO puede escribirse aquí: cuando autofill.py genera el
SEO la imagen destacada aún no se ha elegido (de ahí su
'feature_image_alt': ""  # human adds later). Ese paso humano no ocurría
nunca — los 9 posts publicados entre el 29-jun y el 16-jul salieron sin alt.

  prep <slug>   paquete de revisión: descarga la imagen destacada y la
                convierte a PNG (Ghost sirve webp), vuelca el texto final,
                lista el SEO actual con longitudes y las violaciones. READ-ONLY.
  apply <slug>  aplica un patch vía ghst-en, con backup previo, y RE-VALIDA
                después (si sigue incumpliendo, lo dice).

Guardas por límites duros, para convertir en error explicado lo que Ghost
devuelve como 422 mudo:
  * feature_image_alt > 191 car. (límite de Ghost, descubierto a base de 422)
  * meta_description > 145 / meta_title > 60 (seo_rules)

El criterio (redactar la meta, describir la imagen) lo pone quien invoca —
humano o Claude vía hermes. El script hace lo mecánico y lo verifica.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 10:14:52 +00:00