Silo de noticias + /lecturas — decisión (2026-09-11)

Contexto: plan aprobado para extraer sitios destino de X, unificar timelines DS/ML/AI y cruzar con second-brain; esta decisión incorpora los descubrimientos de la revisión de ~/nef/decisions/.

# Silo de noticias y /lecturas — plan y constraints (2026-09-11)
 
## Visión
Unificar timelines: (1) X → sitios destino (no tuits), (2) HN + Telegram
hn_best_comments + outsiders MX (izquierda independiente, anti-extractivista,
anti-feudalista, crítica de la tecnología con perspectiva social), (3)
Lobste.rs, (4) medios US/MX con énfasis en análisis (no titulares), (5)
lectura DS/ML/AI, y (6) cruce transversal con second-brain (escuela, libros,
papers). Clave: feed y retrieval.
 
## Decisiones cerradas
1. Sin planes de pago: extracción local vía RSSHub (:1200). Apify/Twillot
   descartados por ahora (se pueden añadir como capa aparte si el volumen
   lo exige).
2. NYT + WaPo + Washington Sun solo RSS público + NewsAPI (100 req/día free;
   NEWSAPI_KEY ya en .env.local). El módulo de sesión subscrita
   (`prensa_sesion.py`) NO se implementa: queda apagado como opción futura
   (usuario se conecta desde MX; acceso "extremadamente cauteloso" solo si
   se decide explícitamente).
3. `/lecturas` es local-first: se genera, el usuario revisa en local y se
   sube "como está". El commit + deploy ES la aprobación (sin gate en código).
4. Términos/conceptos se derivan del second-brain COMPLETO (360 nodos + tags)
   + rama DVS (499 recursos). No se inventan.
5. Silo X = sitios destino; cubre TECH_X (7) + HERMANAS_X (12) = campo
   semántico completo.
 
## Descubrimientos de /decisions (constraints que aplican)
- `2026-09-06-surtido-no-divulgar-receta.md`: el HTML público de /lecturas no
  menciona jerga interna (scripts, rutas, nombres de archivos, instrucciones);
  estados vacíos neutros; el resumen de aprobación es interno; grep pre-deploy.
- `2026-09-09-capa-recursos-dvs-local.md`: DVS es local-only, nunca a nodo.ws;
  sus TÉRMINOS alimentan el catálogo, su CONTENIDO no se publica ni se
  convierte en nodos del grafo ("no inventar memoria").
- `2026-09-08-second-brain-twitter-logica.md` + `2026-09-10-...-operacion.md`
  + `2026-09-09-...-observar-atención.md`: el corpus propio (5,911 tweets +
  130,626 likes, SQLite FTS5 / D1 con búsqueda local-only) es la otra mitad
  de "unificar timelines": el silo es lo entrante, el corpus es el historial
  de atención. Cruce futuro natural: "¿ya me importó esto?" contra likes.
  La señal técnica está en los likes, no en los tweets.
- `[CREDENCIAL].md`: paquete semántico
  (fuente, prioridad, caducidad, versión) y frescura visible. Los JSON del
  silo llevan `fuente`, `fecha`, `generado`; /lecturas muestra frescura.
- `2026-09-06-surtido-auditoria-anti-bots.md`: /lecturas se renderiza estático
  desde JSON; cero fetch/LLM en request; cero endpoints nuevos; sin exponer
  tokens. El hardening ya deployado se respeta.
- `[CREDENCIAL].md`: para el cruce futuro
  noticia→grafo, patrón de revisión humana (stubs, evidencia/inferencia/
  confianza separadas); nada entra directo a content/nodes.
- `2026-09-07-surtido-mesh-cauces.md`: guion.json como semilla semántica;
  contexto para el formato de paquete, no bloqueante.
 
## Plan por fases
F4 → F1 → F2 → F3 → verificación → commit/push → revisión local → deploy.
 
- F4 Términos: `scripts/terminos_desde_second_brain.py` extrae de
  `~/nef/second-brain`: nodos (360: 243 concept, 38 tool, 28 paper, 27
  algorithm, 18 model; tags ml, dl, ai-systems, nlp, retrieval, dataeng,
  stats, cybersec, snn, responsible-ai…) + DVS (`content/resources/`: 499;
  categorías Websites & Tools 128, Media 125, Style Guides 69, Publications
  63, Education 47, Data Sources 45…; temas visualizacion, narrativa,
  diseno-ux, datos-geo) → `terminos_dsml.txt` editable (~700–900 términos).
- F1 Silo X: `feed.py` `_urls_destino()` / `_dominio_basura()` / `_silo_x()`
  sobre TECH_X + HERMANAS_X vía RSSHub; dedupe por URL destino; detecta
  medios nuevos sin RSS; CLI `feed.py --silo` → `reporte/x-silos.json`
  (`post_partida, url_destino, dominio, medio, publicado, terminos[]`).
