- 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>
10 KiB
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_types—GraphNode/GraphEdgeminimos.
Lo que limita escalar:
- Force layout en CPU domina a partir de ~5k nodos.
- Renderer aloca y resube buffers cada frame (
glBufferData). - Aristas reconstruidas vertex-by-vertex en CPU.
- Sin shapes, iconos, edge styles, flechas, filtros, labels.
- 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
- OpenGL 4.3 core (no 3.3): habilita compute shaders + SSBOs, simplifica el layout GPU drasticamente. Trade: GPUs ~2012+ obligatorias (todas las modernas — aceptable).
- 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.
- Modelo de datos extendido es breaking change controlado: la unica consumidora actual es
demos_graphenprimitives_gallery; se migra en el mismo sub-issue (0049e). - GraphSource es funcional, no OO: punteros a funcion con misma firma, swap trivial. Sin virtuals, sin templates, sin std::function en hot path.
- types.yaml externo define visual mapping (color/shape/icon per entity type). El renderer no sabe nada de OSINT — solo lee tablas.
- CPU mirror de posiciones se mantiene siempre (8 bytes × N) para hit-test, drag, labels — leido via
glGetBufferSubData1x/frame. Trivial coste, simplifica todo. - Cada app C++ es sub-repo Gitea (
apps_tbd.md+cpp_apps.md):graph_explorerse crea con.gitapuntando adataforge/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_explorerabre cualquierapps/<x>/operations.dbdel 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.yamlopcional que mergea defaults con override visual por tipo.fn indexcompleta y todas las funciones nuevas aparecen conuses_functionscorrecto.- Tests Catch2 verdes para
graph_layouts,graph_icons,graph_force_layout_gpu,graph_sources. - Visual test golden actualizado para
demos_graphcon el nuevo modelo. - Sub-repo
dataforge/graph_explorerpushed con master limpio. - Feature flag
osint_graph_v1=true.