Files
fn_registry/docs/adr/0003-orphan-tu-as-separate-function-entry.md
egutierrez bf94893032 feat(cpp/viz): split orphan TUs as separate fn entries (ADR 0003)
Cuando una funcion del registry parte su .cpp en varios TUs por testabilidad
o separacion ImGui-vs-puro, cada TU adicional se registra como entrada propia
con su .md en lugar de extender file_path para listar varios archivos.

Aplicado a:
- graph_labels_select_cpp_viz: helpers puros (compute_degrees + labels_select).
- graph_viewport_selection_cpp_viz: clear/add/toggle/is_selected puros.
- graph_types_cpp_viz: TU de update_bounds + find_node_by_user_data.

graph_labels y graph_viewport actualizados para declarar las nuevas entradas
en uses_functions. Razon detallada en docs/adr/0003 + regla actualizada en
.claude/rules/uses_functions.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 11:51:10 +02:00

62 lines
4.5 KiB
Markdown

# ADR 0003 — TUs adicionales de una funcion C++ se registran como entrada propia
- **Fecha:** 2026-05-04
- **Estado:** accepted
## Contexto
Algunas funciones C++ del registry necesitan dividir su implementacion en varios `.cpp` por motivos legitimos:
- **Testabilidad sin ImGui**: `graph_labels` tiene `graph_labels_draw` (depende de `ImDrawList`) y `graph_labels_select` (logica pura). Mantenerlos en el mismo `.cpp` obliga a los tests unitarios a linkear ImGui solo para ejercer la seleccion de candidatos.
- **Separacion impl/header**: `graph_types.h` declara `GraphData` (tipo del registry, vive en `types/viz/graph_types.md`). Sus metodos miembro (`update_bounds`, `find_node_by_user_data`) se implementan en `graph_types.cpp` para no inlinear en cada TU consumidor.
- **Separacion logica vs render**: `graph_viewport` tiene la mecanica de pan/zoom/click (ImGui) y la mecanica de seleccion (vectores + flags, sin ImGui). Tests unitarios de seleccion no deberian abrir ventana.
El indexer asume `1 .cpp = 1 .md` — el campo `file_path` del frontmatter es un solo path. Si una funcion partia su impl en varios `.cpp`, los `.cpp` adicionales quedaban como huerfanos: el `CMakeLists.txt` los listaba para enlazar, pero no aparecian en `registry.db`. Resultado: una app nueva que consultaba el registry para reusar `graph_labels` recibia `file_path: graph_labels.cpp` y al compilar fallaba con `undefined reference to graph_labels_select`.
Esta sesion (2026-05-04) detecto 3 huerfanos asi:
- `cpp/functions/viz/graph_labels_select.cpp`
- `cpp/functions/viz/graph_viewport_selection.cpp`
- `cpp/functions/viz/graph_types.cpp`
## Decision
**Cada TU adicional se registra como una entrada propia del registry con su `.md`**. El parent declara la nueva entrada en `uses_functions`.
Estructura tras aplicar la decision:
```
cpp/functions/viz/
graph_labels.cpp ← parent: graph_labels_draw, graph_labels_draw_at (impure, ImGui)
graph_labels.md ← uses_functions: ["graph_labels_select_cpp_viz"]
graph_labels_select.cpp ← TU split: graph_compute_degrees, graph_labels_select (pure)
graph_labels_select.md ← entrada propia, purity: pure
graph_viewport.cpp ← parent: widget completo (impure, ImGui)
graph_viewport.md ← uses_functions: [..., "graph_viewport_selection_cpp_viz"]
graph_viewport_selection.cpp ← TU split: helpers de seleccion (pure)
graph_viewport_selection.md ← entrada propia, purity: pure
graph_types.h ← header del tipo (indexado en types/viz/graph_types.md)
graph_types.cpp ← TU impl de metodos miembro
graph_types.md ← entrada propia kind: function, purity: pure
```
## Alternativas descartadas
- **Extender `file_path` a `[paths]`** (lista). Romperia la convencion vigente y obligaria a tocar parser, store, schema FTS, sync API y vista del dashboard. Ganancia: ninguna, las apps siguen necesitando la informacion para enlazar.
- **`notes:` con instruccion de enlazar el TU adicional**. Frágil: ningun parser lo enforce, las apps lo olvidan.
- **Un solo `.cpp` macro con flags de compilacion**. Mantiene los tests acoplados a ImGui, no resuelve el problema raiz.
- **Mover el TU puro a `core/`**. Rompe la cohesion del modulo (los helpers son intimos a `graph_labels` / `graph_viewport`) y crea ciclos de includes.
## Consecuencias
- Nuevas funciones registradas: `graph_labels_select_cpp_viz`, `graph_viewport_selection_cpp_viz`, `graph_types_cpp_viz`.
- `cpp/functions/viz/graph_labels.md` y `cpp/functions/viz/graph_viewport.md` declaran las nuevas entradas en `uses_functions`.
- `graph_explorer/app.md` declara explicitamente las 3 entradas en su `uses_functions` — antes solo declaraba el parent y el `.cpp` adicional pasaba "de matute" via `CMakeLists.txt`.
- Convencion para futuros splits: si un parent añade un TU `<name>_<sufijo>.cpp` y exporta funciones nuevas, crear `<name>_<sufijo>.md` con `kind: function`, su propia firma, `purity` real (normalmente `pure` ya que ese es el motivo del split), y dependencias correctas. El parent enlaza via `uses_functions`.
## Aprendizaje
El registry funciona como API publica: lo que esta indexado define lo que las apps externas pueden consumir. Un `.cpp` que existe en disco pero no en la BD es invisible — y la unica garantia de "una app nueva sabra que enlazar" es que toda dependencia este declarada formalmente. El TU split no es un problema de organizacion del codigo: es un problema de superficie de API que tiene que reflejarse en el contrato del registry.