Files
fn_registry/dev/issues/completed/0045-cpp-extract-pure-logic.md

116 lines
4.8 KiB
Markdown

---
id: "0045"
title: "Extraer logica pura de componentes C++ impuros (sql_workbench, process_runner, file_watcher)"
status: completado
type: refactor
domain:
- cpp-stack
- registry-quality
scope: registry-only
priority: media
depends: []
blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: []
---
# 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
```