Files
fn_registry/dev/issues/completed/0049-osint-graph-viewer.md

10 KiB
Raw Permalink Blame History

id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
id title status type domain scope priority depends blocks related created updated tags
0049 OSINT graph viewer + GPU graph rendering system completado feature
osint
multi-app alta
2026-05-17 2026-05-17

0049 — OSINT graph viewer + GPU graph rendering system

Metadata

Campo Valor
ID 0049
Estado pendiente
Prioridad alta
Tipo feature — proyecto C++ multi-fase

Dependencias

ID Título Estado Requerido
0042 C++ layout_storage publico completado si
0043 C++ apps standardize shell completado si
0048 C++ visual tests CI gate completado si

Bloqueada por: ninguna (todas las deps cerradas). Desbloquea: apps tipo Maltego local + cualquier app del registry que necesite visualizacion de grafos a escala.


Objetivo

Construir un sistema de visualizacion de grafos GPU-accelerated, agnostico del backend de datos, y sobre el una app graph_explorer para OSINT/ontologia. El renderer debe escalar a 50k+ nodos sin caida de fps, soportar layouts (force, grid, circular, radial, jerarquico, fixed), formas/iconos/colores per-tipo, edges direccionales y con estilos, drag-and-drop, multiseleccion, labels con politica, y filtros por tipo. Datos cargables desde operations.db de cualquier app del registry como primer source, con abstraccion funcional preparada para JSON/JSONL/GraphML.

Contexto

Lo que existe hoy (cpp/functions/viz/):

  • graph_renderer — instanced quad rendering en OpenGL 3.3 con SDF circular. CPU rebuilds vertex buffers cada frame.
  • graph_force_layout — Barnes-Hut quadtree en CPU, una iteracion por frame.
  • graph_viewport — wrapper ImGui con pan/zoom/hit-testing.
  • graph_typesGraphNode/GraphEdge minimos.

Lo que limita escalar:

  1. Force layout en CPU domina a partir de ~5k nodos.
  2. Renderer aloca y resube buffers cada frame (glBufferData).
  3. Aristas reconstruidas vertex-by-vertex en CPU.
  4. Sin shapes, iconos, edge styles, flechas, filtros, labels.
  5. Bound a OpenGL 3.3 (sin compute shaders ni SSBOs).

Caso de uso final: Visor tipo Maltego local con extraccion de entidades por tipos sobre analysis/ontology_graph (OSINT banca espanola, ya en marcha). Recoleccion masiva → entities/relations llegan en streaming → visualizacion en tiempo real.

Arquitectura

projects/osint_graph/                           # NEW project
├── project.md                                  # NEW
├── apps/
│   └── graph_explorer/                         # NEW app (sub-repo dataforge/graph_explorer)
│       ├── app.md
│       ├── CMakeLists.txt
│       ├── main.cpp
│       ├── data.{h,cpp}                        # dispatcher de GraphLoadFn
│       ├── views.{h,cpp}                       # toolbar/legend/inspector/stats
│       └── types_registry.{h,cpp}              # carga types.yaml para visual override
├── analysis/                                   # vacio inicial
└── vaults/
    └── osint_data -> ~/vaults/osint_graph/     # symlink

cpp/functions/viz/                              # extensiones + funciones nuevas
├── graph_types.{h,cpp}                         # MOD — modelo extendido (type_id, flags, icons...)
├── graph_renderer.{h,cpp}                      # MOD — RGBA8, orphan, TBO, shapes, iconos, flechas
├── graph_force_layout.{h,cpp}                  # MOD — auto-pause
├── graph_force_layout_gpu.{h,cpp}              # NEW — compute shader + spatial hash
├── graph_layouts.{h,cpp}                       # NEW — radial, hierarchical, fixed (consolida)
├── graph_viewport.{h,cpp}                      # MOD — lasso, multi-select, drag-pin, callbacks
├── graph_labels.{h,cpp}                        # NEW — render con LabelPolicy
├── graph_icons.{h,cpp}                         # NEW — atlas Tabler en textura
└── graph_sources.{h,cpp}                       # NEW — graph_load_from_operations + stream

cpp/framework/app_base.cpp                      # MOD — bump GL 3.3 → 4.3 core

.claude/rules/cpp_apps.md                       # YA AÑADIDO en sesion previa

Abstraccion funcional GraphSource

Misma firma para todos los backends — swap por puntero a funcion, sin virtuals:

typedef bool (*GraphLoadFn)(const char* uri, GraphData* out, GraphLoadStats* stats);

bool graph_load_from_operations(const char*, GraphData*, GraphLoadStats*);
bool graph_load_from_json      (const char*, GraphData*, GraphLoadStats*);  // futuro
bool graph_load_from_jsonl     (const char*, GraphData*, GraphLoadStats*);  // futuro
bool graph_load_from_graphml   (const char*, GraphData*, GraphLoadStats*);  // futuro

struct GraphStreamSource;
GraphStreamSource* graph_stream_operations_open(const char* db_path, int poll_ms);
int                graph_stream_pull(GraphStreamSource*, GraphData*);
void               graph_stream_close(GraphStreamSource*);

Desglose multi-issue

