Mazinger Knowledge Graph

Arquitectura visual del grafo de conocimiento que conecta cartera, contactos, documentos, conversaciones y análisis financieros del fondo. Pensado para entender de un vistazo cómo fluye la data y qué se puede hacer con ella.

Índice

  1. ¿Qué es esto?
  2. Estado actual del grafo
  3. Modelo del grafo (nodos + aristas)
  4. De dónde viene la data
  5. Cómo se mantiene actualizado
  6. Cómo lo usa el agente Claude
  7. Casos de uso con queries reales
  8. Antes vs ahora (modelo B-completo implementado)
  9. Lo que queda

01 ¿Qué es y por qué importa?

Un Knowledge Graph es una base de datos donde la información se modela como nodos (cosas: empresas, personas, documentos, reuniones) y aristas (relaciones entre cosas: "esta persona trabaja en", "este deck menciona", "esta reunión fue con"). Lo que esto desbloquea para un fondo PE/VC es conexión entre todas las piezas de información que hoy viven aisladas en distintos sistemas.

6 cosas que el KG habilita

1 · Dossier instantáneo

30 min → 5 segundos. Lo que antes requería abrir Drive + Gmail + Notion + Excel + Granola para armar un dossier de Citibox, ahora es una query.

✓ Hoy

2 · Conexiones invisibles

"3 de mis founders vienen de Glovo" → detectado automático cruzando decks de cartera con LLM extraction. Insight que SQL plano no descubre.

✓ Hoy

3 · Memoria del cliente

El agente recuerda lo que dijiste sobre Citibox la semana pasada. Cada mensaje se extrae a Mentions estructuradas con quote + timestamp.

⚠ Parcial — backfill 2858 msgs pendiente

4 · Una persona, una identidad

1 persona = 1 nodo, aunque esté en el CRM de varios miembros del fondo. El linker consolida por email canónico y conserva el contexto per-user en la arista IN_CRM_OF (cargo, fuente, fecha).

✓ Modelo B-completo implementado 2026-05-15

5 · Trazabilidad LP-grade

Cada recomendación rastreable hasta su fuente. Cuando el agente sugiere algo, sabés exactamente qué quarterlies, meetings y emails leyó para llegar ahí.

⚠ F7 Recommendation pendiente

6 · El sistema te avisa

De analyst que busca a sistema que alerta. Patterns nightly: "3 participadas con cambio CEO + drop headcount" → notif por WA antes que vos lo notes.

⚠ F6 pendiente — foundation lista

¿Cómo lo entrega técnicamente?

A · Modelado relacional explícito

13 tipos de nodos + 7 tipos de aristas representan la realidad operativa del fondo. Cada pregunta del negocio se traduce a un path en el grafo: (Directa)-[:HOLDS]->(Company) <-[:ABOUT]-(Document)-[:HAS_MENTION]->(:Mention)-[:OF]->(Competitor).

Schema canónico en docs/kg/kg-schema.md.

B · Extracción LLM async

Cada texto que entra al sistema (deck, email, meeting summary, mensaje WA) pasa por un LLM Haiku que detecta entidades mencionadas y las atan al nodo canónico via :Mention. No depende de búsqueda exacta — el LLM entiende contexto y abreviaciones ("Glovo", "Glovo Apps", "@glovo").

~10s en background, ~$0.0001 por texto.

C · Entity linker 4-tier

Cuando aparece una mención nueva, un linker decide a qué nodo canónico atarla con 4 estrategias en cascada: identifier exacto (email/linkedin/tax_id) → name exactfuzzy matchLLM disambiguate si hay ambigüedad real.

Evita duplicación de identidades. Detalle en kg_entity_linker.py.

Por qué un grafo (y no SQL o vectores)

La magia se ve cuando una pregunta necesita saltar entre cosas distintas — muchas veces. Acá la comparación visual:

¿Quién es el CEO de Citibox?

1 salto · trivial
Citibox
1
tiene como CEO a
David Pascual
1 conexión. SQL, vectores y grafo lo resuelven todos. Sin diferencia real.

