fix(fn-run): propagar stdout/stderr de bash functions library-style #1
@@ -0,0 +1,124 @@
|
||||
# 0041 — C++ app shell estandarizado: BEST_PRACTICES + AppConfig extendido
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0041 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | alta |
|
||||
| **Tipo** | feature — C++ framework (`cpp/framework/`) + docs |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Ninguna. Habilita **0043** (estandarizar apps existentes) y todo desarrollo futuro de apps C++.
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
1. Documentar el patron canonico de apps C++ del registry en `cpp/PATTERNS.md` con checklist obligatorio.
|
||||
2. Extender `fn::AppConfig` para que `fn::run_app()` registre About + paneles + theming en una sola llamada, eliminando boilerplate por app.
|
||||
|
||||
## Contexto
|
||||
|
||||
La auditoria muestra que `chart_demo`, `primitives_gallery`, `shaders_lab` y `registry_dashboard` arrancan distinto: solo `shaders_lab` aprovecha `app_menubar` con paneles, solo `registry_dashboard` registra About + Settings, `primitives_gallery` llama `apply_dark_theme()` + `gl_loader_init()` a mano que el resto delega a `run_app()`. Sin estandar, cada app proxima reinventa esto.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
cpp/
|
||||
├── PATTERNS.md # NEW — checklist y patrones
|
||||
├── framework/
|
||||
│ ├── app_base.h # MOD — extender AppConfig
|
||||
│ └── app_base.cpp # MOD — aplicar nuevos campos
|
||||
└── functions/core/
|
||||
└── (sin cambios — app_menubar/app_about/app_settings ya existen)
|
||||
```
|
||||
|
||||
### AppConfig extendido (propuesta)
|
||||
|
||||
```cpp
|
||||
struct AppAboutInfo {
|
||||
const char* name = nullptr;
|
||||
const char* version = nullptr;
|
||||
const char* description = nullptr;
|
||||
};
|
||||
|
||||
struct AppConfig {
|
||||
const char* title = "fn app";
|
||||
int width = 1280;
|
||||
int height = 800;
|
||||
bool vsync = true;
|
||||
bool viewports = false;
|
||||
ThemeMode theme = ThemeMode::FnDark;
|
||||
float bg_r=0,bg_g=0,bg_b=0;
|
||||
|
||||
// NEW — registra About si name != nullptr.
|
||||
AppAboutInfo about{};
|
||||
|
||||
// NEW — paneles toggleables del menubar (si != nullptr).
|
||||
const fn_ui::PanelToggle* panels = nullptr;
|
||||
size_t panel_count = 0;
|
||||
|
||||
// NEW — callbacks de layouts persistentes (si != nullptr).
|
||||
fn_ui::LayoutCallbacks* layouts_cb = nullptr;
|
||||
|
||||
// NEW — si true, llama gl_loader_init() antes del primer frame.
|
||||
bool init_gl_loader = false;
|
||||
};
|
||||
```
|
||||
|
||||
`run_app()` aplica:
|
||||
- Si `about.name != nullptr` → `fn_ui::about_window_set_info(...)`.
|
||||
- Si `init_gl_loader` → `fn::gfx::gl_loader_init()` tras crear el contexto GL.
|
||||
- Cada frame, si `panels != nullptr` o `layouts_cb != nullptr`, llama `app_menubar(panels, panel_count, layouts_cb)` automaticamente — la app NO la llama.
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — Doc
|
||||
|
||||
1.1 Crear `cpp/PATTERNS.md` con checklist:
|
||||
- Usa `fn::run_app()` con `AppConfig` (jamas `glfwInit` directo).
|
||||
- Registra About via `AppConfig::about` o `about_window_set_info()`.
|
||||
- Registra Settings extras via `settings_window_add_section()`.
|
||||
- Si tienes paneles, define `static constexpr fn_ui::PanelToggle panels[]` y pasalo en `AppConfig::panels`.
|
||||
- Si necesitas layouts, implementa `LayoutCallbacks` y pasalas en `AppConfig::layouts_cb`.
|
||||
- Usa `fn_tokens::colors|spacing|radius` siempre. Nunca colores hex literales.
|
||||
- Evita `ImGui::BeginTable / Selectable / BeginPopupModal / BeginChild` con styling manual — usa `dashboard_grid`, `tree_view`/`select`, `modal_dialog`, `dashboard_panel`.
|
||||
|
||||
### Fase 2 — Framework
|
||||
|
||||
2.1 Anadir campos `about`, `panels`, `panel_count`, `layouts_cb`, `init_gl_loader` a `AppConfig` en `app_base.h`.
|
||||
2.2 En `run_app()` (`app_base.cpp`):
|
||||
- Tras `gl_loader_init` opcional.
|
||||
- Tras `about_window_set_info` si procede.
|
||||
- Antes del `render_fn()` por frame, llama `app_menubar(panels, panel_count, layouts_cb)` si alguno != nullptr.
|
||||
2.3 Backward-compat: campos nuevos opcionales con defaults — apps existentes compilan sin tocarlas.
|
||||
|
||||
### Fase 3 — Validacion
|
||||
|
||||
3.1 Compilar todas las apps existentes sin cambios, verificar que no rompe.
|
||||
3.2 Build Linux + cross-compile Windows.
|
||||
|
||||
### Fase 4 — Indexar
|
||||
|
||||
4.1 `./fn index` para refrescar metadata (no cambia funciones — solo doc).
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- `AppConfig` con campos opcionales (no nuevos overloads de `run_app`) — minimiza la API surface.
|
||||
- La menubar se llama desde `run_app` solo si la app declara paneles/layouts; en otro caso la app puede llamar `app_menubar(nullptr,0,nullptr)` ella misma (compat).
|
||||
|
||||
## Riesgos
|
||||
|
||||
- Apps que ya llaman `app_menubar` manualmente con `panels` distintos al `AppConfig`: documentar — `run_app` la llama una vez al inicio del frame, la app puede dejar de hacerlo.
|
||||
|
||||
## Validacion
|
||||
|
||||
- `cpp/PATTERNS.md` legible en GitHub.
|
||||
- `chart_demo` (la mas simple) puede ahora declararse asi:
|
||||
```cpp
|
||||
fn::run_app({.title="chart demo", .about={.name="chart demo", .version="0.1", .description="..."}}, render);
|
||||
```
|
||||
- Tests de compilacion OK para shaders_lab/chart_demo/primitives_gallery/registry_dashboard sin modificar.
|
||||
@@ -0,0 +1,110 @@
|
||||
# 0042 — C++ layout_storage: extraer y publicar como API reutilizable
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0042 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | alta |
|
||||
| **Tipo** | feature — C++ core (`cpp/functions/core`) |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Ninguna. Habilita **0043** (estandarizar apps).
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Extraer la persistencia de layouts ImGui (actualmente privada en `shaders_lab/main.cpp` lineas 415-447) a una funcion publica del registry: `layout_storage_cpp_core`. Cualquier app puede pasarla a `app_menubar` via `LayoutCallbacks` con un solo `setup`.
|
||||
|
||||
## Contexto
|
||||
|
||||
`shaders_lab` guarda layouts (snapshots de `imgui.ini`) en SQLite via `shaderlab_db_cpp_core`. La logica que conecta SQLite con `LayoutCallbacks` (`save`, `load`, `list`, `remove`) esta inline en su `main.cpp` y no es reusable. Otras apps (registry_dashboard, primitives_gallery, chart_demo) no tienen layouts persistentes.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
cpp/functions/core/
|
||||
├── layout_storage.h # NEW — API publica
|
||||
├── layout_storage.cpp # NEW — impl con SQLite
|
||||
├── layout_storage.md # NEW
|
||||
└── (opcional) layouts_menu.h ya existe — sin cambios
|
||||
|
||||
cpp/apps/shaders_lab/
|
||||
└── main.cpp # MOD — usa layout_storage en lugar de inline
|
||||
```
|
||||
|
||||
### API propuesta
|
||||
|
||||
```cpp
|
||||
namespace fn_ui {
|
||||
|
||||
struct LayoutStorage; // opaque
|
||||
|
||||
// Crea un storage que persiste layouts ImGui en una tabla SQLite del path dado.
|
||||
// Si la BD no existe, la crea. Tabla: `imgui_layouts(name TEXT PRIMARY KEY, ini TEXT, updated_at)`.
|
||||
LayoutStorage* layout_storage_open(const char* db_path);
|
||||
void layout_storage_close(LayoutStorage* s);
|
||||
|
||||
// Helper que rellena un LayoutCallbacks usando este storage.
|
||||
// El caller mantiene vivo el storage durante la vida de los callbacks.
|
||||
void layout_storage_make_callbacks(LayoutStorage* s, LayoutCallbacks& out);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
`LayoutCallbacks` ya esta definido en `panel_menu.h`/`layouts_menu.h`. Esta funcion solo wirea SQLite.
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — Codigo
|
||||
|
||||
1.1 Crear `cpp/functions/core/layout_storage.{h,cpp,md}`.
|
||||
1.2 Implementar usando sqlite3 vendoreada (`cpp/vendor/sqlite3`). Tabla unica `imgui_layouts`.
|
||||
1.3 Save: serializa `ImGui::SaveIniSettingsToMemory()` y hace UPSERT por nombre.
|
||||
1.4 Load: lee `ini` y llama `ImGui::LoadIniSettingsFromMemory(ini, len)`.
|
||||
1.5 List: `SELECT name FROM imgui_layouts ORDER BY updated_at DESC`.
|
||||
1.6 Remove: `DELETE FROM imgui_layouts WHERE name=?`.
|
||||
1.7 Frontmatter `.md` con `purity: impure`, `error_type: error_go_core`, `uses_types: []`.
|
||||
|
||||
### Fase 2 — Migrar shaders_lab
|
||||
|
||||
2.1 Reemplazar el bloque inline (l. 415-447) por:
|
||||
```cpp
|
||||
auto* g_layouts = fn_ui::layout_storage_open("shaders_lab.db");
|
||||
fn_ui::LayoutCallbacks layouts_cb;
|
||||
fn_ui::layout_storage_make_callbacks(g_layouts, layouts_cb);
|
||||
// ...pasar layouts_cb a app_menubar
|
||||
```
|
||||
2.2 Mantener `shaderlab_db_cpp_core` como esta (no es lo mismo: guarda shaders, no layouts) — pero quitar de el la parte de layouts si la tiene.
|
||||
2.3 Verificar que los layouts existentes siguen cargando (compatibilidad de schema o migracion automatica).
|
||||
|
||||
### Fase 3 — Tests
|
||||
|
||||
3.1 Test unitario: open → save("test", ini) → list() == ["test"] → load("test") devuelve el ini → remove("test") → list() == [].
|
||||
3.2 Test de regresion en shaders_lab (build + abrir/cerrar layout manual).
|
||||
|
||||
### Fase 4 — Indexar
|
||||
|
||||
4.1 `./fn index` y verificar `fn show layout_storage_cpp_core`.
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- BD SQLite por app (no compartida) — cada app gestiona sus layouts.
|
||||
- Schema simple (`name PRIMARY KEY, ini, updated_at`) — sin namespaces ni jerarquia.
|
||||
- API opaca (`LayoutStorage*`) para no exponer sqlite3 en headers publicos.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- shaders_lab tiene layouts existentes en su `shaders_lab.db`. Si la tabla actual difiere del schema nuevo: migracion automatica al primer open o conservar ambas tablas.
|
||||
- Threading: ImGui::SaveIniSettingsToMemory solo es seguro desde el thread principal — documentar.
|
||||
|
||||
## Validacion
|
||||
|
||||
```bash
|
||||
cd cpp/build && cmake --build . --target shaders_lab
|
||||
# Abrir shaders_lab, guardar/cargar layouts, restart, verificar que persiste.
|
||||
./fn show layout_storage_cpp_core
|
||||
```
|
||||
@@ -0,0 +1,92 @@
|
||||
# 0043 — Estandarizar shell de las 4 apps C++ (About + Settings + paneles + tokens)
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0043 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | alta |
|
||||
| **Tipo** | refactor — `cpp/apps/*` y `projects/fn_monitoring/apps/registry_dashboard` |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Bloquea-por: **0041** (AppConfig extendido), **0042** (layout_storage publico).
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Que las 4 apps C++ con GUI (`shaders_lab`, `chart_demo`, `primitives_gallery`, `registry_dashboard`) sigan el mismo patron de inicializacion documentado en `cpp/PATTERNS.md` (issue 0041): About + Settings + paneles + tokens, sin reinventar boilerplate.
|
||||
|
||||
## Contexto
|
||||
|
||||
Auditoria muestra que cada app arranca distinto: solo `shaders_lab` aprovecha menubar con paneles, solo `registry_dashboard` registra About + Settings, `primitives_gallery` llama `apply_dark_theme()` + `gl_loader_init()` a mano. Tras 0041 y 0042, se puede unificar.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
cpp/apps/
|
||||
├── shaders_lab/main.cpp # MOD — usa layout_storage publico, About, init via AppConfig
|
||||
├── chart_demo/main.cpp # MOD — registra About, simplifica
|
||||
├── primitives_gallery/main.cpp # MOD — gl_loader_init via AppConfig, About
|
||||
└── text_editor_smoke/ # SIN CAMBIOS (test CLI)
|
||||
|
||||
projects/fn_monitoring/apps/registry_dashboard/
|
||||
└── main.cpp # MOD — usa AppConfig.about en lugar de about_window_set_info inline
|
||||
```
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — chart_demo (mas simple, validacion temprana)
|
||||
|
||||
1.1 Cambiar a:
|
||||
```cpp
|
||||
return fn::run_app({
|
||||
.title="chart_demo", .width=1280, .height=800,
|
||||
.about={.name="chart_demo", .version="0.1.0",
|
||||
.description="Demo de primitivos viz: line, scatter, bar, heatmap"}
|
||||
}, render);
|
||||
```
|
||||
1.2 Quitar la llamada manual a `app_menubar(nullptr,0,nullptr)` del render — `run_app` la invoca por nosotros si hay panels/layouts; en este caso sin panels, dejar render limpio (o llamar `app_menubar(nullptr,0,nullptr)` solo si hace falta menubar para Settings).
|
||||
1.3 Build OK.
|
||||
|
||||
### Fase 2 — primitives_gallery
|
||||
|
||||
2.1 Quitar `apply_dark_theme()` y `gl_loader_init()` del init manual (l. 129-134). Pasar `init_gl_loader=true` y `theme=ThemeMode::FnDark` en `AppConfig`.
|
||||
2.2 Anadir About (`name="Primitives Gallery"`, version, description).
|
||||
2.3 Mantener `app_menubar(nullptr,0,nullptr)` solo si la menubar la quiere la app — opcionalmente delegar a `run_app` extendido.
|
||||
2.4 Build OK.
|
||||
|
||||
### Fase 3 — registry_dashboard
|
||||
|
||||
3.1 Reemplazar la llamada manual `about_window_set_info(...)` (l. 121-127) por `AppConfig::about={...}`. La seccion `Status` se queda como `settings_window_add_section` (no cambia).
|
||||
3.2 Build OK.
|
||||
|
||||
### Fase 4 — shaders_lab
|
||||
|
||||
4.1 Reemplazar el bloque de layouts inline por `fn_ui::layout_storage_open("shaders_lab.db")` + `layout_storage_make_callbacks` (consume issue 0042).
|
||||
4.2 Anadir About (`name="shaders_lab"`, version, description).
|
||||
4.3 Pasar `panels` y `layouts_cb` via `AppConfig` (issue 0041) — quitar la llamada manual a `app_menubar`.
|
||||
4.4 Build OK.
|
||||
|
||||
### Fase 5 — Verificacion cross
|
||||
|
||||
5.1 Build Linux y Windows de las 4 apps.
|
||||
5.2 Run rapido en Linux para confirmar que About y Settings/Status aparecen en el menubar de cada una.
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- Tocar registry_dashboard para que sea consistente con el patron, aunque hoy ya tenia About/Settings via APIs sueltas.
|
||||
- text_editor_smoke se queda igual (es un test CLI).
|
||||
|
||||
## Riesgos
|
||||
|
||||
- Si `run_app` invoca `app_menubar` y la app tambien lo llama, salen dos menubars. Verificar que cada main.cpp solo llama `app_menubar` si NO esta declarado en AppConfig.
|
||||
- shaders_lab: la migracion a `layout_storage` debe preservar layouts existentes — ver riesgo de 0042.
|
||||
|
||||
## Validacion
|
||||
|
||||
- Las 4 apps abren y muestran menu Settings con Settings… + About… (mas Status… donde aplique).
|
||||
- shaders_lab guarda/carga layouts despues de la migracion.
|
||||
- `cmake --build` pasa para todas. Cross-compile Windows OK.
|
||||
@@ -0,0 +1,84 @@
|
||||
# 0044 — Auditar 52 funciones C++ huerfanas y poblar uses_functions
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0044 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | media |
|
||||
| **Tipo** | chore — registry hygiene |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Ninguna.
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Resolver las 52 funciones C++ que aparecen sin `uses_functions` en `registry.db`: o son legitimamente independientes, o se usan pero no se registra la dependencia (caso `fps_overlay` que se invoca desde `app_base.cpp` pero no aparece). Resultado: `uses_functions` reflejando la verdad.
|
||||
|
||||
## Contexto
|
||||
|
||||
Ejemplos detectados:
|
||||
- `fps_overlay` — usado por `app_base.cpp`, no registrado.
|
||||
- `tokens` — usado por 16+ componentes, ya registrado bien.
|
||||
- `tween_curves`, `orbit_camera`, `time_series_buffer`, `graph_force_layout`, `plot_theme` — sin consumidores visibles. Verificar si estan en gallery/chart_demo o son scaffolding.
|
||||
- `app_settings`, `app_about`, `app_menubar`, `icon_font` — usados por `app_base.cpp`, no registrados.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
Este issue NO modifica codigo C++. Solo modifica:
|
||||
|
||||
- Frontmatter `.md` de funciones huerfanas para anadir `uses_functions: [...]` reflejando llamadas reales.
|
||||
- Eventualmente borrar funciones que se confirmen sin uso real ni plan de uso (con el OK del usuario via comment en el issue).
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — Lista exacta
|
||||
|
||||
1.1 Generar la lista actual:
|
||||
```bash
|
||||
sqlite3 registry.db "SELECT id FROM functions WHERE lang='cpp' AND uses_functions = '[]' ORDER BY id;"
|
||||
```
|
||||
1.2 Para cada id, hacer `grep -rn "<name>" cpp/ projects/*/apps/*/` y ver donde se invoca.
|
||||
|
||||
### Fase 2 — Categorizar
|
||||
|
||||
Para cada huerfana, asignar uno de estos estados (anotar en una tabla en este issue):
|
||||
- **USED** — se invoca desde otra funcion/app. Anadir el caller a `uses_functions` del consumidor (no del huerfano).
|
||||
- **DEMO_ONLY** — solo en `primitives_gallery` o demos. OK como esta. Documentar en `.md` como `# scaffolding/demo only`.
|
||||
- **PLANNED** — sin uso pero hay issue/plan futuro. Anotar en `.md` con referencia.
|
||||
- **DEAD** — sin uso real ni plan. Candidato a borrar (preguntar al usuario antes).
|
||||
|
||||
### Fase 3 — Actualizar frontmatter
|
||||
|
||||
3.1 Para cada **USED**: editar el `.md` del CONSUMIDOR para anadir el huerfano a su `uses_functions`. Ejemplo: `app_base.cpp` consume `fps_overlay_cpp_core`, `app_settings_cpp_core`, `app_about_cpp_core`, `app_menubar_cpp_core`, `icon_font_cpp_core`, `tokens_cpp_core`. Pero `app_base` NO esta en functions/ del registry — es un .cpp del framework. **Corregir**: si `app_base.cpp` no esta indexado, registrar como funcion en `cpp/framework/` o documentar la convencion en notes.
|
||||
3.2 Para **DEMO_ONLY**: anadir nota en frontmatter `notes: "demo en primitives_gallery, scaffolding"`.
|
||||
3.3 Para **PLANNED**: anadir `notes: "planned use in issue NNNN"`.
|
||||
3.4 Para **DEAD**: listar en este issue y abrir un sub-issue de delete (no borrar de oficio).
|
||||
|
||||
### Fase 4 — Reindex
|
||||
|
||||
4.1 `./fn index` para regenerar `registry.db`.
|
||||
4.2 Verificar:
|
||||
```bash
|
||||
sqlite3 registry.db "SELECT COUNT(*) FROM functions WHERE lang='cpp' AND uses_functions = '[]';"
|
||||
```
|
||||
La cifra debe bajar significativamente (objetivo: <20 huerfanas reales).
|
||||
|
||||
### Fase 5 — Documentar la convencion
|
||||
|
||||
5.1 Anadir a `.claude/rules/uses_functions.md` (NEW) la regla: cada vez que un .cpp llama a otra funcion del registry, el `.md` del CONSUMIDOR debe listar la dependencia en `uses_functions`. El indexer no lo deduce automaticamente (el codigo C++ no es trivial de parsear).
|
||||
|
||||
## Decisiones
|
||||
|
||||
- No borrar funciones sin OK explicito.
|
||||
- `app_base.cpp` no esta hoy indexado como funcion del registry (es framework). Si decidimos indexarlo, eso es 0048 — ahora solo registramos en uses_functions de los CONSUMIDORES que si esten indexados (gallery, dashboard, etc.).
|
||||
|
||||
## Validacion
|
||||
|
||||
- `uses_functions` poblados para los casos reales (verificable por SQL).
|
||||
- `cpp/PATTERNS.md` (de 0041) referencia esta convencion.
|
||||
- Nada compilado se rompe (este issue NO toca .cpp/.h).
|
||||
@@ -0,0 +1,98 @@
|
||||
# 0045 — Extraer logica pura de componentes C++ impuros (sql_workbench, process_runner, file_watcher)
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0045 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | media |
|
||||
| **Tipo** | refactor — `cpp/functions/core` |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Ninguna.
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Extraer la parte pura (parsing, state machines, diff) de componentes hoy mezclados con I/O y UI. Resultado: cada uno se descompone en `<x>_pure_cpp_core` (testeable, sin ImGui ni I/O) + `<x>_ui_cpp_core` (thin wrapper impuro). Tambien aplica al compiler de `shaders_lab` que vive en su `main.cpp`.
|
||||
|
||||
## Contexto
|
||||
|
||||
- `sql_workbench_cpp_core` mezcla parsing SQL, ejecucion SQLite y render ImGui en una sola funcion.
|
||||
- `process_runner_cpp_core` mezcla state machine de proceso (idle/running/success/error) con UI helpers.
|
||||
- `file_watcher_cpp_core` mezcla polling de filesystem con notificaciones UI.
|
||||
- `shaders_lab/main.cpp` tiene `compile_code()`, `compile_dag()`, `mark_code_dirty()` inline.
|
||||
|
||||
Sin separacion no hay tests unitarios, no es reutilizable y crece la deuda con cada feature.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
cpp/functions/core/
|
||||
├── sql_parse.{h,cpp,md} # NEW — pure
|
||||
├── sql_workbench.{h,cpp,md} # MOD — thin wrapper, llama sql_parse
|
||||
├── process_state_machine.{h,cpp,md} # NEW — pure (transiciones)
|
||||
├── process_runner.{h,cpp,md} # MOD — usa process_state_machine
|
||||
├── file_poll_diff.{h,cpp,md} # NEW — pure (calcula diff de snapshots)
|
||||
└── file_watcher.{h,cpp,md} # MOD — usa file_poll_diff
|
||||
|
||||
cpp/apps/shaders_lab/
|
||||
├── compiler.h # NEW
|
||||
├── compiler.cpp # NEW (extrae compile_code/compile_dag)
|
||||
└── main.cpp # MOD (461 → ~250 lineas)
|
||||
```
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — sql_workbench
|
||||
|
||||
1.1 `sql_parse_cpp_core` (pure): tokeniza SQL minimal (separa statements por `;`, detecta keyword inicial: SELECT/INSERT/UPDATE/DELETE/CREATE/etc., devuelve struct `SqlStatement{kind, text, line}`).
|
||||
1.2 `sql_workbench` pasa a llamar `sql_parse` para detectar tipo de statement antes de ejecutar; el parser puro es testeable sin SQLite.
|
||||
1.3 Test unitario: dado SQL multi-statement, devuelve N statements con kind correcto.
|
||||
|
||||
### Fase 2 — process_runner
|
||||
|
||||
2.1 `process_state_machine_cpp_core` (pure): funcion `process_transition(current_state, event) -> new_state` con eventos `{Trigger, Spawned, Finished, Failed, Timeout}` y estados `{Idle, Running, Success, Error}`.
|
||||
2.2 `process_runner` pasa a usar la maquina pura para gestionar transiciones; la parte impura solo dispara `popen`/`spawn`/`wait` y traduce a eventos.
|
||||
2.3 Test unitario: secuencia de eventos → estado final esperado.
|
||||
|
||||
### Fase 3 — file_watcher
|
||||
|
||||
3.1 `file_poll_diff_cpp_core` (pure): dado dos snapshots `vector<FileEntry{path, size, mtime}>`, devuelve `FileDiff{added, modified, removed}`.
|
||||
3.2 `file_watcher` pasa a hacer el polling impuro y delegar el diff al puro.
|
||||
3.3 Test unitario: dado A=[a,b,c], B=[a,b',d] → modified=[b], added=[d], removed=[c].
|
||||
|
||||
### Fase 4 — shaders_lab compiler
|
||||
|
||||
4.1 Crear `cpp/apps/shaders_lab/compiler.{h,cpp}` con `compile_code(code, &out_log) -> bool`, `compile_dag(...)`, `mark_code_dirty(...)`. Estas funciones llaman al backend GLSL existente — no son del registry porque dependen de estado interno de shaders_lab.
|
||||
4.2 Mover el codigo correspondiente desde `main.cpp`.
|
||||
4.3 `main.cpp` queda <250 lineas.
|
||||
|
||||
### Fase 5 — Indexar y validar
|
||||
|
||||
5.1 `./fn index` para registrar las 3 nuevas funciones puras.
|
||||
5.2 Verificar `purity: pure`, `returns_optional: false`, `error_type: ""` en cada una.
|
||||
5.3 Build Linux + Windows. Tests pasan.
|
||||
|
||||
## Decisiones
|
||||
|
||||
- `sql_parse` es deliberadamente minimal — no es un parser SQL completo, solo distingue tipos de statement. Si en el futuro hace falta mas, se anade.
|
||||
- `compile_code/compile_dag` quedan como utilities de la app, NO en el registry (dependen de tipos internos de shaders_lab).
|
||||
|
||||
## Riesgos
|
||||
|
||||
- Tests unitarios C++: no hay framework configurado todavia (issue 0047 lo monta). Mientras tanto, anadir tests dentro del archivo via `#ifdef TESTING` + un main pequeno, o esperar a 0047.
|
||||
- Decision: usar `#ifdef TESTING` por ahora; cuando 0047 monte Catch2, migrar.
|
||||
|
||||
## Validacion
|
||||
|
||||
```bash
|
||||
./fn run sql_parse_cpp_core # ejecuta el test si lo hay
|
||||
./fn show sql_parse_cpp_core
|
||||
./fn show process_state_machine_cpp_core
|
||||
./fn show file_poll_diff_cpp_core
|
||||
cmake --build cpp/build --target shaders_lab
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
# 0046 — Reemplazar raw ImGui en apps por primitivos del registry
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0046 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | media |
|
||||
| **Tipo** | refactor — `cpp/apps/*` y `projects/fn_monitoring/apps/registry_dashboard` |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Bloquea-por: **0043** (apps con shell estandarizado, evita conflictos al refactor).
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Eliminar el uso innecesario de raw ImGui en las 4 apps GUI: tablas custom, `Selectable` con styling manual, modales propios y `BeginChild` con borde+padding repetido. Sustituir por primitivos del registry (`dashboard_grid`, `dashboard_panel`, `tree_view`/`select`, `modal_dialog`, `tokens`).
|
||||
|
||||
## Contexto
|
||||
|
||||
Auditoria conto:
|
||||
- `registry_dashboard/views.cpp`: 33 raw calls — tablas con `BeginTable` + `PushStyleColor` repetido (l. 87, 143, 321), `BeginChild` con borde+padding (l. 122).
|
||||
- `primitives_gallery/main.cpp`: sidebar con `Selectable` + `PushStyleColor` (l. 91-124).
|
||||
- `shaders_lab/main.cpp`: modal save-as custom (l. 272-300) que reimplementa lo que hace `modal_dialog`.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
projects/fn_monitoring/apps/registry_dashboard/views.cpp # MOD — usar dashboard_panel/grid en lugar de BeginTable+styling
|
||||
cpp/apps/primitives_gallery/main.cpp # MOD — sidebar via tree_view o select
|
||||
cpp/apps/shaders_lab/main.cpp # MOD — save-as via modal_dialog + text_input
|
||||
```
|
||||
|
||||
Posibles primitivos faltantes detectados (crear si no existen):
|
||||
- **No crear** `tab_container` por ahora — `chart_demo` lo usa OK con tabs nativos. Solo extraer si se repite.
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — registry_dashboard/views.cpp
|
||||
|
||||
1.1 Sustituir `chart_panel_begin/end` (l. 105-127) por llamadas a `dashboard_panel` si encaja.
|
||||
1.2 Cambiar `BeginTable("##chart_grid", 4, ...)` por `dashboard_grid` (4 cols stretchsame).
|
||||
1.3 Mismo cambio en `BeginTable("##kpi_grid", 4, ...)` y `BeginTable("##proj_layout", 2, ...)`.
|
||||
1.4 `BeginChild` en `draw_projects_list` (proj_tree, proj_detail) → usar `dashboard_panel` con `Borders=true`.
|
||||
1.5 Al final del refactor: contar raw `ImGui::Begin*` en views.cpp. Meta: <10 (de 33).
|
||||
|
||||
### Fase 2 — primitives_gallery sidebar
|
||||
|
||||
2.1 Sustituir el bloque `for (...) { Selectable + PushStyleColor }` (l. 96-122) por `fn_ui::select(...)` con la lista de demos, o por `tree_view` agrupado por categoria si la API encaja.
|
||||
2.2 Mantener visualmente equivalente (separadores por categoria, item activo coloreado).
|
||||
|
||||
### Fase 3 — shaders_lab save-as modal
|
||||
|
||||
3.1 Reemplazar el bloque `BeginPopupModal` (l. 272-300) por `fn_ui::modal_dialog_begin("Save layout as...", &g_show_save_as, ImVec2(360, 0)) + text_input(...) + buttons + modal_dialog_end()`.
|
||||
|
||||
### Fase 4 — Build cross
|
||||
|
||||
4.1 Build Linux y Windows de las 3 apps modificadas.
|
||||
4.2 Run rapido en Linux para verificar que el comportamiento es identico (solo cambia la implementacion).
|
||||
|
||||
### Fase 5 — Reporte
|
||||
|
||||
5.1 Anadir al final del issue una tabla "antes/despues" con:
|
||||
- LoC de cada main.cpp / views.cpp.
|
||||
- Numero de raw `ImGui::*` calls antes/despues.
|
||||
|
||||
## Decisiones
|
||||
|
||||
- Mantener `ImGui::BeginTabBar/EndTabBar` para tabs simples (chart_demo, dashboard) — son delgaditos y no aportan valor envolverlos.
|
||||
- No crear primitivos nuevos en este issue. Si en el camino aparece un patron repetido, abrir issue separado.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- `select` puede no soportar grupos por categoria con encabezado — verificar API actual. Si no lo soporta, usar `tree_view`.
|
||||
- Conflicto potencial con 0043 si ambos tocan los mismos `main.cpp`. Por eso 0046 depende de 0043.
|
||||
|
||||
## Validacion
|
||||
|
||||
- Las 3 apps se ven igual visualmente (mismo dark theme, mismas zonas).
|
||||
- Build OK.
|
||||
- Reduccion clara de raw calls (verificable con `grep -c "ImGui::Begin" archivo`).
|
||||
@@ -0,0 +1,114 @@
|
||||
# 0047 — C++ tests foundation: Catch2 + tests para top-20 primitivos
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0047 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | alta |
|
||||
| **Tipo** | feature — testing infra |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Ninguna.
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
Montar Catch2 (single-header, vendoreado) en `cpp/`, integrar con CMake y `ctest`, y escribir tests unitarios para el top-20 de primitivos puros del registry. Pasar de 4% a >25% de cobertura en C++.
|
||||
|
||||
## Contexto
|
||||
|
||||
Hoy hay 3 funciones C++ con `tested: true` (3.7% de 81). El indexer ya soporta extraer tests automaticamente al campo `tests` del `.md` cuando hay `test_file_path`. Falta el framework, la integracion y la cobertura inicial.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
cpp/
|
||||
├── vendor/catch2/
|
||||
│ └── catch_amalgamated.{hpp,cpp} # NEW — Catch2 v3 amalgamated, MIT
|
||||
├── tests/
|
||||
│ ├── CMakeLists.txt # NEW — un test per-file
|
||||
│ ├── test_tokens.cpp # NEW
|
||||
│ ├── test_button.cpp # NEW (state-only — sin GUI render)
|
||||
│ ├── test_select.cpp # NEW
|
||||
│ ├── test_text_input.cpp # NEW
|
||||
│ ├── test_badge.cpp # NEW
|
||||
│ ├── test_kpi_card.cpp # NEW (calculo de delta/format)
|
||||
│ ├── test_pie_chart.cpp # NEW (slice_at logic)
|
||||
│ ├── test_bar_chart.cpp # NEW (label rotation logic)
|
||||
│ ├── test_tree_view.cpp # NEW
|
||||
│ ├── test_modal_dialog.cpp # NEW
|
||||
│ ├── test_toolbar.cpp # NEW
|
||||
│ ├── test_toast.cpp # NEW
|
||||
│ ├── test_empty_state.cpp # NEW
|
||||
│ ├── test_page_header.cpp # NEW
|
||||
│ ├── test_dashboard_panel.cpp # NEW
|
||||
│ ├── test_dashboard_grid.cpp # NEW
|
||||
│ ├── test_sparkline.cpp # NEW
|
||||
│ ├── test_table_view.cpp # NEW
|
||||
│ ├── test_icon_button.cpp # NEW
|
||||
│ └── test_tween_curves.cpp # NEW (puro, ideal candidato)
|
||||
└── CMakeLists.txt # MOD — anadir tests subdir si BUILD_TESTING
|
||||
```
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — Vendoreado de Catch2
|
||||
|
||||
1.1 Bajar `catch_amalgamated.hpp` + `catch_amalgamated.cpp` (Catch2 v3 single-header) a `cpp/vendor/catch2/`. Anadir LICENSE y README pequeno.
|
||||
1.2 No usar FetchContent — stay offline. Catch2 v3 es BSL-1.0.
|
||||
|
||||
### Fase 2 — Integracion CMake
|
||||
|
||||
2.1 En `cpp/CMakeLists.txt`, anadir option `BUILD_TESTING` (default ON). Si activo, `add_subdirectory(tests)`.
|
||||
2.2 `cpp/tests/CMakeLists.txt`: una funcion CMake `add_fn_test(name srcs)` que:
|
||||
- Crea un executable test linkeado contra `fn_framework`, ImGui (sin GLFW si no hace falta), Catch2.
|
||||
- Anade al `ctest` con `add_test(NAME ${name} COMMAND ${name})`.
|
||||
|
||||
### Fase 3 — Tests para puros (sin GUI)
|
||||
|
||||
3.1 `tween_curves`: lerp, ease_in, ease_out, edge cases (t=0, t=1, valores fuera de rango).
|
||||
3.2 `slice_at` de pie_chart (es funcion interna — exponer via header de test o moverla a `pie_math.h`).
|
||||
3.3 Cualquier helper puro de `bar_chart` (rotacion de labels), `kpi_card` (formato de delta).
|
||||
|
||||
### Fase 4 — Tests para componentes con state pero sin render (parcial)
|
||||
|
||||
4.1 Para `process_state_machine`, `file_poll_diff`, `sql_parse` (creados en 0045 si existen): tests directos.
|
||||
4.2 Para componentes UI (`button`, `select`, `tree_view`, etc.): solo logica accesible sin contexto ImGui (callbacks, state setters, formateo). Render real queda para tests visuales (issue 0048).
|
||||
|
||||
### Fase 5 — Hook con el indexer
|
||||
|
||||
5.1 Para cada funcion testeada, actualizar su `.md`: `tested: true`, `test_file_path: cpp/tests/test_<name>.cpp`. El indexer puebla `tests` automaticamente desde el archivo.
|
||||
5.2 `./fn index` y verificar:
|
||||
```bash
|
||||
sqlite3 registry.db "SELECT COUNT(*) FROM functions WHERE lang='cpp' AND tested=1;"
|
||||
```
|
||||
Meta: >=20 (de 81 = 25%).
|
||||
|
||||
### Fase 6 — CI gate (warmup, sin failure)
|
||||
|
||||
6.1 Anadir `cpp/scripts/run_tests.sh` que hace `cmake --build && ctest --output-on-failure`.
|
||||
6.2 Documentar en `cpp/PATTERNS.md` (issue 0041) que toda funcion nueva debe tener `tested: true`.
|
||||
|
||||
## Decisiones
|
||||
|
||||
- Catch2 v3 amalgamated (no header-only) — compila mas rapido despues del primer build.
|
||||
- Tests **no** intentan renderizar ImGui — pintar requiere GL context, complicado en CI. Tests visuales se hacen en issue 0048 con primitives_gallery + screenshots.
|
||||
|
||||
## Riesgos
|
||||
|
||||
- Algunos primitivos no tienen logica testeable sin contexto ImGui (ej. `toolbar` solo concatena items). En esos casos, escribir test trivial que verifica que el codigo compila + linkea, o saltarlo y documentar en `notes`.
|
||||
- Catch2 puede tardar 30-60s la primera vez. Aceptable.
|
||||
|
||||
## Validacion
|
||||
|
||||
```bash
|
||||
cd cpp/build && cmake -DBUILD_TESTING=ON .. && cmake --build . -j
|
||||
ctest --output-on-failure
|
||||
sqlite3 registry.db "SELECT id FROM functions WHERE lang='cpp' AND tested=1;"
|
||||
```
|
||||
|
||||
20+ tests pasando, 20+ funciones con `tested: true`.
|
||||
@@ -0,0 +1,107 @@
|
||||
# 0048 — Visual tests via primitives_gallery (golden screenshots) + CI gate para nuevas funciones
|
||||
|
||||
## Metadata
|
||||
|
||||
| Campo | Valor |
|
||||
|-------|-------|
|
||||
| **ID** | 0048 |
|
||||
| **Estado** | pendiente |
|
||||
| **Prioridad** | media |
|
||||
| **Tipo** | feature — testing infra + CI |
|
||||
|
||||
## Dependencias
|
||||
|
||||
Bloquea-por: **0047** (Catch2 montado).
|
||||
|
||||
---
|
||||
|
||||
## Objetivo
|
||||
|
||||
1. Anadir captura automatica de screenshots por demo en `primitives_gallery`, comparados pixel-a-pixel contra goldens en `cpp/tests/golden/`. Cada PR que toque un primitivo de UI muestra el diff.
|
||||
2. CI gate: PR que anada funcion nueva en `cpp/functions/` exige `tested: true` en el `.md`.
|
||||
|
||||
## Contexto
|
||||
|
||||
`primitives_gallery` ya renderiza cada primitivo del registry con datos sinteticos. Si capturamos PNGs por demo y los comparamos con goldens commiteados, tenemos test visual automatico para cualquier cambio que afecte a render.
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
cpp/
|
||||
├── apps/primitives_gallery/
|
||||
│ ├── main.cpp # MOD — flag --capture <out_dir>
|
||||
│ └── capture.{h,cpp} # NEW — render headless por demo, dump PNG
|
||||
├── tests/
|
||||
│ ├── golden/ # NEW
|
||||
│ │ ├── button.png
|
||||
│ │ ├── select.png
|
||||
│ │ ├── kpi_card.png
|
||||
│ │ └── ... (1 png por demo del gallery)
|
||||
│ ├── test_visual.cpp # NEW — corre gallery con --capture, compara con golden
|
||||
│ └── CMakeLists.txt # MOD
|
||||
└── scripts/
|
||||
├── run_tests.sh # MOD — incluye visual
|
||||
└── update_goldens.sh # NEW — regenera goldens
|
||||
```
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1 — Capture mode en primitives_gallery
|
||||
|
||||
1.1 Anadir flag `--capture <output_dir>`. Cuando esta activo:
|
||||
- Inicializa GLFW en modo offscreen (`glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE)`) o usa headless via EGL si esta disponible.
|
||||
- Para cada demo en `k_demos[]`: setea `g_selected_id`, hace 3 frames de warmup (para tooltips/animaciones estables), captura framebuffer con `glReadPixels`, guarda como PNG via `stb_image_write`.
|
||||
- Output: `<output_dir>/<demo_id>.png`.
|
||||
- Sale tras procesar todas.
|
||||
1.2 Si `--capture` no esta presente: comportamiento normal (interactivo).
|
||||
|
||||
### Fase 2 — Goldens iniciales
|
||||
|
||||
2.1 `scripts/update_goldens.sh`:
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
mkdir -p cpp/tests/golden
|
||||
./cpp/build/apps/primitives_gallery/primitives_gallery --capture cpp/tests/golden
|
||||
```
|
||||
2.2 Generar y commitear los PNGs como linea base.
|
||||
|
||||
### Fase 3 — Test visual
|
||||
|
||||
3.1 `test_visual.cpp` (Catch2): para cada demo, lanzar gallery con `--capture` a un dir temporal, comparar contra `cpp/tests/golden/<demo>.png` con tolerancia configurable (por defecto: 1% pixels distintos, threshold por canal 5/255).
|
||||
3.2 Si difiere, fallar con info: `expected golden/X.png, actual /tmp/.../X.png, diff Y%`.
|
||||
|
||||
### Fase 4 — CI gate para tested:true
|
||||
|
||||
4.1 Crear `cpp/scripts/check_tested.sh` que valida:
|
||||
```bash
|
||||
sqlite3 registry.db "SELECT id FROM functions
|
||||
WHERE lang='cpp' AND tested=0 AND created_at > date('now','-30 days')"
|
||||
```
|
||||
Si hay alguno → exit 1 con mensaje "anade test antes de mergear".
|
||||
4.2 Ganchar en `cpp/scripts/run_tests.sh` (post-ctest).
|
||||
|
||||
### Fase 5 — Documentar en PATTERNS
|
||||
|
||||
5.1 En `cpp/PATTERNS.md` (de 0041) anadir seccion "Tests visuales":
|
||||
- Como capturar nuevo golden cuando se anade un primitivo (`update_goldens.sh`).
|
||||
- Como diagnosticar diff (renderiza el png actual vs golden lado a lado).
|
||||
|
||||
## Decisiones
|
||||
|
||||
- Headless via GLFW invisible es lo simple. Si no funciona en algun entorno, usar EGL/swiftshader como fallback.
|
||||
- Tolerancia 1% para evitar flakes por antialiasing/font rendering distinto. Ajustable.
|
||||
- Goldens en repo (PNGs binarios) — pesa poco si los demos son pequenos (200x200 max).
|
||||
|
||||
## Riesgos
|
||||
|
||||
- Diferencias de rendering entre Linux dev y CI: usar mesa software rendering (`LIBGL_ALWAYS_SOFTWARE=1`) en ambos lados para consistencia.
|
||||
- Cambios cosmeticos legitimos en primitivos requieren regenerar goldens — flujo: `update_goldens.sh && git diff cpp/tests/golden/` para revisar visualmente.
|
||||
|
||||
## Validacion
|
||||
|
||||
```bash
|
||||
cmake --build cpp/build -j
|
||||
ctest --test-dir cpp/build -R visual --output-on-failure
|
||||
# Cambia un color en tokens, run otra vez, debe FALLAR.
|
||||
# update_goldens.sh + git diff muestra los pngs cambiados.
|
||||
```
|
||||
@@ -46,3 +46,11 @@
|
||||
| [0038](0038-gliner-entity-extractor.md) | GLiNER entity extractor (zero-shot NER multilingue) | pendiente | alta | feature | 0039, 0040 |
|
||||
| [0039](0039-glirel-relation-extractor.md) | GLiREL relation extractor (zero-shot triplets) | pendiente | media | feature | 0040 |
|
||||
| [0040](0040-hybrid-extraction-pipeline.md) | Pipeline hibrido extraccion grafos (regex + GLiNER + GLiREL + LLM fallback) | pendiente | media | feature | — |
|
||||
| [0041](0041-cpp-app-best-practices.md) | C++ app shell estandarizado (PATTERNS.md + AppConfig extendido) | pendiente | alta | feature | 0043 |
|
||||
| [0042](0042-cpp-layout-storage-public.md) | C++ layout_storage publico (extraer de shaders_lab) | pendiente | alta | feature | 0043 |
|
||||
| [0043](0043-cpp-apps-standardize-shell.md) | Estandarizar shell de las 4 apps C++ | pendiente | alta | refactor | 0046 |
|
||||
| [0044](0044-cpp-orphans-audit.md) | Auditar 52 funciones C++ huerfanas y poblar uses_functions | pendiente | media | chore | — |
|
||||
| [0045](0045-cpp-extract-pure-logic.md) | Extraer logica pura de impuros (sql_workbench, process_runner, file_watcher, shaders_lab compiler) | pendiente | media | refactor | — |
|
||||
| [0046](0046-cpp-refactor-raw-imgui.md) | Reemplazar raw ImGui en apps por primitivos del registry | pendiente | media | refactor | — |
|
||||
| [0047](0047-cpp-tests-foundation.md) | C++ tests foundation (Catch2 + top-20 primitivos) | pendiente | alta | feature | 0048 |
|
||||
| [0048](0048-cpp-visual-tests-ci-gate.md) | Visual tests via primitives_gallery + CI gate tested:true | pendiente | media | feature | — |
|
||||
|
||||
Reference in New Issue
Block a user