validador: un par consolidado no es una colisión, es su solución

topic_collision marcaba como colisión los dos artículos del acto de Grusch
del 9 de junio, cuando el de mayo lleva canonical_url apuntando al otro
desde hace semanas. Google ya sabe cuál manda y Ghost excluye al secundario
del sitemap: no hay nada que arreglar, y el propio mensaje ofrecía
«interlink deliberately» como salida, que es justo lo que había.

Un aviso que no se puede resolver nunca es peor que no avisar, porque
enseña a ignorar al validador entero — la misma razón por la que esta
mañana retiramos la comprobación de reddit-intel de backup-verify.

El par se salta cuando cualquiera de los dos declara canónico al otro. Si
el canónico apunta a un tercero, la colisión sigue avisando: comprobado con
los cuatro casos (sin canónico dispara, en las dos direcciones se calla,
canónico a un tercero dispara). fetch_corpus pide ya canonical_url, que
antes no traía.
This commit is contained in:
ChemaVX
2026-07-28 07:11:51 +00:00
parent f7be9ccb3e
commit 1febcfe03b
2 changed files with 25 additions and 1 deletions
+22
View File
@@ -270,6 +270,19 @@ def _sig_tokens(title, slug):
if len(t) >= 3 and t not in TOPIC_STOPWORDS and not _YEAR_RE.fullmatch(t)}
def _canoniza_a(post):
"""Slug al que este post declara canónico, o None si no declara ninguno.
Ghost guarda una URL completa; aquí solo interesa el último segmento, que es
lo único comparable con el slug de otro post del mismo sitio.
"""
url = _s(post.get("canonical_url"))
if not url:
return None
resto = url.split("?")[0].split("#")[0].rstrip("/")
return resto.rsplit("/", 1)[-1] or None
def _hook(title):
return _s(title).split(":")[0].strip().lower()
@@ -290,10 +303,19 @@ def topic_collision(post, corpus):
c_hook = _hook(post.get("title"))
c_slug_toks = _tokens(_s(post.get("slug")).replace("-", " "))
c_canon = _canoniza_a(post)
for other in corpus:
if other.get("id") == post.get("id"):
continue
o_title, o_slug = _s(other.get("title")), _s(other.get("slug"))
# Un par consolidado NO es una colisión: es la solución a una colisión.
# Cuando uno de los dos declara al otro como canónico, Google ya sabe
# cuál manda y Ghost excluye al secundario del sitemap. Marcarlo sería
# pedir que se arregle algo que está arreglado — y el aviso, al no poder
# resolverse nunca, enseña a ignorar al validador.
if c_canon == o_slug or _canoniza_a(other) == _s(post.get("slug")):
continue
o_years = _case_years(o_title, o_slug)
o_sig = _sig_tokens(o_title, o_slug)