- F2 Fuentes: `HERMANAS_RSS` += NYT (HomePage/Technology/Science), WaPo
  (world/national https), Washington Sun; flags `analisis`, `paywall`;
  NewsAPI vía `sentimiento.collect_newsapi` con
  `domains=nytimes.com,washingtonpost.com`.
- F3 `/lecturas`: `lecturas.py` → `reporte/lecturas.json` (merge X+TG+RSS+
  NewsAPI; categorías DS/ML/AI/PROG/CHINA-RD; dedupe por URL destino);
  `GET /lecturas` en asgi (patrón /fuentes).
- F5 Verificación: `py_compile` + `git diff --check`; curl local de `--silo`
  y `/lecturas`; commit por fase; push; deploy CLI solo tras revisión local.
 
## Estado
Plan aprobado y persistido. Nada toca S76 (fuera de servicio) ni Linode
(radio); todo local y gratis.
 
## Addendum (misma fecha, ejecución)
- Env real: los secretos viven en `.vercel/.env` (ignorado por git), no en
  `.env.local`. `feed.py`/`lecturas.py` ahora cargan `.env.local` +
  `.vercel/.env`. La llave es `NEWS_API_KEY`; `sentimiento.collect_newsapi`
  acepta ambos nombres (`NEWSAPI_KEY` o `NEWS_API_KEY`).
- Volumen: China y tech ampliados (21 fuentes nuevas: Solidot, V2EX, 少数派,
  爱范儿, OSChina, InfoQ 中国, 钛媒体, 极客公园, Lobsters, Ars Technica,
  TechCrunch, The Verge, 404 Media, Simon Willison, Import AI, The Gradient,
  Alignment Forum, MIT Tech Review, Krebs, The Record, BleepingComputer).
  Topes: 12/fuente y 12/medio. `/lecturas` pasó de 265 a ~810 items.
- Diseño: 9 fuentes dataviz/diseño (FlowingData, Nightingale DVS, The Pudding,
  Visual Capitalist, Information is Beautiful, Storytelling with Data,
  Creative Review, Smashing, A List Apart) con categoría DISEÑO.
- Archivo: `archivo.py` acumula diseño + ML desde `/lecturas` y data/prensa/ a
  `reporte/archivo-diseno-ml.json/.html` (solo metadatos y enlace).
- Acceso cauteloso: `prensa_sesion.py` NO automatiza login con password; usa
  cookies exportadas a mano (`data/prensa-cookies.json`), cola en
  `data/prensa-cola.txt`, máx 2/día/sitio, espera 45–90 s, aborta 401/403/429.
  Texto completo solo en `data/prensa/` (local, ignorado por git); nunca a
  reporte/ ni publicado. `--status` para ver si hay cookies.
- Variante Selenium: `prensa_selenium.py` usa Brave con perfil dedicado
  (`data/prensa-perfil/`): login manual UNA vez (`--login`), cookies persisten
  en el perfil; luego visita la cola con los mismos límites y registro
  compartido con prensa_sesion. Ventana visible, una pestaña, sin headless en
  producción. `--check` verifica driver (Brave 152 verificado).
- Referencias (brecha informativa): `referencias.py` busca sin Google (ddgs;
  SerpAPI si hay llave) por perfil ML/Data/DataViz/Programmer/AI en NYT, WaPo
  y web; filtra relevancia por palabras; consulta Wayback (CDX) y archive.today
  por resultado y acumula en `reporte/referencias.json/.html`. `--preciada URL`
  marca joyas y las respalda (ej. "Twelve Million Phones, One Dataset, Zero
  Privacy", NYT 2019). Límites: 2–4 s entre búsquedas, 1.5–3 s entre archivos.
- Título de NYT/WaPo puede venir basura (403 con <title>dominio): se rechaza
  y se toma del snapshot de Wayback.
- SerpAPI: `SERPAPI_KEY` en `.vercel/.env` (250 consultas/mes). Motor
  `duckduckgo` (sin Google; `SERPAPI_ENGINE` configurable). Contador
  `serpapi_uso` en `reporte/referencias.json`; corte en 240 (`SERPAPI_BUDGET`),
  al agotarse cae a ddgs. `--news` usa ddgs news (gratis, sin gastar).
- Rotación: `cursor` en referencias.json avanza por la matriz perfiles×sitios
  para que cada corrida traiga consultas nuevas.
- Runner local: `scripts/local_news.sh` (lecturas → archivo → referencias;
  `--queries N`, `--archivo N`, `--news`).