Files
ChemaVXandClaude Opus 5 20c8d03aa7
Build & Deploy ResearchOwl / build-and-push (push) Successful in 9s
feat(short): generación y render de Shorts vía shortsmith
Añade /generate short_en y /short_spec. El pipeline genera un shot spec
con Haiku, verifica cada cifra, fecha y cita contra los chunks de la
sesión, lo renderiza en shortsmith y entrega el MP4 por Telegram junto
a un informe de claims.

- ShortsmithClient con sondeo y fallback al spec JSON si el render falla
- Contrato de plantillas obtenido de GET /templates, no codificado
- Comprobación de fundamento determinista, sin LLM
- outputs.published_url para enlazar el artículo de Ghost
- Normalización de comillas rectas a tipográficas (ver KNOWN-ISSUES.md)

Lo que no aparece en los chunks se contrasta contra el ejemplo del
prompt: si casa ahí es fuga, no invención, y se informa como tal. El
purgado de sesiones se lleva también su MP4.

La subida a YouTube queda fuera a propósito: fase 3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 21:55:42 +00:00

36 lines
1.4 KiB
Python

"""Separación de capas.
`bot/` puede importar de todo; nadie puede importar de `bot/`. El progreso y
los callbacks viajan como callables genéricos justo para no necesitarlo.
"""
import re
from pathlib import Path
SRC = Path(__file__).resolve().parents[1] / "src"
LOWER_LAYERS = ("generator", "scraper", "processor", "db", "seo", "news")
IMPORTS_BOT = re.compile(r"^\s*(from\s+src\.bot|import\s+src\.bot|from\s+\.\.bot)",
re.MULTILINE)
def test_no_lower_layer_imports_from_bot():
offenders = []
for layer in LOWER_LAYERS:
for path in (SRC / layer).rglob("*.py"):
if IMPORTS_BOT.search(path.read_text(encoding="utf-8")):
offenders.append(str(path.relative_to(SRC.parent)))
assert not offenders, f"importan de bot/: {offenders}"
IMPORTS_TELEGRAM = re.compile(r"^\s*(from\s+telegram|import\s+telegram)", re.MULTILINE)
def test_the_short_pipeline_takes_progress_as_a_plain_callable():
"""La comprobación concreta para lo añadido en fase 2: si algún día alguien
mete un `Message` de Telegram aquí, este test lo dice. Nombrar Telegram en
un comentario vale — importarlo, no."""
for module in ("short.py", "shortsmith.py", "shortspec.py", "grounding.py",
"spec_contract.py"):
source = (SRC / "generator" / module).read_text(encoding="utf-8")
assert not IMPORTS_TELEGRAM.search(source), f"{module} importa telegram"