fix(ghost): find_draft_by_title compara títulos normalizados, no igualdad exacta
Si Ghost normaliza el título al guardar (trunca a 255 un H1 largo del LLM, colapsa whitespace), la igualdad exacta no encontraba el draft recién creado y la recuperación fallaba justo en el escenario que debe cubrir. _norm_title aplica el mismo colapso+truncado a ambos lados de la comparación. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
634f38e016
commit
b58a3ce118
@@ -385,6 +385,14 @@ def _seo_dryrun_message(ghost: "GhostPublisher", post: dict, seo: dict, inserted
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _norm_title(t: str) -> str:
|
||||||
|
"""Normaliza un título para compararlo con lo que Ghost almacenó: colapsa
|
||||||
|
whitespace y trunca a 255 chars (límite de posts.title en Ghost — un H1
|
||||||
|
largo del LLM puede volver truncado/normalizado, y la igualdad exacta
|
||||||
|
fallaría justo en los casos que el guard debe cubrir)."""
|
||||||
|
return " ".join((t or "").split())[:255]
|
||||||
|
|
||||||
|
|
||||||
def _parse_ghost_ts(ts: str) -> float | None:
|
def _parse_ghost_ts(ts: str) -> float | None:
|
||||||
"""created_at de la Admin API (ISO 8601, p.ej. 2026-07-04T20:26:00.000+00:00
|
"""created_at de la Admin API (ISO 8601, p.ej. 2026-07-04T20:26:00.000+00:00
|
||||||
o sufijo Z) → epoch. None si no parsea."""
|
o sufijo Z) → epoch. None si no parsea."""
|
||||||
@@ -438,7 +446,9 @@ class GhostPublisher:
|
|||||||
(p.ej. decode roto), el draft existe aunque el caller viera una
|
(p.ej. decode roto), el draft existe aunque el caller viera una
|
||||||
excepción. Con `since` (epoch) solo casan drafts creados en este
|
excepción. Con `since` (epoch) solo casan drafts creados en este
|
||||||
intento — un draft viejo del mismo título de una run anterior NO cuenta
|
intento — un draft viejo del mismo título de una run anterior NO cuenta
|
||||||
como "ya publicado". Best-effort: None si no hay match o si falla."""
|
como "ya publicado". La comparación usa _norm_title (whitespace
|
||||||
|
colapsado + truncado a 255) para sobrevivir la normalización de Ghost.
|
||||||
|
Best-effort: None si no hay match o si falla."""
|
||||||
import aiohttp as _aio
|
import aiohttp as _aio
|
||||||
token = self._make_token()
|
token = self._make_token()
|
||||||
url = (
|
url = (
|
||||||
@@ -458,8 +468,9 @@ class GhostPublisher:
|
|||||||
if resp.status != 200:
|
if resp.status != 200:
|
||||||
return None
|
return None
|
||||||
data = await resp.json()
|
data = await resp.json()
|
||||||
|
wanted = _norm_title(title)
|
||||||
for p in data.get("posts", []):
|
for p in data.get("posts", []):
|
||||||
if p.get("title") != title:
|
if _norm_title(p.get("title") or "") != wanted:
|
||||||
continue
|
continue
|
||||||
if since is not None:
|
if since is not None:
|
||||||
created = _parse_ghost_ts(p.get("created_at") or "")
|
created = _parse_ghost_ts(p.get("created_at") or "")
|
||||||
|
|||||||
Reference in New Issue
Block a user