¿Qué founders de mi cartera vienen de Glovo?

5 saltos · cross-source
Mi Fondo (Mazos)
1
invierte en
Citibox
2
tiene un deck
Pitch Deck Series E
3
menciona a una persona
"David Pascual — Ex-Glovo"
4
que es
David Pascual
5
trabajó antes en
Glovo ✓
5 saltos. Una sola pregunta. El grafo lo navega en ~80ms. Descubre 3 founders ex-Glovo en cartera → patrón sectorial.
Tipo de pregunta SQL clásico RAG vectorial Knowledge Graph
"¿CEO de X?" ⚠ aprox
"¿Quién menciona a X?" ⚠ lento
"¿Conexión entre X e Y?" ✗ inviable ✗ se pierde
"¿Patrones cross-empresa?" (cartera ex-Glovo, etc.) ✓ único

La diferencia clave: SQL piensa en tablas (bueno para "qué tengo"). Vectores piensan en similitud (bueno para "qué se parece"). Los grafos piensan en conexiones (único para "cómo se relaciona").

Pieza arquitectural clave: el grafo NO reemplaza Postgres. Postgres sigue siendo la fuente de verdad — ahí viven los datos operacionales del CRM. El KG es una vista derivada optimizada para preguntas de relaciones, que se sincroniza automáticamente con 3 capas defensivas (backfill + hooks live + reconcile nightly). Si Neo4j cae, Postgres sigue operativo; cuando vuelve, el grafo se reconstruye.
El valor diferencial vs alternativas: vs SQL plano = queries cross-source rápidas; vs Notion/Airtable = relaciones a 2-3 hops sin joins manuales; vs Cala AI (data externa) = data de tu universo (cartera + CRM + docs propios); vs RAG vectorial = identidad estructurada y trazabilidad exacta de la cita.

02 Estado actual del grafo

Total de nodos
1,231
15 tipos distintos
Total de aristas
1,225
10 tipos de relación
Hooks live activos
24
propagación automática
Fuentes integradas
8
Postgres + WhatsApp + Drive + Granola + Gmail + Holded + Cala + LLM

Distribución de nodos por tipo

Document — pitch decks, balances, contratos, notas
Mention — referencias detectadas por LLM
Company — empresas (cartera + leads + externas)
Person — personas del CRM y mencionadas · consolidada por email
DailyMemory — resúmenes diarios omzg
Directa — inversiones del fondo
Email — emails de Gmail/Outlook
Meeting — reuniones de Granola
QuarterlyUpdate — datos trimestrales
FinancialAnalysis — análisis estructurados
Conversation — hilos WA/TG
Fondo — fondos de inversión
User — miembros del fondo · lee Invitations
Organization — empresas operadoras del fondo (Mazos, Umbratech, Greelow, Inspirit)
Fund — raíz explícita del fondo Mazos
TipoQué representaDe dónde vieneNodos
:DocumentPitch decks, balances, contratos, NDAs, meeting notes GranolaDrive watcher + email pipeline + sync ETL318
:MentionCada vez que el LLM detecta una entidad en un texto, con quoteExtracción LLM (Haiku) post-OCR248
:CompanyEmpresas (cartera + CRM + externas mencionadas)Postgres companies + extracción LLM212
:PersonContactos del CRM y personas extraídas, 1 nodo canónico por email (ya no se duplica por user)Postgres kb_personas + LLM, agrupado111
:DailyMemoryResúmenes diarios de actividad por usuarioomzg_memory_svc nightly76
:DirectaCada inversión directa del fondo (1 ticker = 1 directa)Postgres directas67
Emails procesados por Kabutoemail_pipeline → kb_interacciones51
:MeetingReuniones registradas (Granola)granola_ingest → kb_interacciones48
:QuarterlyUpdateUpdates financieros trimestrales de carteraPostgres quarterly_updates40
:FinancialAnalysisAnálisis financieros estructurados (extracted_data, key_metrics)finanzas_service tras OCR21
:ConversationHilos de WhatsApp/Telegramomzg_orchestrator18
:FondoFondos de inversión que el grupo gestionaPostgres fondos12
:UserMiembros del fondo (1 por Invitation con phone)Postgres invitations · phone normalizado5 (14 prod)
:OrganizationOrgs operadoras del fondo (Mazos, Umbratech, Greelow, Inspirit)Auto-inferida por email domain de cada User3 (5 prod)
:FundRaíz explícita del fondo gestor (Mazos)Hardcoded — único fondo gestor por ahora1

