Files
fn_registry/dev/issues/completed/0049-osint-graph-viewer.md
T
egutierrez decc468531 feat(0049k): graph_explorer wiring + close issue 0049
- cpp/CMakeLists.txt: register projects/osint_graph/apps/graph_explorer/
  via add_subdirectory pattern (igual que registry_dashboard).
- dev/feature_flags.json: osint_graph_v1 = true (enabled_at 2026-04-30).
- dev/issues/{0049,0049k} → dev/issues/completed/. README index actualizado.

La app vive en su sub-repo dataforge/graph_explorer (push hecho al cerrar).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 00:14:31 +02:00

10 KiB
Raw Blame History

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.