2026-09-19 — Surtidito: home por temas + silo-engine en Linode

1. Home limpio, estructurado por temas

  • scripts/home_feed.py (nuevo): toma reporte/feed.json + reporte/feed-tech.json, deduplica (URL + titular normalizado), descarta lo viejo (--dias, default 3) y clasifica cada nota en un tema editorial fijo.
  • Salida única que consume el home: reporte/home.json.
  • Temas (orden fijo): Mexico, Mundo, Tech/IA, Seguridad, Economia, Ciencia, Cultura. El tema base viene de la categoría de origen; Seguridad/Economia/Ciencia/Cultura se refinan por palabras del titular.
  • hn.py: el home ahora lee home.json y sus tabs son los temas (+ “Todos”); sin links a Fuentes/Radio. Ordena por frescura.
  • asgi.py limpio: solo /, /leer, /leer/descargar, /leer/lectura, /salto como rutas visibles, más endpoints operativos (/subscribe, /robots.txt, /llms.txt, /health, /api/proponer, /aprobar, /webhook/resend, /api/cron). Fuera: ediciones, fuentes, radio, cursos y sus helpers. Verificado: esas rutas devuelven 404.

Comandos:

.venv/bin/python feed.py --tech && .venv/bin/python feed.py --out reporte/feed.json --limite 60
.venv/bin/python scripts/home_feed.py --dias 3 --max 400

2. silo-engine (aparte) en el Linode

Ubicación: ~/nef/silo-engine/ (componente aparte; no vive en surtido).

  • recursos.json: 127 fuentes agrupadas por tema (65 RSS + 56 X + 6 Telegram), generadas desde surtido/feed.py + channels-todo.json.
  • silo_engine.py:
    • recursos reconstruye recursos.json.
    • capturar trae RSS + X + Telegram (vía RSSHub), clasifica por tema, deduplica y guarda en data/silo.db (SQLite), data/silo.jsonl (append), data/ultimo.json y data/estado.json (conteos + errores por fuente).
    • estado imprime el último estado.
  • run.sh (con flock anti-solapamiento) y deploy.sh (rsync + venv + feedparser + token + RSSHub + crontab).

Despliegue (Linode [IP], root, key ~/.ssh/linode_root):

  • Código en /opt/silo; venv /opt/silo/venv.
  • RSSHub en Docker rsshub-silo, solo [IP]:1200, con TWITTER_AUTH_TOKEN en /opt/silo/.env (chmod 600, nunca en logs).
  • Cron: */30 * * * * /opt/silo/run.sh >> /var/log/silo.log 2>&1 (todo el día).
  • Seed verificado: 1062 items en silo.db → Tech/IA 615 · Mundo 177 · Seguridad 97 · Mexico 93 · Ciencia 46 · Cultura 22 · Economia 12.

Pendientes

  • channels-todo.json (+22 canales) sigue sin commitear.
  • 4 handles PENDIENTE (@fireimages, @gurablo, @lnk, @promakos_) dan timeout en X; @philosophymemo0 y @LWN dan 503. Reintentan en cada corrida.
  • home_feed.py es manual: falta un cron (local o Linode) que regenere home.json y lo publique.
  • Enganchar el silo-engine con news-silo (embeddings/HDBSCAN) para silos por evento.

Resueltos (misma sesión, tras el push)

  • channels-todo.json +22 commiteado y pusheado (b08477c).
  • Cuentas PENDIENTE excluidas de recursos.json (127 → 122 fuentes); ya no ensucian el silo con timeouts.
  • home.json ya no queda manual: hn.py::_cargar_feed lo reconstruye al vuelo (scripts/home_feed.build()) si falta o es más viejo que feed.json/feed-tech.json.
  • Hook a news-silo: silo_engine.py exportar escribe data/silo-textos.json ({"texts": [...], "items": [...]}); el clustering es un paso local: cat data/silo-textos.json | ~/nef/news-silo/.venv/bin/python silo.py -o data/silos.json.

Commits

  • 09ce195 home por temas (home.json + asgi solo / /leer /salto).
  • b08477c retrieval + scripts (feeds frescos, fomo-release, likes, channels-todo).