hreflang: curadas las 5 parejas de agosto, y el aviso que no se podía atender

El NIVEL C decía «nada convincente» en belgium, jal-1628 y libro azul, pero eso
era del escáner de vectores: el espejo ES existe y está en la cola de agosto,
no publicado cuando se escaneó. Abiertos los dos lados de cada uno:

  SÍ  Bélgica 89-90    mismas noches (Eupen, 30/31-mar), Petit-Rechain, SOBEPS
  SÍ  JAL 1628         mismo vuelo del 17-nov-86, Terauchi, Callahan y la FAA
  SÍ  Libro Azul       mismo programa y mismas cifras (12.618 / 701)
  SÍ  Colares 1977     misma isla, Operação Prato, testimonio de Hollanda
  SÍ  Teherán 1976     misma madrugada, los dos F-4, el documento de la DIA
  NO  bases nucleares  el EN son DOS casos (Malmstrom y Rendlesham); el ES es la
                       apertura de PURSUE y CINCO bases. Solo comparten Malmstrom

Libro Azul es el que enseña dónde está la línea: los apartados NO coinciden y
aun así es SÍ, porque el SUJETO de los dos es el mismo programa histórico. En
AARO el sujeto del ES era la confrontación con Grusch, y por eso es NO. Y las
bases nucleares traen la lección de AARO repetida: coincidían hasta en el
recuento —1.264 palabras exactas los dos— y no son el mismo artículo. Un número
que cuadra no es prueba de equivalencia.

Declararlas destapó un falso positivo: `violaciones()` solo miraba que ESTE
lado estuviera publicado, así que los tres EN ya publicados con el ES aún
programado salieron como hreflang.missing, recetando un `aplicar` que se niega
—y con razón— porque apuntaría a una URL que no existe. Ahora exige los dos
lados publicados. Un aviso que no se puede atender es ruido, y el ruido acaba
con que nadie mire el informe.

Auditores 42 y 40 limpios, seo-watch sin hallazgos.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ChemaVX
2026-07-29 09:04:32 +00:00
co-authored by Claude Opus 5
parent 2ec9b228f0
commit f4121d11bb
2 changed files with 90 additions and 6 deletions
+22
View File
@@ -161,6 +161,18 @@ def cambios():
return plan + huerfanos(parejas), avisos, parejas
_PUB_OTRO = {}
def publicados(site):
"""Slugs publicados del OTRO sitio, cacheado. Hace falta para no cantar una
violación que no se puede arreglar (ver `violaciones`)."""
if site not in _PUB_OTRO:
_PUB_OTRO[site] = {s for s, p in trae(site, None).items()
if p.get("status") == "published"}
return _PUB_OTRO[site]
def violaciones(post, site, parejas=None):
"""Regla para el auditor: una pareja declarada que NO lo tiene puesto.
@@ -171,6 +183,13 @@ def violaciones(post, site, parejas=None):
No basta con que exista el bloque: se comprueba que las URLs sean las de ESTA
pareja. Si un slug cambia, el hreflang se queda apuntando al viejo y esto es
lo único que lo cazaría.
Hacen falta los DOS lados publicados, no solo este. Al curar las parejas de
agosto (2026-07-29) quedaron tres EN ya publicados emparejados con un ES aún
programado, y el auditor cantó tres violaciones con una receta que no las
arreglaba: `aplicar` se niega, y con razón, porque el hreflang apuntaría a
una URL que todavía no existe. Un aviso que no se puede atender es ruido, y
el ruido acaba con que nadie mire el informe.
"""
import seo_rules as R
if parejas is None:
@@ -181,6 +200,9 @@ def violaciones(post, site, parejas=None):
return []
if post.get("status") != "published":
return []
otro_site = "es" if site == "en" else "en"
if (par[1] if site == "en" else par[0]) not in publicados(otro_site):
return []
cabeza = post.get("codeinjection_head") or ""
esperado = bloque(*par)
if esperado in cabeza: