---
id: "0107e"
title: "uses_modules con min_version + codegen fail-loud"
status: pendiente
type: feature
domain:
  - meta
  - cpp-stack
  - tooling
scope: registry
priority: media
depends:
  - "0107a"
blocks: []
related:
  - "0107"
created: 2026-05-17
updated: 2026-05-17
tags: [modules, versioning, codegen, fail-loud, ausente-ready]
---

# 0107e — Version pinning + codegen fail-loud

Parte del issue principal [0107](0107-modules-standardization.md).

## Objetivo

Permitir que `app.md` declare version minima del modulo y que el codegen falle ruidosamente si:

1. Modulo declarado en `uses_modules` tiene `version < min_version`.
2. Python3 no disponible y `uses_modules` no vacio.
3. Codegen produce `count = 0` cuando `uses_modules` declara N>0 modulos.

## Schema extendido `app.md::uses_modules`

```yaml
# Forma corta (back-compat, sin pinning):
uses_modules: [data_table_cpp]

# Forma larga (con pinning):
uses_modules:
  - name: data_table_cpp
    min_version: "1.4"        # SemVer minor — acepta 1.4.x, 1.5.x, ..., NO 2.0.0
  - name: chat_ia_cpp
    min_version: "0.1"

# Mixed permitido:
uses_modules:
  - data_table_cpp           # sin pin
  - name: framework_cpp      # con pin
    min_version: "1.1"
```

Reglas:
- `min_version` formato `MAJOR.MINOR` (no patch — patch siempre bug fix compatible).
- Comparacion: `module.md::version >= min_version` AND `module.md::version.major == min_version.major`. Esto previene saltos de major silenciosos.

## Tareas

- [ ] **5.1** `python/functions/infra/codegen_app_modules.py`: parser acepta string corto Y dict largo.
- [ ] **5.2** Codegen lee `module.md::version` y compara contra `min_version` declarado en `uses_modules`. Si falla → exit 3 con mensaje claro.
- [ ] **5.3** `cpp/CMakeLists.txt::add_imgui_app`: si codegen exit != 0 AND != 2 → `message(FATAL_ERROR ...)` (no WARNING como hoy).
- [ ] **5.4** Si Python3 NO encontrado AND `app.md` tiene `uses_modules` no vacio → `message(FATAL_ERROR "Python3 required to parse uses_modules; install python3.")`.
- [ ] **5.5** Si codegen devuelve count=0 cuando `uses_modules` declara N>0 → `message(FATAL_ERROR ...)` con apunta a la app.md.
- [ ] **5.6** Indexer `registry/parser.go`: parsea ambas formas y persiste en `apps.uses_modules_json` con shape canonico `[{name, min_version}]` (min_version null si no declarado).
- [ ] **5.7** Test: app sintetica con dict largo + modulo sintetico con version 1.3 y min_version 1.4 → cmake configure falla con mensaje esperado.
- [ ] **5.8** Migrar 7 apps consumidoras de data_table a usar dict largo con `min_version: "1.4"` (o lo que sea v actual cuando 0107e cierre).

## Mensajes de error esperados

```
CMake Error at cpp/CMakeLists.txt:289 (message):
  codegen_app_modules failed for services_monitor: module 'data_table_cpp'
  version 1.3.0 does not satisfy min_version 1.4 declared in
  apps/services_monitor/app.md::uses_modules.

  Either bump module version (via /version) or relax pin in app.md.
```

```
CMake Error at cpp/CMakeLists.txt:289 (message):
  codegen_app_modules: app 'dag_engine_ui' declares uses_modules: [data_table_cpp]
  but generated module manifest has count=0.

  Likely cause: Python parser failed silently. Re-run with verbose:
    python3 python/functions/infra/codegen_app_modules.py \
      --app-md apps/dag_engine_ui/app.md \
      --modules-root modules/ \
      --app-name dag_engine_ui \
      --out /tmp/test.cpp
```

## Riesgos

- **Apps existentes sin pinning rompen?**: NO. La forma corta sigue valida y trata `min_version` como null = sin chequeo. Solo apps que opten explicitamente reciben gate.
- **Build se vuelve ruidoso si modulo no se actualizo**: deliberado. Es el sentido del fail-loud.