Aristas — cómo se conectan los nodos

AristaOrigen → DestinoSignificadoCantidad
ABOUTDocument/Email/Meeting/FinAnalysis → Company"Este documento es sobre esta empresa"400
HAS_MENTIONDocument/Email/Meeting/Conv → Mention"Este texto contiene esta mención específica"248
OFMention → Company/Person"Esta mención se refiere a esta entidad"189
WITHMeeting → Person"Esta reunión tuvo como attendee a esta persona"94
OPERATESFund → Directa/Fondo"Este fondo opera esta inversión" — cierra la jerarquía institucional79
HOLDS_DIRECTADirecta → Company"Esta inversión es sobre esta empresa"67
WORKS_ATPerson → Company"Esta persona trabaja en esta empresa"62
DELIVERED_BYDocument → Person"Este doc lo trajo esta persona (sender)"43
IN_CRM_OFPerson → User"Esta persona está en el CRM de este miembro del fondo" — preserva cargo/fuente/fecha per-user, una persona puede tener N aristas39
MEMBER_OFUser → Organization"Este miembro pertenece a esta org operadora" — inferida por email domain4

03 Modelo del grafo: cómo se conecta todo

El siguiente diagrama muestra los tipos de nodo y cómo se relacionan entre sí. Cada flecha es una arista típica del grafo.

Modelo B-completo Identidad institucional explícita

Encima del diagrama clásico (Cartera · Sources · Identidad · Memoria) se agrega una capa institucional: :Fund {id:'mazos'}OPERATES:Directa/:Fondo; :UserMEMBER_OF:Organization; :PersonIN_CRM_OF:User (con cargo/fuente/fecha por arista).

Grafo interactivo · arrastrá cualquier nodo · scroll para zoom · click derecho para liberar
Estructural (ABOUT, HOLDS, WITH, DELIVERED_BY)
Extracción LLM (OF, HAS_MENTION)
Modelo B-completo (OPERATES, IN_CRM_OF, MEMBER_OF)
WORKS_AT (Person → Company)
CARTERA DEL FONDO Directa 67 Company 210 Fondo 12 Quarterly Update 40 HOLDS_DIRECTA OWNS ABOUT FUENTES — CAPTURAN INFORMACIÓN Document 318 Email 51 Meeting 48 Financial Analysis 21 Daily Memory 76 Conver- sation 18 ABOUT (400 aristas) LLM EXTRACTION — DETECCIÓN DE ENTIDADES MENCIONADAS Mention 248 HAS_MENTION (248) OF (189) PERSONAS Person 130 User 1 OF WORKS_AT (78) WITH (94) DELIVERED_BY (43) LEYENDA DE ARISTAS Estructural (ABOUT, HOLDS, WITH, DELIVERED_BY) Extracción LLM (OF — Mention apunta a entidad) Personas (WORKS_AT — persona en empresa) Las flechas representan la dirección de la relación. Cada arista tiene su contador real entre paréntesis.

Cómo leerlo — 4 capas claras: arriba está la cartera (Directa, Company, Fondo, Quarterly), al medio están las fuentes que capturan información del día a día (Document, Email, Meeting, FinAnalysis, Memory, Conversation), abajo está el extractor LLM que produce Mentions, y a la derecha viven las personas. Cualquier query atraviesa estas 4 capas en pocas aristas.

04 De dónde viene la data

El grafo no inventa nada — toda la información viene de fuentes reales del sistema. Hay 8 entradas activas:

Source 1 · Postgres CRM (cartera + contactos)

