--- id: "0107" title: "Estandarizar sistema de modulos C++: limpiar drift data_table + politica API + version pinning + /version command" status: pendiente type: refactor domain: - meta - cpp-stack - tooling scope: multi-app priority: alta depends: [] blocks: - "0108" related: - "0097" - "0081" - "0086" created: 2026-05-17 updated: 2026-05-17 tags: [modules, cpp, data-table, framework, refactor, fn-doctor, versioning] --- # 0107 — Estandarizar sistema de modulos C++ ## Problema Auditoria 2026-05-17 sobre `modules/` (framework + data_table) revela que el sistema de modulos C++ esta a medio camino: la idea (modulos opt-in versionados con manifest auditable) es solida, pero su implementacion tiene fugas que invalidan el contrato. ### Drift uses_modules ↔ uses_functions (7/7 apps consumidoras) `module.md` dice "cuando declaras `uses_modules`, NO repetir los miembros en `uses_functions`". Realidad medida hoy: | App | uses_functions total | miembros data_table duplicados | |---|---|---| | services_monitor | 12 | 12 | | dag_engine_ui | 13 | 12 | | odr_console | 5 | 5 | | navegator_dashboard | 20 | 12 | | graph_explorer | 42 | 12 | | registry_dashboard | 37 | 11 | | app_gestion | 12 | 12 | 7 de 7 apps violan la regla clave que justifica el sistema. `fn doctor cpp-apps` no detecta el drift. ### `data_table.cpp` = 4777 LOC El "modulo" es un god-file con UI entera (chips, viz, grid, drill, joins, AI, button, color rules) dentro de un `.cpp`. Imposible auditar consumidores parciales, imposible registrar miembros como funciones reales del registry (cada uno con su `.md`). ### Boundary modulo vs funcion borrosa `lua_engine`, `llm_anthropic`, `join_tables` son members de `data_table`. Pero lua/llm/join son utiles fuera de tablas. Forzar membership infla el surface del modulo y obliga a las apps a tragarse lua+llm+anthropic+join aunque solo quieran render simple. No hay tier "data_table_core" vs "data_table_full". ### Versionado declarado, no enforced `module.md` tiene `version: 1.4.0`. `app.md` dice `uses_modules: [data_table_cpp]` sin version. Bump breaking de modulo → todas las apps rompen sin warning hasta compile error. ### Codegen silencioso `execute_process(... codegen_app_modules)` emite WARNING solo si rc != 0 y != 2. Si Python falta → stub vacio sin error. About panel muestra "0 modules" en apps que SI deberian tener 1. ### Hard dep oculto `fn_module_data_table` linkea `fn_framework` PRIVATE para `fn::local_path()`. `module.md` no lo documenta como precondicion publica. Si alguien intenta usar el modulo en una app no-framework, falla en link sin mensaje claro. ### Sin doc API de modulos No hay un sitio canonico que diga "para usar el modulo X, incluye Y.h, llama X::render(...), pasa State Z". Cada modulo lo improvisa en su `module.md`. ### Sin /version command No hay flujo estandar para bumpear semver de un modulo o framework. Cada PR lo hace a ojo, sin coherencia entre `module.md::version` y `## Capability growth log`. ## Decision Issue desglosado en 6 sub-issues independientes detras de feature flag `modules-v2`: 1. **0107a** — `fn doctor modules` que detecta drift uses_modules vs uses_functions. 2. **0107b** — Limpiar `uses_functions` de las 7 apps consumidoras de data_table (eliminar miembros duplicados). 3. **0107c** — Partir `modules/data_table/data_table.cpp` (4777 LOC) en sub-funciones del registry (`data_table_chips`, `data_table_grid`, `data_table_viz_panels`, `data_table_drill`, `data_table_ai_panel`, `data_table_color_rules`). Cada una con `.md` propio. Entrypoint queda thin. 4. **0107d** — Mover members generales (`lua_engine`, `llm_anthropic`, `join_tables`, `auto_detect_type`) fuera de `data_table` module. Quedan funciones sueltas que el modulo USA pero no posee. Crear tiers explicitos. 5. **0107e** — Version pinning en `uses_modules` (`uses_modules: [{name: data_table_cpp, min_version: "1.4"}]`) + codegen fail-loud (error si Python falta o count=0 cuando deberia ser >0). 6. **0107f** — `modules/README.md` (catalogo) + `docs/MODULES_API.md` (contrato publico por modulo: header path, namespace, entry function, State struct, lifecycle). Ademas: - `/version` slash command para bumpear semver de modulo/framework consistentemente (`module.md::version` + `## Capability growth log` + git commit). - `/fix-issue` referenciara `/version` cuando el cambio toque framework/modules. Feature flag `modules-v2` activado solo cuando 0107a-f cierran. Antes de cerrar, recompilar TODAS las apps cpp para verificar que el refactor no rompe linkage. Aceptamos coste de recompilacion total. ## Restriccion explicita Prohibido empezar `chat_ia` (proximo modulo planeado) hasta que 0107 cierre. Razon: si arrancamos otro modulo sin estandar estable, replicamos los mismos bugs en el doble de superficie. ## Tareas (resumen — detalle en sub-issues) - [ ] **1** Auditoria automatizada → `fn doctor modules` (0107a) - [ ] **2** Limpiar drift en 7 apps consumidoras (0107b) - [ ] **3** Partir `data_table.cpp` en sub-funciones del registry (0107c) - [ ] **4** Politica members generales + tiers (0107d) - [ ] **5** Version pinning + codegen fail-loud (0107e) - [ ] **6** Docs API publica modulos (0107f) - [ ] **7** Recompilar todas las apps cpp + verificar smoke (al cerrar) - [ ] **8** Activar feature flag `modules-v2` - [ ] **9** `/version` + `/fix-issue` (no son sub-issues; tareas inline en este issue principal) ## Desglose multi-issue | Sub-issue | Rama | Alcance | Estado | |-----------|------|---------|--------| | 0107a-fn-doctor-modules | issue/0107a-fn-doctor-modules | Check drift uses_modules vs uses_functions + version skew | pendiente | | 0107b-clean-data-table-consumers | issue/0107b-clean-data-table-consumers | Eliminar miembros duplicados en 7 app.md | pendiente | | 0107c-split-data-table | issue/0107c-split-data-table | Partir data_table.cpp 4777 LOC en sub-funciones del registry | pendiente | | 0107d-module-tiers-policy | issue/0107d-module-tiers-policy | Sacar lua/llm/join del modulo data_table; tiers + politica | pendiente | | 0107e-version-pinning-codegen | issue/0107e-version-pinning-codegen | min_version en uses_modules + codegen fail-loud | pendiente | | 0107f-modules-api-docs | issue/0107f-modules-api-docs | modules/README.md + docs/MODULES_API.md | pendiente | ### Feature flag Nombre: `modules-v2` Se activa cuando 0107a-f cierran + recompilacion total verificada + `fn doctor modules` reporta 0 drift. ### Progreso por tarea - [ ] **1.1** Implementar check drift en `fn doctor cpp-apps` o sub-comando nuevo — 0107a - [ ] **1.2** Output JSON con apps que violan regla — 0107a - [ ] **1.3** Tests sobre fixture sintetica (1 modulo, 3 apps simuladas) — 0107a - [ ] **2.1** Editar 7 `app.md` removiendo miembros data_table — 0107b - [ ] **2.2** Verificar build pasa post-clean (no rompe nada — solo metadata) — 0107b - [ ] **3.1** Identificar fronteras funcionales en data_table.cpp 4777 LOC — 0107c - [ ] **3.2** Crear `cpp/functions/viz/data_table_chips.cpp` + .h + .md — 0107c - [ ] **3.3** Crear `cpp/functions/viz/data_table_grid.cpp` + .h + .md — 0107c - [ ] **3.4** Crear `cpp/functions/viz/data_table_viz_panels.cpp` + .h + .md — 0107c - [ ] **3.5** Crear `cpp/functions/viz/data_table_drill.cpp` + .h + .md — 0107c - [ ] **3.6** Crear `cpp/functions/viz/data_table_ai_panel.cpp` + .h + .md — 0107c - [ ] **3.7** Crear `cpp/functions/viz/data_table_color_rules.cpp` + .h + .md — 0107c - [ ] **3.8** `data_table.cpp` queda como entrypoint thin que compone las sub-funciones — 0107c - [ ] **3.9** Bump `module.md::version` a 2.0.0 (breaking interno, API publica `data_table::render` intacta) — 0107c - [ ] **4.1** Crear `cpp/functions/core/lua_engine.cpp` (ya existe) como funcion suelta; quitar de `module.md::members` — 0107d - [ ] **4.2** Idem `llm_anthropic`, `join_tables`, `auto_detect_type` — 0107d - [ ] **4.3** Actualizar `modules/data_table/CMakeLists.txt`: estos `.cpp` ya no se enlazan dentro del modulo; apps que los necesiten los anaden a su CMakeLists — 0107d - [ ] **4.4** Definir tiers en `module.md`: `core_members` (esenciales) vs `optional_members` (deps externas pesadas) — 0107d - [ ] **5.1** Parser `app.md::uses_modules` acepta string corto y dict largo — 0107e - [ ] **5.2** Codegen comprueba `min_version` vs `module.md::version` — error si no cumple — 0107e - [ ] **5.3** Codegen: si `Python3 NOT FOUND` y app tiene `uses_modules` → CMake FATAL_ERROR — 0107e - [ ] **5.4** Codegen: si parser devuelve count=0 pero app.md declara `uses_modules` no-vacio → FATAL_ERROR — 0107e - [ ] **6.1** `modules/README.md` con tabla modulos + version + descripcion + link a contrato — 0107f - [ ] **6.2** `docs/MODULES_API.md` con contrato canonico (template + ejemplos data_table + framework) — 0107f - [ ] **6.3** Actualizar `.claude/rules/cpp_apps.md` referenciando `docs/MODULES_API.md` — 0107f - [ ] **7.1** `redeploy_all_cpp_apps_bash_pipelines` + verificar 0 errores de link — issue principal, al cerrar - [ ] **7.2** Smoke manual de cada app con `data_table::render` — issue principal, al cerrar - [ ] **8** Flip `modules-v2: enabled: true` en `dev/feature_flags.json` — issue principal - [ ] **9.1** Crear `.claude/commands/version.md` (slash command bump semver) — issue principal, ya en este turno - [ ] **9.2** Crear `.claude/commands/fix-issue.md` que referencie `/version` — issue principal, ya en este turno ## Arquitectura ### Archivos afectados **0107a** (`fn doctor modules`): - `functions/infra/audit_modules_drift.go` (NEW) — funcion del registry - `functions/infra/audit_modules_drift.md` (NEW) - `cmd/fn/doctor.go` — subcomando `modules` - `apps/registry_mcp/...` — exponer via `mcp__registry__fn_doctor subcommand="modules"` **0107b**: - 7 `app.md` editados: services_monitor, dag_engine_ui, odr_console, navegator_dashboard, graph_explorer, registry_dashboard, app_gestion. **0107c**: - `modules/data_table/data_table.cpp` — pasa de 4777 LOC a ~400 (entrypoint que compone). - `cpp/functions/viz/data_table_chips.cpp/.h/.md` (NEW) — ~600 LOC - `cpp/functions/viz/data_table_grid.cpp/.h/.md` (NEW) — ~1200 LOC - `cpp/functions/viz/data_table_viz_panels.cpp/.h/.md` (NEW) — ~800 LOC - `cpp/functions/viz/data_table_drill.cpp/.h/.md` (NEW) — ~300 LOC - `cpp/functions/viz/data_table_ai_panel.cpp/.h/.md` (NEW) — ~500 LOC - `cpp/functions/viz/data_table_color_rules.cpp/.h/.md` (NEW) — ~400 LOC - `modules/data_table/module.md` — bump version + actualizar members. - `modules/data_table/CMakeLists.txt` — anadir las sub-funciones a la static lib. **0107d**: - `modules/data_table/module.md` — quitar `lua_engine`, `llm_anthropic`, `join_tables`, `auto_detect_type` de members. - `modules/data_table/CMakeLists.txt` — estos `.cpp` salen. - Apps consumidoras que necesiten lua/llm/join → declarar en `uses_functions` + anadir el `.cpp` a su CMake. **0107e**: - `python/functions/infra/codegen_app_modules.py` — soporte dict largo `{name, min_version}`. - `cpp/CMakeLists.txt::add_imgui_app` — fail-loud en codegen errors. - `registry/parser.go` — indexer entiende dict largo. **0107f**: - `modules/README.md` (NEW) - `docs/MODULES_API.md` (NEW) - `.claude/rules/cpp_apps.md` — link nuevo doc. **Slash commands** (este issue): - `.claude/commands/version.md` (NEW) - `.claude/commands/fix-issue.md` (NEW si no existe) ### pkg/ puro vs shell/ impuro `audit_modules_drift_go_infra` (0107a) es **impuro** — lee `registry.db` + filesystem (`app.md`, `module.md`). Vive en `functions/infra/`. Core logico (comparar listas de IDs, detectar miembros duplicados) es **puro** y vive como sub-funcion interna del paquete `infra`. ## Ejemplo de uso ```bash # 1. Detectar drift fn doctor modules # Output: # Module drift report # =================== # data_table_cpp (v1.4.0): 7/7 consumers list members in uses_functions # services_monitor — duplicates: data_table_cpp_viz, viz_render_cpp_viz, ... # dag_engine_ui — duplicates: ... # Total apps with drift: 7 # Total modules: 2 # Exit: 1 # 2. Bump version de un modulo (slash command) /version modules/data_table minor "split data_table.cpp into 6 sub-functions; API publica intacta" # - Detecta version actual en module.md (1.4.0) # - Calcula proxima (1.5.0 si minor, 2.0.0 si major) # - Anade entrada a ## Capability growth log con fecha de hoy # - Stage en git pero NO commit # 3. Pinning version en una app # app.md: # uses_modules: # - name: data_table_cpp # min_version: "1.4" # Codegen falla en cmake si module.md::version < 1.4 # 4. fix-issue referencia /version /fix-issue 0107c # Flow normal del fix-issue + "¿este cambio bumpea version de modulo/framework? si si → /version" ``` ## Decisiones de diseno 1. **No tocar API publica `data_table::render(...)`**. Refactor interno. Apps existentes no cambian su llamada. 2. **Aceptamos recompilacion total**. El usuario lo dijo explicito. Coste de tiempo razonable a cambio de limpieza. 3. **Feature flag `modules-v2` no protege codigo runtime** — protege la "promesa" del sistema. Cuando flag flip, `fn doctor modules` debe pasar verde. 4. **`/version` NO hace commit**. Solo edita archivos + stage. El commit final lo hace el flujo normal del fix-issue. 5. **Bloqueamos `chat_ia`**. Si saltamos a otro modulo sin estandar, el caos se duplica. ## Prerequisitos - Issue 0097 (modules infra inicial) — completado, esto es la evolucion. - `fn doctor cpp-apps` existe (0081) — reutilizamos paths. ## Riesgos - **Refactor 4777 LOC**: alto riesgo de regresion visual/funcional. Mitigacion: smoke manual app-por-app + `primitives_gallery --capture` golden images antes/despues. - **Apps que dependen indirectamente de lua/llm/join** sin declararlo: post-0107d podrian fallar en link. Mitigacion: `fn doctor uses-functions` + recompilacion total como gate. - **Codegen fail-loud** rompe builds que hoy pasan con stub: deliberado, parte de la idea — pero hay que arreglar todos los app.md antes de mergear 0107e. ## Notas - `/version` se referenciara desde `/fix-issue` con prompt: "este cambio toca `modules/` o `cpp/framework/`? si si → run `/version [major|minor|patch] [reason]` antes de commit". - Politica: bump de modulo SIN bump de version = bug. `fn doctor modules` lo detectara via diff hash de `members` + `description` vs ultima version registrada.