2026-09-19 — nef-silo: mejora 4 (búsqueda híbrida) aplicada y desplegada
Repo: ~/nef/nef-silo (commits bf1e422, ae52ea5, más fix de orden).
Qué se hizo
Mejora 4 — búsqueda híbrida en silo_engine.py:
- Embeddings sin dependencias (no hay torch en el Linode): hashing trick
sobre char 3-grams + palabras, 256 dims con signo por hash, L2 normalizado
(
_embed). Multilingüe (CJK incluido), determinista, rápido. - Columna
items.emb(BLOB) +_backfill_emb(enbuscary encapturar). buscarcon consulta: canal léxico BM25 (FTS5) + canal semántico (coseno query↔titular, top 200 recientes, umbral 0.05) → fusión RRF k=60.- Rerank barato: desempate por
capturado(rerank neural diferido; no hay modelo en el server).--solo-lexicapara comparar.
Error 6 — silo.jsonl: _compactar_jsonl() al final de cada capturar:
dedup por url, descarta >30 días, tope 20k líneas, escritura atómica.
Verificado: 2012 → 1351 líneas, 0 dups.
Fix de proceso — pull.sh: ahora solo baja data/. La versión anterior
rsyncaba el código del server y revirtió edits locales sin commitear
(pasó en esta sesión; re-apliqué a mano). Regla: pull = datos, deploy = código.
Verificación (Linode, 21:5x)
- “ataque cibernético a infraestructura”: léxica 0 → híbrida 5 (recupera “ataque a balazos”, “military strike”).
- “inteligencia artificial”: léxica 1 → híbrida 5, respeta filtros tema/lang.
- 1338/1350 items con embedding; FTSMATCH con sintaxis rara no revienta.
estado.jsonahora incluyejsonl_vivos.
Pendiente que sigue (del plan)
- Mejora 5: clustering incremental (fingerprint + LSH + assign-or-open).
- Mejora 6: calidad de silos (c-TF-IDF; KMeans vs HDBSCAN por corpus).
- Mejora 7: robustez/observabilidad (topes por fuente, alertas, —dry-run).
- Rerank neural solo si algún día hay GPU/modelo en el server.
2026-09-21 — Mejora 5 aplicada: clustering incremental de eventos
Commit 5d1cd8d, desplegado y verificado en Linode.
Diseño (versión mínima real)
- Tabla
silos(tema, abierto, ultimo, n) +items.silo_id. - Assign-or-open en cada
capturar: si un item ~similar (MinHash, Jaccard ≥ 0.6) y ~coetáneo (Publicado dentro de 48h, fallback capturado) ya tiene silo → se une; si no, silo nuevo. - Filtro temporal con
publicado: separa columnas semanales/diarias que se capturan juntas (Khrys’presso, Pluralistic quedaron separadas). - Digestos excluidos (
早报|晚报|日报|早知道|快讯|点氪|newsletter|roundup...): no anclan ni se unen a eventos — era la fuente principal de over-merge. reparar(union-find): reconstruye la ventana de 7 días por componentes conexas; reutiliza silo mayoritario existente. 2192 items en 0.46 s.silos(cmd): lista eventos con n≥2 (default).
Tuning con datos reales
- 0.35/0.45: over-merge zh (tokens genéricos “Pro” juntaban 中兴 M3 Pro, Geekbench M6 Pro, 小米 18 Pro). 0.6 = limpio (39 eventos multi en 2192).
- Env para ajustar:
SILO_EVENTO_UMBRAL,SILO_EVENTO_DIAS,SILO_EVENTO_VENTANA_H. - Residuo conocido: pares zh que comparten solo “2026” aún se juntan a veces. Pertenece a mejora 6 (c-TF-IDF / calidad de clusters).
Lección de depuración
Test fallaba con “todos los items comparten silo_id”: mi helper abría conexión
y hacía close() sin commit() → SQLite rollback → todos los INSERT
devolvían rowid 1. El código de producción usa una conexión y commitea:
antes de culpar al código, verificar cómo cierras la conexión en el test.
Estado de producción
Corrida 02:26 UTC: +29 nuevos, 2221/2221 items con silo_id, 0 errores,
jsonl_vivos visible en estado.json.
Siguiente: mejora 6 (calidad de silos: c-TF-IDF para etiquetar eventos; KMeans vs HDBSCAN por tipo de corpus).