Las tablas companies, directas, fondos, transferencias, quarterly_updates, kb_personas son la fuente de verdad. Se sincronizan al grafo via backfill (one-shot) + reconcile nightly.

Modificable manualmente vía dashboard o API.

Source 2 · WhatsApp / Telegram (omzg)

Cuando un user manda un mensaje al bot (omzg_orchestrator), se persiste en omzg_messages y se dispara kg_ingest_omzg: extracción LLM + linking → Mentions en el grafo.

En tiempo real. Hook fire-and-forget.

Source 3 · Google Drive (drive_watcher)

Cada PDF/DOCX/XLSX nuevo en el Drive del fondo se descarga, OCR-ea, clasifica con LLM, persiste en kb_documentos y dispara kg_ingest_drive.

Cada 8 minutos via cron Kabuto.

Source 4 · Granola (notas de meetings)

Granola envía summaries de cada Google Meet/Zoom transcripto. Entran a kb_interacciones tipo "Reunión" con full_content.

Sync nightly. Crea :Meeting nodes.

Source 5 · Gmail (email pipeline)

El pipeline de Kabuto procesa emails entrantes, extrae attachments, classifica via LLM y persiste en kb_interacciones tipo "Mail" + kb_documentos.

Cada 5 minutos.

Source 6 · Holded ERP (preparado, sin data hoy)

Cuando se conecte: facturas y treasury van a holded_invoices. Pipeline preparado para crear :Invoice nodes con tax_id como identidad legal.

0 filas hoy.

Source 7 · Cala AI (data externa)

El agente Claude usa el MCP HTTP oficial de Cala para enriquecer empresas con data del universo VC global (CEOs, founders, funding rounds).

On-demand desde el agente, no batch.

Source 8 · Extracción LLM (cross-source)

Sobre el texto de cualquier source (doc, email, meeting summary, mensaje WA), un LLM Haiku detecta entidades mencionadas y crea :Mention nodes con quote y contexto.

Async via ThreadPoolExecutor (max 4 workers). ~10s por source con texto.

05 Cómo se mantiene actualizado: 3 capas defensivas

Cualquier cambio en Postgres (nuevo contacto, nuevo doc, nueva interacción) se refleja en el grafo en menos de 30 segundos — automáticamente. Si algo falla, hay 2 capas más de respaldo.

CAPA 1 · BACKFILL ONE-SHOT sync_all(db) Lee toda Postgres → MERGE al grafo. Idempotente (re-run no duplica). Manual o desde script: python scripts/kg_sync_run.py 18 funciones de sync companies, directas, fondos, transferencias, quarterly, personas, users, organizations, fund, documentos, interacciones, eventos… CAPA 2 · HOOKS LIVE kg_hook(obj) Después de cada db.commit() en routers. 2 pasos: sync sync (~50ms) + extract LLM async (~10s background). Endpoints siguen rápidos. 24 hook points activos 17 en routers/kabuto.py 3 en finanzas_service.py + omzg_orchestrator + drive_watcher + omzg_memory_svc + linkedin_enrichment CAPA 3 · RECONCILE NIGHTLY kg_reconcile_nightly Cron 04:30 UTC. Re-corre sync_all() entero. Red de seguridad: si la capa 2 falló por algún motivo (Neo4j caído, bug, write SQL directo), el grafo se sincroniza al menos 1x/día. Lag máximo: 24h Aceptable para escenarios edge. MERGE idempotente — no duplica.
Garantía de consistencia eventual: bajo cualquier escenario (Neo4j cae, hook falla, deploy rompe algo, alguien escribe SQL directo a Postgres), el grafo está actualizado en máximo 24 horas. En operación normal, en menos de 30 segundos.

Ejemplo: Kabuto crea un contacto nuevo en el CRM

