---
id: "0096"
title: "Estandarizar ubicacion de apps: fuera de carpetas por lenguaje"
status: completado
type: feature
domain:
  - apps-infra
scope: app-scoped
priority: alta
depends: []
blocks: []
related: []
created: 2026-05-17
updated: 2026-05-17
tags: []
---
# 0096 — Estandarizar ubicacion de apps: fuera de carpetas por lenguaje

**Status:** pendiente
**Created:** 2026-05-15
**Type:** refactor
**Priority:** alta
**Blocks:** 0097 (data_factory) — no se arranca app nueva mientras la convencion esta rota

## Problema

La regla esta documentada (`.claude/rules/apps_vs_functions.md`, memoria `apps_location`): **toda app vive en `apps/` (independiente) o `projects/<p>/apps/` (de proyecto)**. NUNCA en una carpeta nombrada por lenguaje (`cpp/apps/`, `python/apps/`, etc.).

Violacion actual: `cpp/apps/` contiene 8 apps:

| Actual | Tipo | Destino propuesto |
|---|---|---|
| `cpp/apps/altsnap_jitter_test` | test ad-hoc | `apps/altsnap_jitter_test` |
| `cpp/apps/chart_demo` | demo standalone | `apps/chart_demo` |
| `cpp/apps/dag_engine_ui` | companion `apps/dag_engine` | `apps/dag_engine_ui` |
| `cpp/apps/engine_smoke` | smoke runtime | `apps/engine_smoke` |
| `cpp/apps/primitives_gallery` | demo componentes registry | `apps/primitives_gallery` |
| `cpp/apps/runtime_test` | smoke runtime | `apps/runtime_test` |
| `cpp/apps/shaders_lab` | tooling shaders | `apps/shaders_lab` (existe homonimo en `apps/shaders_lab` — VERIFICAR antes) |
| `cpp/apps/text_editor_smoke` | smoke editor | `apps/text_editor_smoke` |

Carpetas `python/apps/`, `bash/apps/`, `frontend/apps/` no existen — convencion solo rota por C++ historicamente.

## Por que importa

- **Auto-discovery**: `fn doctor cpp-apps`, `fn doctor artefacts`, indexador, `pc_locations` asumen `apps/` o `projects/<p>/apps/`. Soporte de `cpp/apps/` esparcido por codigo, ramas if-else, paths hardcodeados.
- **Sub-repos Gitea**: cada app es `dataforge/<name>` (ADR 0002). Path en disco no afecta al remoto pero la entrada `pc_locations.dir_path` diverge.
- **Onboarding**: nueva persona/agente lee la regla, ve `cpp/apps/`, asume que aplica solo a Go/Py. Confusion.
- **Scaffolder roto**: `init_cpp_app_bash_pipelines` puede haber generado en `cpp/apps/` historicamente; debe forzar `apps/`.

## Objetivo

1. Mover los 8 directorios `cpp/apps/*` -> `apps/*`.
2. Actualizar `cpp/CMakeLists.txt` para apuntar a los nuevos paths.
3. Actualizar `dir_path` en cada `app.md`.
4. `fn index` para refrescar registro.
5. `fn sync` para actualizar `pc_locations` en BD remota.
6. Modificar scaffolder `init_cpp_app_bash_pipelines` para escribir siempre en `apps/` (o `projects/<p>/apps/` si flag `--project`), nunca en `cpp/apps/`.
7. Anadir check `fn doctor artefacts` (o nuevo subcomando `fn doctor app-location`) que falle si encuentra cualquier artefacto bajo carpeta de lenguaje (`cpp/apps`, `python/apps`, `bash/apps`, `frontend/apps`, ademas `cpp/analysis`, etc.).
8. Borrar `cpp/apps/` vacio al final.

## Aceptacion

- `ls cpp/apps/ 2>/dev/null` devuelve vacio (o el directorio no existe).
- `ls apps/` incluye los 8 nuevos.
- `cmake --build cpp/build -j` compila todos los targets (mismo binario, distinto path source).
- Cada app sigue ejecutandose y pasando su `e2e_checks` (si declarado).
- `fn doctor artefacts` y `fn doctor cpp-apps` sin nuevos warnings.
- `fn doctor app-location` (nuevo) reporta 0 violaciones.
- `mcp__registry__fn_show id="<app>"` devuelve `dir_path: "apps/<app>"` para los 8.
- `init_cpp_app_bash_pipelines` con destino default crea en `apps/`, no `cpp/apps/`.
- ADR / regla `.claude/rules/cpp_apps.md` actualizada: tabla "Ubicacion" elimina la fila "App independiente | `cpp/apps/<nombre>/`" -> "App independiente | `apps/<nombre>/`".

