feat(seo): fijar vocabulario de tags ES en el autofill
Build & Deploy ResearchOwl / build-and-push (push) Successful in 6s

Cierra el TODO de ALLOWED_TAGS: el allow-list ES son los 6 tags del
núcleo vivo de zonadeexclusion (Admin API, 2026-07-03), espejo de la
lista EN confirmada: uap, desclasificados, casos-militares,
casos-clasicos, investigacion, casos-espana. Quedan fuera la cola de
tags de 1 post que el modelo inventó antes de constreñir y el duplicado
investigacion-2 (colisión de mayúsculas en Ghost).

La regla anti-legacy 'never use "investigacion"' del prompt pasa a ser
solo-EN: en ES ese slug es el tag canónico del allow-list.

Tests de las funciones puras (_coerce, _system_prompt) por idioma.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
ChemaVX
2026-07-03 07:52:26 +00:00
co-authored by Claude Fable 5
parent b872d00efc
commit 19efc70539
2 changed files with 52 additions and 4 deletions
+13 -4
View File
@@ -37,14 +37,19 @@ SITE_BY_LANG = {
# Tag allow-list — the model may ONLY pick from these; invented tags are dropped
# deterministically after the call (never trust the LLM to self-limit). EN is the
# live vocabulary Jose confirmed; ES is not yet constrained, so we don't enforce
# it (model picks freely there until an ES vocab is pinned down).
# live vocabulary Jose confirmed; ES is the live core taxonomy on zonadeexclusion
# (fetched 2026-07-03), mirroring EN. Deliberately excluded from ES: the one-post
# long-tail tags the model invented before constraining, and "investigacion-2"
# (a Ghost case-collision duplicate of "investigacion").
ALLOWED_TAGS = {
"en": [
"uap", "declassified", "military-cases", "classic-cases",
"investigation", "spain-cases", "latin-america",
],
# "es": [...] # TODO: pin the live ES tag vocabulary before constraining.
"es": [
"uap", "desclasificados", "casos-militares", "casos-clasicos",
"investigacion", "casos-espana",
],
}
# Language-aware default tag when nothing from the allow-list fits / the model
@@ -116,9 +121,13 @@ async def fetch_published_menu(lang: str) -> list[dict]:
def _system_prompt(lang: str) -> str:
allow = ", ".join(ALLOWED_TAGS.get(lang, []))
out_lang = "SPANISH" if lang == "es" else "ENGLISH"
# The anti-legacy "never use investigacion" rule is EN-only: on the ES site
# "investigacion" IS the canonical tag (and the allow-list already excludes
# the "investigacion-2" duplicate).
legacy_clause = ", never use \"investigacion\"" if lang == "en" else ""
tag_clause = (
f"TAGS: choose 2-4 tags ONLY from this exact list (never invent a tag, "
f"never translate it, never use \"investigacion\"): {allow}.\n"
f"never translate it{legacy_clause}): {allow}.\n"
if allow else
"TAGS: 2-4 lowercase-hyphenated topical tags appropriate to the article.\n"
)