1
Kabuto procesa un email entrante de "alex@acme.com"
El email pipeline lo clasifica y decide upsertar a Alex como contacto nuevo.
~ms
2
Kabuto llama POST /kabuto/personas/upsert al backend
El router recibe el body, hace UPSERT en kb_personas, db.commit() exitoso.
~50ms
3
Hook live: kg_hook(persona)
Detecta que es un KbPersona, llama sync_persona_single → MERGE :Person en Neo4j.
~50ms (sync, blocking)
4
El endpoint responde a Kabuto con la persona creada
Kabuto sigue su pipeline. Total user-perceived latency: ~100ms.
Caller HAPPY
5
Si Neo4j está caído en el paso 3
El hook falla en silencio (try/except). El endpoint igual responde 200 OK. La nightly reconcile a las 04:30 detecta la persona faltante y la sincroniza. Cliente nunca ve error.
Recuperación ≤ 24h

06 Cómo lo usa el agente Claude (vía MCP)

El agente Claude que responde por WhatsApp / Telegram tiene acceso al grafo a través del MCP oficial de Neo4j Labs (mcp-neo4j-cypher), montado en modo read-only. El agente puede leer cualquier query Cypher pero NO puede escribir (los writes van solo por los hooks live del backend).

Tool 1 · get_neo4j_schema bug upstream

Pensada para que Claude descubra dinámicamente qué labels y relaciones existen. Hoy el agente la salta porque mcp-neo4j-cypher@0.6.0 tiene un bug en apoc.meta.schema. Workaround: usar queries de introspección directas via read_neo4j_cypher.

CALL db.labels()
CALL db.relationshipTypes()
Tool 2 · read_neo4j_cypher

Ejecuta cualquier query Cypher de lectura. Read-timeout 2 minutos para queries pesadas. Sin token-limit (respuestas completas).

read_neo4j_cypher(
  query: "MATCH (d:Directa)-[:HOLDS_DIRECTA]->(c)
          WHERE c.name = $name RETURN d",
  params: {name: "Citibox"}
)

Flujo típico de una pregunta

1
Cliente pregunta por WhatsApp
"contame cómo va Citibox y si hubo eventos relevantes este mes"
2
Orchestrator omzg llama a Claude con el MCP de Neo4j cargado
El system prompt indica: para preguntas sobre cartera/menciones/relaciones cross-source, usar mcp__neo4j__*.
3
Claude descubre el schema
Llama get_neo4j_schema → ve que existe :Directa, :Company, :Document, :FinancialAnalysis, etc.
4
Claude genera Cypher para el dossier
Una query que une cartera + docs recientes + análisis + mentions cruzadas, todo en una sola operación de grafo.
5
Claude redacta la respuesta natural
"Citibox (CIT-01) tiene 5 análisis financieros. La Series E levantó €150M @ €1.250M post. Founders ex-Glovo. Competidores mencionados en decks: Amazon, Glovo, SEUR..."

07 Casos de uso reales (con queries que funcionan hoy)

contame cómo va Citibox
MATCH (d:Directa)-[:HOLDS_DIRECTA]->(c:Company {name:'Citibox'})
OPTIONAL MATCH (qu:QuarterlyUpdate)-[:ABOUT]->(c)
OPTIONAL MATCH (doc:Document)-[:ABOUT]->(c)
OPTIONAL MATCH (m:Meeting)-[:ABOUT]->(c)
OPTIONAL MATCH (f:FinancialAnalysis)-[:ABOUT]->(c)
RETURN d.ticker, d.cost_eur, d.tipo, d.status,
  count(DISTINCT qu) AS quarterlies,
  count(DISTINCT doc) AS docs,
  count(DISTINCT m) AS meetings,
  count(DISTINCT f) AS analyses
Devuelve: CIT-01, €25K, VC, Activa, 0 quarterlies, 1 doc, 0 meetings, 5 análisis financieros
qué decks de mi cartera mencionan a Glovo
MATCH (d:Document {doc_type:'pitch_deck'})
      -[:HAS_MENTION]->(:Mention)-[:OF]->(c:Company)