## Plan de ejecucion

Por cada app `<X>` (en orden de dependencia: tests primero, luego demos, luego apps):

```bash
# 1. Verificar que no hay homonimo en apps/
test -d apps/<X> && echo "CONFLICT" || true

# 2. Mover (preserva .git interno del sub-repo)
git mv cpp/apps/<X> apps/<X>
# o si .git esta dentro y git mv complica: cp -a + rm + commit en sub-repo

# 3. Editar dir_path en apps/<X>/app.md
sed -i 's|dir_path: "cpp/apps/<X>"|dir_path: "apps/<X>"|' apps/<X>/app.md

# 4. Editar cpp/CMakeLists.txt para usar _DIR pattern como graph_explorer:
#    set(_<X>_DIR ${CMAKE_SOURCE_DIR}/../apps/<X>)
#    add_subdirectory(${_<X>_DIR} ${CMAKE_BINARY_DIR}/apps/<X>)

# 5. Re-build
cmake --build cpp/build -j --target <X>

# 6. Validar binario
./cpp/build/apps/<X>/<X> --self-test || ./cpp/build/apps/<X>/<X> --help
```

Una vez los 8 movidos:

```bash
rmdir cpp/apps/  # debe estar vacio
./fn index
./fn sync
./fn doctor app-location  # subcomando nuevo
```

### Sub-tareas (recomendado: una rama TBD por bloque)

| Rama | Apps | Comentario |
|---|---|---|
| `issue/0096-tests` | altsnap_jitter_test, engine_smoke, runtime_test, text_editor_smoke | smoke tests, riesgo bajo |
| `issue/0096-demos` | chart_demo, primitives_gallery | demos |
| `issue/0096-tools` | shaders_lab, dag_engine_ui | tooling. shaders_lab CHECK homonimo en `apps/shaders_lab` primero |
| `issue/0096-scaffolder` | — | parche a `init_cpp_app_bash_pipelines` + `fn doctor app-location` + regla `.md` |

Merge `--no-ff` a master tras cada bloque, validar build entre uno y otro.

## Riesgos

| Riesgo | Mitigacion |
|---|---|
| Homonimo en `apps/<X>` ya existente (caso `shaders_lab`) | Verificar `ls apps/<X>` antes de mover. Si existe: decidir merge / rename. |
| `git mv` rompe sub-repo interno con su propio `.git/` | El `.git/` viaja con el directorio. Verificar `git -C apps/<X> status` tras mv. Si rompe, cp -a + delete + commit. |
| `pc_locations` queda desincronizado en otros PCs | `fn sync` push tras cambios + `/full-git-pull` en otros PCs lo reconcilia. Documentar. |
| `cpp/CMakeLists.txt` con paths absolutos sucios | Usar variable `_<X>_DIR` con `${CMAKE_SOURCE_DIR}/../apps/<X>` igual que `graph_explorer`. Convencion ya probada. |
| Sub-repo tiene gitignore o config que asume path | Improbable. Verificar tras primer mv. |
| Memoria del usuario / claude assumes paths viejos | Actualizar `.claude/rules/cpp_apps.md` + memoria `apps_location` con nota explicita. |

## No-objetivos

- Mover `cpp/functions/`, `python/functions/`, `bash/functions/`, `frontend/functions/`. Estos NO son artefactos — son codigo del registry organizado por lenguaje. La regla solo aplica a apps/analysis/vaults/projects.
- Mover `cpp/build/`, `cpp/vendor/`, `cpp/framework/`. Son infraestructura compartida del registry C++, no artefactos.
- Renombrar apps. Solo se mueve directorio.
- Cambiar identidad de sub-repo Gitea (`dataforge/<name>` queda igual).

## Nueva regla: detector

Funcion nueva (delegar a fn-constructor): `audit_app_location_go_infra` (puro: scan filesystem). Reglas:

- Si encuentra `app.md` con `lang: cpp` (o cualquier lang) bajo `cpp/apps/`, `python/apps/`, `bash/apps/`, `frontend/apps/` -> reporta violacion.
- Lo mismo para `analysis.md` bajo carpetas de lenguaje.
- Wrap en `fn doctor app-location`.

Add al `fn doctor` agregador.

## Telemetria objetivo

- 8 entradas en `pc_locations` actualizadas (`entity_type='app'`, `dir_path` cambia de `cpp/apps/*` a `apps/*`).
- `function_stats` de `init_cpp_app_bash_pipelines`: incremento de version (v1.x.0 -> v1.(x+1).0) por el cambio de default path.
- `fn doctor app-location` con 0 violaciones tras ejecucion.