Este issue se implementa en 11 sub-issues independientes. Cada sub-issue es autocontenido — debe compilar, pasar tests, no romper master. Trunk-based development obligatorio (ver .claude/rules/apps_tbd.md).

Sub-issue Rama Alcance Estado
0049a issue/0049a-osint-graph-setup Crear proyecto osint_graph + vault + sub-repo Gitea de la app pendiente
0049b issue/0049b-cpp-bump-gl-43 Bump OpenGL 3.3 → 4.3 core en app_base + verificar apps existentes pendiente
0049c issue/0049c-graph-renderer-tier1 RGBA8, orphan buffers, frustum cull aristas, auto-pause force pendiente
0049d issue/0049d-graph-edges-vertex-pulling TBO + vertex pulling para aristas pendiente
0049e issue/0049e-graph-types-extended Modelo extendido: type_id, flags, EntityType/RelationType pendiente
0049f issue/0049f-graph-renderer-symbols Shapes SDF, icon atlas, flechas, edge styles pendiente
0049g issue/0049g-graph-source-operations graph_load_from_operations + stream variant pendiente
0049h issue/0049h-graph-force-layout-gpu Compute shader + spatial hash GPU pendiente
0049i issue/0049i-graph-layouts-static radial, hierarchical, fixed + viewport extendido pendiente
0049j issue/0049j-graph-labels graph_labels con LabelPolicy via ImDrawList pendiente
0049k issue/0049k-graph-explorer-app App graph_explorer + indexado + push final pendiente

Feature flag

Nombre: osint_graph_v1 Se activa al cerrar 0049k cuando graph_explorer compila, consume operations.db y muestra grafos OSINT con todas las features (shapes, iconos, layouts, labels, filtros).

Progreso por fase

  • 0049a — proyecto osint_graph + vault + sub-repo
  • 0049b — bump GL 4.3
  • 0049c — renderer Tier 1 (perf)
  • 0049d — edges via vertex pulling (perf)
  • 0049e — modelo de datos extendido (breaking change a graph_types)
  • 0049f — shapes/iconos/edge-styles/flechas (renderer extendido)
  • 0049g — source operations.db + streaming
  • 0049h — force layout GPU compute
  • 0049i — layouts estaticos + viewport extendido
  • 0049j — labels con politica
  • 0049k — app graph_explorer + flag activado

Decisiones de diseno

  1. OpenGL 4.3 core (no 3.3): habilita compute shaders + SSBOs, simplifica el layout GPU drasticamente. Trade: GPUs ~2012+ obligatorias (todas las modernas — aceptable).
  2. Spatial hash grid GPU en vez de Barnes-Hut: Barnes-Hut quadtree es muy duro en GPU sin punteros. Spatial hash es uniforme en carga y suficiente visualmente para el caso OSINT.
  3. Modelo de datos extendido es breaking change controlado: la unica consumidora actual es demos_graph en primitives_gallery; se migra en el mismo sub-issue (0049e).
  4. GraphSource es funcional, no OO: punteros a funcion con misma firma, swap trivial. Sin virtuals, sin templates, sin std::function en hot path.
  5. types.yaml externo define visual mapping (color/shape/icon per entity type). El renderer no sabe nada de OSINT — solo lee tablas.
  6. CPU mirror de posiciones se mantiene siempre (8 bytes × N) para hit-test, drag, labels — leido via glGetBufferSubData 1x/frame. Trivial coste, simplifica todo.
  7. Cada app C++ es sub-repo Gitea (apps_tbd.md + cpp_apps.md): graph_explorer se crea con .git apuntando a dataforge/graph_explorer.

Riesgos

Riesgo Mitigacion
Bump GL 4.3 rompe apps existentes en HW antiguo Validar en 0049b sobre las 4 apps actuales en Linux + Windows cross-compile antes de mergear
Compute shader complexity (0049h) Caer back a CPU layout es trivial — la API es identica
Streaming desde operations.db sin estabilidad de positions Pin nodos nuevos cerca del padre por N frames, luego release
Demo demos_graph queda roto durante 0049e Migrar demos_graph.cpp en el mismo sub-issue con tests visuales
Atlas de iconos Tabler ocupa espacio 512×512 RGBA = 1 MB en VRAM, despreciable

Criterio de done global

  • graph_explorer abre cualquier apps/<x>/operations.db del registry y lo visualiza con tipos descubiertos automaticamente.
  • 50k nodos + 200k aristas a 60fps en GPU integrada con layout corriendo.
  • Drag, multi-select (Ctrl+click + Shift+lasso), filter-by-type, fit-view operativos.
  • Labels visibles para selected/hovered + top-N por tamaño con LabelPolicy configurable.
  • Iconos Tabler renderizados dentro de cada nodo segun EntityType.icon_id.
  • Edges direccionales con flechas + estilos solid/dashed/dotted segun RelationType.style.
  • types.yaml opcional que mergea defaults con override visual por tipo.
  • fn index completa y todas las funciones nuevas aparecen con uses_functions correcto.
  • Tests Catch2 verdes para graph_layouts, graph_icons, graph_force_layout_gpu, graph_sources.
  • Visual test golden actualizado para demos_graph con el nuevo modelo.
  • Sub-repo dataforge/graph_explorer pushed con master limpio.
  • Feature flag osint_graph_v1 = true.