WHERE toLower(c.name) CONTAINS 'glovo'
OPTIONAL MATCH (d)-[:ABOUT]->(deckOf:Company)
RETURN d.filename, deckOf.name, c.name
Devuelve: 3 decks (Citibox, Autocafler, Vicio) — todos con founders ex-Glovo. Insight: pipeline VC español viene de Glovo.
qué competidores tienen en común al menos 2 participadas
MATCH (cart:Company)<-[:ABOUT]-(doc:Document)
      -[:HAS_MENTION]->(:Mention)-[:OF]->(comp:Company)
MATCH (:Directa)-[:HOLDS_DIRECTA]->(cart)
WHERE comp <> cart AND comp.verified = false
WITH comp, count(DISTINCT cart) AS shared,
     collect(DISTINCT cart.name) AS participadas
WHERE shared >= 2
RETURN comp.name, shared, participadas
Devuelve: Wallapop aparece en decks de Vicio + Autocafler.
top personas con más reuniones registradas
MATCH (p:Person {verified:true})<-[:WITH]-(m:Meeting)
RETURN p.name, p.cargo, count(m) AS meetings
ORDER BY meetings DESC LIMIT 5
Devuelve: el top 5 de personas con más reuniones, con su nombre, cargo y número de meetings asociadas. La primera concentra ~17 reuniones registradas, la segunda 8 — útil para detectar quién mueve más el deal flow.
analisis financieros con preview del summary
MATCH (f:FinancialAnalysis)-[:ABOUT]->(c:Company)
RETURN c.name, f.doc_type, f.status,
  substring(coalesce(f.summary,''), 0, 100) AS preview
ORDER BY c.name LIMIT 5
Devuelve: "Citibox levanta Series E €150M @ €1.250M post...", "Autocafler Series B €25M...", "LBO Citibox 152x EBITDA LTM...", "Merger Citibox + Hive Box €120M..."
founders detectados en decks que NO están en mi CRM
MATCH (d:Document {doc_type:'pitch_deck'})
      -[:HAS_MENTION]->(mn:Mention)
      -[:OF]->(p:Person {verified:false})
OPTIONAL MATCH (d)-[:ABOUT]->(c:Company)
RETURN p.name, mn.role_hint, c.name AS empresa
Devuelve: 8 founders (Marta Ferrer CFO Citibox, David Pascual CEO Citibox, Aleix Puig CEO Vicio, etc.) — oportunidades para enriquecer el CRM.

Modelo B-completo · queries de identidad multi-empresa

¿Qué contactos están en varios CRMs del fondo?
MATCH (p:Person)-[r:IN_CRM_OF]->(u:User)
WITH p, count(DISTINCT u) AS n_users,
     collect({user: u.name, cargo: r.cargo, fuente: r.fuente}) AS detalle
WHERE n_users >= 2
RETURN p.id AS persona_canonica,
       p.postgres_ids AS pg_ids_consolidados,
       n_users AS miembros_que_lo_tienen,
       detalle
ORDER BY n_users DESC LIMIT 10
Devuelve: personas que aparecen en el CRM de varios miembros del fondo, con el detalle del cargo y fuente per-user. Cada contacto es un único nodo canónico (no se duplica), con un array postgres_ids de los rows originales agrupados. Antes esto era N nodos duplicados sin relación entre sí.
Universo institucional: Fondo + miembros + organizaciones
MATCH (f:Fund {id:'mazos'})
OPTIONAL MATCH opPath=(f)-[:OPERATES]->(d:Directa)
WITH f, collect(opPath)[0..10] AS opPaths
MATCH (u:User)
OPTIONAL MATCH memPath=(u)-[:MEMBER_OF]->(o:Organization)
OPTIONAL MATCH crmPath=(p:Person)-[:IN_CRM_OF]->(u)
WITH f, opPaths, u, memPath, collect(crmPath)[0..5] AS crmPaths
RETURN f, opPaths, u, memPath, crmPaths
Devuelve (vista Graph): Fund Mazos como raíz → Directas a un lado → 14 Users del fondo conectados a sus Organizations (Mazos, Umbratech, Greelow, Inspirit) → cada User con sus Persons del CRM. Arquitectura del fondo entera en una pantalla.
Un nombre sin apellido en un meeting: ¿el linker sabe quién es? TIER 1.6
// Cuando el LLM extrae un nombre suelto de un meeting cuyo source ABOUT apunta
// a una Company conocida, el linker filtra candidatos por WORKS_AT a esa misma Company.
// Si solo 1 candidato cumple, hace el match sin LLM (confidence high).

