---
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 <path> [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.
