Files
fn_registry/docs/adr/0003-orphan-tu-as-separate-function-entry.md
T
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

4.5 KiB

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.