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

185 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: "0049"
title: "OSINT graph viewer + GPU graph rendering system"
status: completado
type: feature
domain:
- osint
scope: multi-app
priority: alta
depends: []
blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: []
---
# 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`/`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:
```cpp
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](0049a-osint-graph-setup.md) | issue/0049a-osint-graph-setup | Crear proyecto `osint_graph` + vault + sub-repo Gitea de la app | pendiente |
| [0049b](0049b-cpp-bump-gl-43.md) | issue/0049b-cpp-bump-gl-43 | Bump OpenGL 3.3 → 4.3 core en `app_base` + verificar apps existentes | pendiente |
| [0049c](0049c-graph-renderer-tier1.md) | issue/0049c-graph-renderer-tier1 | RGBA8, orphan buffers, frustum cull aristas, auto-pause force | pendiente |
| [0049d](0049d-graph-edges-vertex-pulling.md) | issue/0049d-graph-edges-vertex-pulling | TBO + vertex pulling para aristas | pendiente |
| [0049e](0049e-graph-types-extended.md) | issue/0049e-graph-types-extended | Modelo extendido: type_id, flags, EntityType/RelationType | pendiente |
| [0049f](0049f-graph-renderer-symbols.md) | issue/0049f-graph-renderer-symbols | Shapes SDF, icon atlas, flechas, edge styles | pendiente |
| [0049g](0049g-graph-source-operations.md) | issue/0049g-graph-source-operations | `graph_load_from_operations` + stream variant | pendiente |
| [0049h](0049h-graph-force-layout-gpu.md) | issue/0049h-graph-force-layout-gpu | Compute shader + spatial hash GPU | pendiente |
| [0049i](0049i-graph-layouts-static.md) | issue/0049i-graph-layouts-static | radial, hierarchical, fixed + viewport extendido | pendiente |
| [0049j](0049j-graph-labels.md) | issue/0049j-graph-labels | `graph_labels` con LabelPolicy via ImDrawList | pendiente |
| [0049k](0049k-graph-explorer-app.md) | 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`.