MATCH (mt:Meeting)-[:ABOUT]->(c:Company),
      (mt)-[:HAS_MENTION]->(m:Mention)-[:OF]->(p:Person)
WHERE m.match_tier = 'name_contextual'
RETURN m.name_extracted AS nombre, c.name AS empresa_del_source,
       p.id AS resolved_to, m.confidence
Devuelve: tier=name_contextual, confidence=high, persona resuelta al nodo canónico correcto. Sin Tier 1.6 esto hubiera quedado como un placeholder auto-* esperando revisión manual.

08 Antes vs ahora (modelo B-completo implementado)

Hasta hace poco el grafo era plano: todo el universo Mazos se modelaba como "datos del fondo" sin distinguir los 14 miembros del sistema (de 5 organizaciones distintas: Mazos, Umbratech, Greelow, Inspirit, Mazingerventures). El Modelo B-completo agrega esa capa de identidad institucional y resuelve la duplicación de personas que tenían varios miembros del fondo en sus CRMs personales.

ANTES (single-tenant implícito)

Funcionalmente correcto, arquitecturalmente incompleto.

AHORA IMPLEMENTADO 2026-05-15

Refleja la realidad multi-empresa del fondo. Detalle en docs/kg/modelo-multiempresa.md.

Estado de la implementación · 7 archivos modificados + 1 script de migración nuevo · QA exhaustivo con 17 tests pasados (idempotencia, hook live, Tier 1.6) · Schema y código aplicados en local · pendiente: aplicar contra prod via SSH tunnel.

09 Lo que queda

TareaEsfuerzoPor qué
Modelo multi-empresa B (Users + Orgs + Fund + consolidación de personas por email) HECHO 3.5h Implementado 2026-05-15 — pendiente aplicar contra prod via SSH tunnel.
Aplicar Modelo B-completo contra prod (SSH tunnel + sync_all + migración) 30min Genera los 14 :User reales + 5 :Organization + consolidación de las personas duplicadas reales del CRM.
Workaround bug get_neo4j_schema del MCP oficial 15min upstream mcp-neo4j-cypher@0.6.0 ejecuta apoc.meta.schema({sample: None}) con None literal. Hoy el agente sólo puede usar db.labels() / db.relationshipTypes().
Deploy Neo4j a prod (instalar uv + agregar a docker-compose + .env) 1h Hoy el KG vive solo en dev. Hasta que esté en prod, el agente prod no usa el grafo.
Backfill 2858 mensajes históricos omzg 30min + ~$0.30 LLM Densidad temporal — Mentions sobre conversaciones antiguas.
Adaptar el script de 3 años de Didac para que descubra nodos + relaciones y los inyecte al KG 1-2d El script ya recorre 3 años de actividad histórica (emails, docs, meetings). Hoy genera output plano — falta engancharlo al pipeline de extracción + linker para que cada entidad detectada caiga al grafo con su :Mention + arista al source correspondiente. Bootstrappea el grafo con contexto temporal profundo.
Endpoint REST /api/kg/dossier + widget Next.js 1.5d Visualización del grafo en el dashboard del cliente.
F6 Discovery proactivo (patterns + alerts WA) 2-3d El agente avisa por WA cuando se cumplen señales compuestas.
F7 Audit trail (Recommendation nodes con JUSTIFIED_BY) 1.5d Reconstruir el reasoning de cualquier recomendación del agente.

Versión visual auto-generada de la arquitectura del KG · Mazinger OS · 2026-05-15 · v2 (Modelo B-completo)
Docs relacionados: docs/kg/sync-sostenible.md, docs/kg/modelo-multiempresa.md, docs/kg/plan-cierre-gaps-2026-05-14.md, docs/kg/kg-schema.md