Files
fn_registry/CHANGELOG.md
T
egutierrez 7eb7b3d0c8 chore: snapshot WIP previo + flow 0008 + 7 sub-issues (0112-0119)
Snapshot de WIP acumulado de sesiones previas antes de merge wave 1
del flow 0008 (kanban_cpp + agent_runner_api + DoD schema).

Incluye:
- dev/flows/0008-kanban-cpp-and-agent-workflows.md
- dev/issues/0112-0119*.md (7 sub-issues)
- WIP previo en cmd/fn/doctor.go, registry/*, modules/, cpp/, etc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 18:17:08 +02:00

39 KiB
Raw Blame History

Changelog

Todos los cambios notables de fn_registry se documentan aquí.

Formato basado en Keep a Changelog. Al no haber releases semver formales, las entradas se ordenan por fecha.

Para contexto detallado del trabajo diario ver docs/diary/. Para decisiones arquitecturales ver docs/adr/.

[Unreleased]

2026-05-17

Added

  • Bloque service: en frontmatter de app.md (issue 0105) — toda app con tag: service declara ahora port, health_endpoint, health_timeout_s, systemd_unit, systemd_scope, restart_policy, runtime (systemd-user|systemd-system|docker-compose|stdio|manual), pc_targets[], is_local_only. 11 apps actualizadas: sqlite_api, dag_engine, call_monitor, kanban, deploy_server, registry_mcp, registry_api, footprint_geo_stack, element_matrix_chat, agents_and_robots, services_api.
  • Migration 014_service_metadata.sql — anade 8 columnas (service_port, service_health_endpoint, service_health_timeout_s, service_systemd_unit, service_systemd_scope, service_restart_policy, service_runtime, service_is_local_only) a apps + tabla nueva service_targets (app_id, pc_id, role) con indices por app_id y pc_id.
  • registry.App.Service *ServiceSpec + parser rawService + escritura/lectura en InsertApp/scanApps/Purge (preserva service_targets). API publica db.GetServicePCTargets(appID) []string.
  • audit_services_spec_go_infra (functions/infra/audit_services_spec.{go,md}) — audita apps tag: service y reporta drift del bloque service: (runtime allowlist, pc_targets >=1, systemd_unit obligatorio si runtime empieza con systemd-, restart_policy en always|on-failure|none).
  • fn doctor services-spec — subcomando nuevo en cmd/fn/doctor.go. Salida tabwriter + --json. Hoy: 11/11 services with complete service: block.
  • App services_api (apps/services_api/, issue 0106) — Go HTTP daemon en 127.0.0.1:8485. Loop paralelo cada 15s (max 8 in-flight, timeout 20s/probe) que reconcilia esperado vs real para cada (app, pc) cruzado de service_targets. Probes locales (systemctl is-active + TCP dial + http.Client) o remotos (ssh_exec_go_infra). Persiste en operations.db: service_state (snapshot actual) + service_transition (cambios de overall append-only). Endpoints GET /api/health, GET /api/services, POST /api/check, GET /api/pcs. systemd unit ~/.config/systemd/user/services_api.service con Restart=always.
  • App services_monitor (apps/services_monitor/, issue 0106) — frontend C++ ImGui. Polling auto cada 5s configurable + boton "Force check" (POST /api/check). Tabla 9-col agrupada por app: overall pill, systemd state, port + listening flag (TI_PLUG/TI_PLUG_CONNECTED), HTTP status+latency, runtime, last change age, error/note. JSON via vendor/nlohmann/json.hpp (copiado de data_factory). HTTP socket TCP via http_client.{cpp,h} (copiado de data_factory). Build linux + windows con add_imgui_app + ws2_32 en Win. Deploy automatico via redeploy_cpp_app_windows.
  • Issues 0105 + 0106 (dev/issues/) — estandarizacion del bloque service: y app services_monitor.

Fixed

  • sqlite_api.service murio 20h sin alerta el 2026-05-17 — Raiz: el unit tenia Restart=on-failure y el ultimo exit fue por SIGTERM (limpio, no failure). systemd NO reinicia exit success. Fix: cambio a Restart=always + RestartSec=5. Reload + restart inmediato. Detectado mientras se debuggeaba data_factory cargando lento (raiz: data_factory llama a sqlite_api:8484, timeout 3s, no responde). Aplicado el mismo Restart=always al unit nuevo services_api.service.
  • sqlite_api/app.md health_endpoint — declaraba /api/status que devuelve 404. Cambiado a /api/databases (200, lista de bases registradas). Detectado por el primer ciclo del propio services_api que marcaba sqlite_api como degraded.

Changed

  • services_monitor tags — sin service/services en tags para evitar falso positivo en el matcher tags LIKE '%service%' del audit services-spec. La app es desktop client (frontend), no daemon.

2026-05-16

Added

  • Panel "Logs" en dag_engine RunDetailapps/dag_engine/frontend/src/pages/RunDetail.tsx anade <Paper> final con <Code block> scrollable + CopyButton de Mantine. Helper buildLogText(run, steps) compone texto plano (metadata del run + por-step status/exit/duration/stdout/stderr indentado) para pegar entero al LLM sin abrir los Collapse del StepTimeline.

Fixed

  • dag_engine steps function: fallando con error: function "<id>" not found (tried as ID and name) — tres DAGs nocturnos (fn_backup x2, daily-registry-audit) fallaron 2026-05-15/16 porque el binario fn resolvia una copia stale apps/dag_engine/registry.db (May 15, 262 KB) en vez del registry.db raiz. Raiz: el systemd unit dag_engine.service tiene WorkingDirectory=apps/dag_engine/ y no exportaba FN_REGISTRY_ROOT; cmd/fn/ops.go::tryOpenRegistryDB cae al walk-up go.mod (devuelve apps/dag_engine/). Fix:
    • Borrado apps/dag_engine/registry.db stale (violaba .claude/rules/db_locations.md).
    • ~/.config/systemd/user/dag_engine.service: anadido Environment=FN_REGISTRY_ROOT, FN_BIN, PATH (con /usr/local/go/bin para steps function: Go sin tests que invocan go vet), HOME.
    • apps/dag_engine/executor.go: steps function: exportan FN_REGISTRY_ROOT=<root> en env y default dir = fnRegistryRoot si step.Dir/dag.WorkingDir vacios. Steps command:/script: sin cambio.

Added

  • Iconos .ico Windows para apps C++ — 11 apps GUI (chart_demo, dag_engine_ui, data_factory, graph_explorer, navegator_dashboard, odr_console, primitives_gallery, registry_dashboard, shaders_lab, text_editor_smoke, altsnap_jitter_test) ahora tienen icono propio en el .exe y en <exe_dir> desplegado.

    • Glyphs: Phosphor Icons (fill weight), clonado en sources/phosphor-core/ (1512 SVGs disponibles). Cada app usa un accent_hex distinto (Tailwind 500-700) para distinguirse en taskbar/desktop.
    • Mapping inicial en dev/gen_app_icons.py (script reproducible). Cada .ico multi-resolucion (16/24/32/48/64/128/256).
    • Wiring CMake: cpp/CMakeLists.txt:1-5 declara LANGUAGES C CXX RC en WIN32; add_imgui_app macro detecta <app_dir>/appicon.ico y genera <target>_appicon.rc enlazado via windres (toolchain cpp/toolchains/mingw-w64.cmake).
    • Nueva funcion del registry: generate_app_icon_py_infra (python/functions/infra/generate_app_icon.{py,md}). Toma phosphor_icon_name + accent_hex + out_ico_path y exporta .ico multi-res. Tags: cpp-windows, icon, phosphor.
    • Convencion documentada en .claude/rules/cpp_apps.md §11.
  • C++ framework — Alt+RMB resize / Alt+LMB move anywhere (cpp/framework/app_base.cpp). WndProc subclass detecta WM_RBUTTONDOWN/WM_LBUTTONDOWN con GetAsyncKeyState(VK_MENU) & 0x8000, ReleaseCapture + PostMessage(WM_SYSCOMMAND, SC_SIZE|dir | SC_MOVE|HTCAPTION). Modal nativo, cero jitter automatico via gate sizemove existente. Aplica a main + cada viewport flotante (subclass per-frame).

  • C++ framework — multi-HWND subclass para anti-jitter. g_subclassed ahora unordered_map<HWND, WNDPROC>, scan per-frame en pio.Viewports instala subclass en cada HWND nuevo, prune_dead_subclassed() con IsWindow, uninstall_sizemove_subclass_all() al exit. Fix del temblor en paneles flotantes (no solo el main HWND).

  • C++ framework — iconified survival de paneles flotantes. Antes glfwWaitEvents+continue paraba el frame loop entero al minimizar el main → secondary viewports congelados/ocultos. Ahora detecta secondary viewports y fall-through al frame normal si existen; solo duerme cuando no hay flotantes.

  • C++ framework — fn::internal::* test observability. sizemove_enter_count(), alt_rmb_resize_count(), alt_lmb_move_count(), rbuttondown_seen_count(), set_force_alt_for_test(bool). Counters monotonicos zero-cost, modo test salta PostMessage SC_SIZE/SC_MOVE para no atrapar al harness en modal.

  • apps/altsnap_jitter_test/ — extendido a 6 phases (p1 sync, p2 main HWND modal, p3 secondary HWND modal, p4 iconify+restore preserva floating, p5 Alt+RMB consumed, p6 Alt+LMB consumed). Todas PASS en Windows.

  • redeploy_all_cpp_apps_bash_pipelines — pipeline nuevo bash/functions/pipelines/redeploy_all_cpp_apps.sh que cross-compila todo el arbol cpp/ en un solo cmake pass + redeploy de cada .exe al Desktop. Filtro opcional por substring de nombre. Tolerante a fallos (build best-effort, summary OK/SKIPPED/FAILED). Tags: cpp, windows, deploy, redeploy, bulk, cpp-windows. Composicion: build_cpp_windows_bash_infra + loop taskkill.exe + deploy_cpp_exe_to_windows_bash_infra.

Changed

  • io.ConfigWindowsMoveFromTitleBarOnly = true en fn::run_app. Floating panels (viewport secundario = OS window borderless con UNA ventana ImGui rellenandolo) ahora respetan "solo header arrastra" como las decoradas. Fix del drag-anywhere-sin-alt en panel flotante. Alt+LMB anywhere sigue funcionando (subclass consume antes que ImGui).
  • resolve_cpp_app_dir_bash_infra v1.1.0 — ahora busca apps tambien en apps/<X>/ (canonical issue 0096) ademas de cpp/apps/<X>/ (legacy) y projects/*/apps/<X>/. Fix retroactivo: ./fn run compile_cpp_app <name> fallaba para apps en el layout canonical (ej. dag_engine_ui). Deduccion desde CWD tambien actualizada. Helper interno _list_cpp_apps.

Notes

  • Apps C++ redesplegadas via redeploy_all_cpp_apps: 12 OK / 1 SKIP (data_factory sin .exe target) / 0 FAILED. Todas tienen los fixes del framework activos.
  • ImGui_ImplGlfw subclassea el HWND DESPUES que nuestro framework. ImGui captura nuestro WndProc como PrevWndProc y chainea via CallWindowProc, asi que el subclass nuestro sigue recibiendo TODOS los mensajes en el orden correcto. NO re-subclassear despues de ImGui init (provoca recursion infinita por cycle: our_proc -> orig=imgui_proc -> imgui_proc -> prev=our_proc -> ...).
  • Pre-existing build break en cpp/tests/test_llm_anthropic.cpp + cpp/tests/test_graph_icons.cpp por uso de setenv() que no existe en mingw-w64. NO bloquea redeploy_all_cpp_apps (build best-effort). Candidato a guard #ifdef _WIN32 con _putenv_s o skip cross-compile. No introducido por esta sesion.

2026-05-14

Added

  • Issue 0086 — Monitor tab del registry_dashboard (sub-repo dataforge/registry_dashboard). Pestaña Monitor primera y por defecto del TabBar, landing del bucle reactivo construir->ejecutar->recopilar->analizar->mejorar.
    • 7 KPIs (Calls / MCP / Reg % / Errors / Violations / Copies / Versions) filtradas por ventana temporal (1h/24h/7d/30d/All).
    • Sub-tab Recent Executions con columnas When/Function/Tool/ms/OK/Error. Columna Function muestra $ <snippet> en gris cuando function_id vacio, hover tooltip con comando completo. Checkbox Only registry functions filtra por function_id != ''.
    • Sub-tab Failed Functions (5a) — subset filtrado a registry-functions fallidas, columnas When/Function/Tool/Error class/Error snippet, function_id en rojo.
    • Live scatter duracion (ms) vs time: eje X auto-scroll a now, ventana configurable (1m/5m/15m/1h/6h) independiente del filtro de KPIs, eje Y dinamico 0..max(visible)+500ms. Hora local (UseLocalTime). Series ok/error en verde/rojo. Hover sobre punto = tooltip Function/Tool/Duration/Error.
    • Indicador live/offline con timestamp del ultimo evento WS.
  • WebSocket live stream sqlite_api -> registry_dashboard (sub-repo dataforge/sqlite_api). Endpoint GET /api/events/call_monitor. Hub global con subscribers; ticker arranca solo con >=1 subscriber (cero overhead si nadie mira). Cliente recibe snapshot inicial (KPIs + 100 ultimas filas + watermark) y luego deltas id > watermark. Cliente puede mandar {watermark: N} para resumir tras reconexion.
  • WS client C++ hand-rolled RFC6455 en ws_client.{h,cpp} (~330 LOC) en el dashboard. Localhost-only (no TLS). Thread propio, reconnect exponencial 0.5s->8s, FIN/text/ping/pong/close handling, queue thread-safe drenada cada frame.
  • Migration 007 command_snippet en calls (projects/fn_monitoring/apps/call_monitor/migrations/007_calls_command_snippet.sql). Aditiva, idempotente. Llena por hook hook_call_monitor.sh solo cuando function_id == ''. Redactado de password=/token=/secret=/api_key=/bearer=. Truncado 200 chars.
  • Issue 0087 — Capability Discovery Acceleration. Modelo 5 capas + 7 piezas (ver dev/issues/0087-*.md).
    • fn match (cmd/fn/match.go) — subcommand fuzzy-FTS5 que dado un comando devuelve top-N funciones del registry candidates. Latencia 6-7ms. Output JSON con score (normalizado top=1.0) + raw_score (absoluto pre-normalizacion) + high_confidence gate (raw_score >= 4.0 AND top1.raw/top2.raw > 1.5).
    • fn doctor capabilities --emit-claude-md (cmd/fn/doctor.go + functions/infra/emit_capabilities_md.go) — emite bloque markdown con secciones TOP 20 (por calls_total), Fresh 7d, Pipelines top 5. Fallback si call_monitor.operations.db ausente.
    • call_monitor sequences --detect [--propose] (projects/fn_monitoring/apps/call_monitor/sequences.go + migrations/006_function_sequences.sql). Detecta secuencias A->B(->C) en calls (same session, gap < 30s, occ >= 5, sess >= 2, success_rate >= 0.9) y abre proposals new_pipeline automaticamente.
    • Hook PreToolUse hook_fn_match.sh — denylist + fn match con timeout 0.2s. Inyecta <system-reminder>FUZZY-MATCH: USE ./fn run <id> cuando confidence alta. Latencia 113ms trigger / 32ms denylist. Registrado en .claude/settings.local.json (Bash matcher).
    • Hook UserPromptSubmit hook_capabilities_inject.sh — cache 1h en ~/.cache/fn_registry/capabilities.txt. Emite JSON hookSpecificOutput.additionalContext con linea compacta CAPABILITIES: TOP / FRESH / PIPELINES. Latencia cold 33ms / warm 18ms.
    • Timer systemd user call_monitor_sequences.timer (OnCalendar 0/6h) + .service oneshot ejecutando call_monitor sequences --detect --propose --report. Versionado en projects/fn_monitoring/apps/call_monitor/systemd/.
  • 3 funciones nuevas grupo cpp-windows + pagina madre docs/capabilities/cpp-windows.md:
    • launch_cpp_app_windows_bash_infracmd.exe/PowerShell Start-Process para lanzar exe en Windows desde WSL2.
    • is_cpp_app_running_windows_bash_infratasklist.exe /FI con exit code 0/1 + stdout RUNNING: PID=N MEM=K o NOT_RUNNING.
    • redeploy_cpp_app_windows_bash_pipelines — pipeline build? + deploy + launch + verify en 1 invocacion. Reemplaza ~6 commands manuales.
  • ADR 0004 docs/adr/0004-telemetry-driven-capability-growth.md — formaliza el bucle telemetria -> proposal -> capability group -> discovery acceleration como motor de crecimiento del registry.
  • Regla .claude/rules/function_growth_and_self_docs.md (entry #30 en INDEX.md) — contrato .md autosuficiente (Ejemplo + Cuando usarla + Gotchas + Growth log) + crecimiento del registry por promocion de composiciones, NO por inflado de funciones individuales.

Changed

  • .claude/CLAUDE.md Norte ampliado — 4o objetivo PROMOVER COMPOSICIONES A PIPELINES (el registry crece por composicion, no por inflado). Linea sobre auto-discovery zero-second-lookup.
  • .claude/rules/registry_calls.md — clausula nueva: hooks e infraestructura de telemetria (fn_match, fn doctor, call_monitor) pueden leer registry.db directo con conexion read-only. NO sujeto a regla MCP-first (no son acciones del agente).
  • /fn_claude command mejorado con objetivos del Monitor + interpretacion de FUZZY-MATCH hint + CAPABILITIES line + threshold semantica.

Fixed

  • launch_cpp_app_windows quoting bugcmd.exe /c "cd /d \"$dir\" && start ..." rompia con paths Windows (el \" final se interpretaba como escape de comilla -> string sin cerrar -> "Windows cannot find \"). Fix: reescribir a powershell.exe -Command "Start-Process -FilePath ... -WorkingDirectory ..." (single-quote PowerShell es literal, sin procesar \ ni $).
  • fn match high_confidence siempre true — debido a normalizacion top=1.0. Fix: añadir raw_score preservado pre-normalizacion + gate dual raw_score >= 4.0 AND top1.raw/top2.raw > 1.5. Threshold 4.0 tuneado contra 14 patrones del analysis domain_coverage_gaps (~93% precision).

2026-05-07

Added

  • fn doctor CLI (cmd/fn/doctor.go) — entrypoint unico read-only para diagnostico del registry y artefactos. Subcomandos: artefacts (git/venv/app.md/upstream), services (apps tag service + systemctl + puerto), sync (drift pc_locations BD vs disco), uses-functions (imports reales vs declarados en app.md), unused (funciones sin consumidores). Flag --json para agentes/scripts. Cada subcomando es wrapper fino sobre una funcion del registry.
  • .claude/rules/fn_doctor.md — regla 23 en INDEX.md. Documenta cuando usar, mapeo subcomando → funcion del registry, y acciones derivadas (que hacer cuando reporta un drift).
  • bash/functions/infra/backup_sqlite_db (backup_sqlite_db_bash_infra, impure) — snapshot atomico de SQLite via VACUUM INTO. Mas seguro que cp con escrituras concurrentes.
  • bash/functions/infra/rotate_backups (rotate_backups_bash_infra, impure) — retention rsnapshot-style daily.N/weekly.M/monthly.K.
  • bash/functions/infra/wait_for_http (wait_for_http_bash_infra, impure) — poll URL hasta 2xx con timeout, util en deploys/smoke tests.
  • bash/functions/infra/wait_for_port (wait_for_port_bash_infra, impure) — poll TCP host:puerto. Usa nc o /dev/tcp builtin (sin deps).
  • bash/functions/infra/port_kill (port_kill_bash_infra, impure) — mata proceso(s) escuchando un puerto. Idempotente, fallback KILL tras TERM.
  • bash/functions/infra/tail_journal (tail_journal_bash_infra, impure) — wrapper journalctl con auto-deteccion --user vs sistema, prioridad y --since.
  • bash/functions/infra/pre_commit_hook_install (pre_commit_hook_install_bash_infra, impure) — instala hook que llama scan_secrets_in_dirty_bash_cybersecurity antes de cada commit. Idempotente con marca fn_registry-pre-commit-v1.
  • functions/infra/notify_telegram (notify_telegram_go_infra, impure) — envia mensaje a chat Telegram via Bot API. Trunca >4096 chars.
  • functions/infra/artefact_doctor (artefact_doctor_go_infra, impure) — audita salud de cada app/analysis: dir existe, .git presente, manifest parseable, .venv valido (analyses), upstream configurado.
  • functions/infra/services_status (services_status_go_infra, impure) — apps con tag service + systemctl is-active (user/system) + puerto declarado en notes/description + check TCP localhost.
  • functions/infra/pc_locations_drift (pc_locations_drift_go_infra, impure) — detecta drift pc_locations BD vs disco para el PC actual (~/.fn_pc). Tres tipos: missing_on_disk, untracked_on_disk, status_should_be_active.
  • functions/infra/audit_uses_functions (audit_uses_functions_go_infra, impure) — para cada app Go/Py compara imports reales contra uses_functions del app.md. Reporta missing_in_app_md y unused_in_app_md. Heuristica documentada (puede dar falsos positivos en unused).
  • functions/infra/find_unused_functions (find_unused_functions_go_infra, impure) — funciones del registry sin consumidores en otras funciones, apps o analyses. Pipelines sin tag launcher tambien aparecen.
  • bash/functions/pipelines/backup_all (backup_all_bash_pipelines, impure, tag launcher) — orquesta backup_sqlite_db + rotate_backups sobre registry.db, cada apps/*/operations.db, y rsync --link-dest para vaults declarados en projects/*/vaults/vault.yaml.

Changed

  • .claude/CLAUDE.md — seccion CLI ampliada con comandos fn doctor [subcommand] [--json] y enlace a la regla.
  • .claude/rules/INDEX.md — anadida fila 23 para fn_doctor.md.

Fixed

  • functions/infra/pc_locations_drift.gofilepath.Join(absoluto, absoluto) producia paths corruptos cuando dir_path ya era absoluto (caso comun: filas pc_locations traen path absoluto al disco del PC). Fix: chequear filepath.IsAbs antes de unir. Sintoma previo: todos los artefactos reportados como missing_on_disk aunque existieran.
  • go.modgolang.org/x/net movido a deps directas (go mod tidy tras anadir notify_telegram).

Notes

  • Hallazgo de la primera ejecucion fn doctor uses-functions: 7/12 apps con drift real (auto_metabase, dag_engine, deploy_server, docker_tui, kanban, metabase_registry, script_navegador). Pendiente sincronizar sus app.md con los imports reales en sesion futura.
  • fn doctor unused muestra muchas funciones core sin consumidores aun (compose2_go_core, curry2_go_core, etc.). Esperado: el registry crece antes que las apps que las consuman.

2026-05-04

Added

  • cpp/functions/viz/graph_labels_select (graph_labels_select_cpp_viz, pure) — TU separado de graph_labels con los helpers puros graph_compute_degrees y graph_labels_select (frustum cull + always_for_* + top-N por size * (degree+1)). Vive en su propio archivo para que los tests unitarios lo cubran sin abrir ImGui.
  • cpp/functions/viz/graph_viewport_selection (graph_viewport_selection_cpp_viz, pure) — TU separado de graph_viewport con clear_selection, is_selected, add_to_selection, toggle_selection. Mantienen sincronizados state.selection y nodes[i].flags & NF_SELECTED.
  • cpp/functions/viz/graph_types (graph_types_cpp_viz, pure) — TU de implementacion de GraphData::update_bounds() y GraphData::find_node_by_user_data(). Pareja obligatoria del header del tipo (graph_types.h indexado en types/viz/).
  • cpp/apps/chart_demo/app.md — la demo de primitivos viz (line/scatter/bar/heatmap) ahora aparece en el registry como chart_demo_cpp_viz.
  • cpp/apps/shaders_lab/app.md — el live GLSL playground con DAG ahora tiene app.md propio (antes solo existia entrada legacy en BD sin .md en disco).

Changed

  • registry/indexer.go — el indexer ahora escanea tambien <lang>/apps/*/app.md (mismo patron que ya usaba para <lang>/functions/ y <lang>/types/). Antes solo veia apps/ y projects/*/apps/ — las apps en cpp/apps/ quedaban invisibles. ./fn index reporta 17 apps (antes 15).
  • cpp/functions/viz/graph_labels.mdsignature reducida a graph_labels_draw y graph_labels_draw_at (los helpers puros pasan a entrada propia). uses_functions apunta a la nueva entrada graph_labels_select_cpp_viz.
  • cpp/functions/viz/graph_viewport.mduses_functions añade graph_viewport_selection_cpp_viz.
  • projects/osint_graph/apps/graph_explorer/app.mduses_functions sincronizado con CMakeLists.txt: ahora declara las 23 funciones del registry que enlaza (antes 15). Añadidas: graph_viewport_selection, graph_labels_select, graph_types, graph_spatial_hash, button, icon_button, badge, empty_state.
  • projects/fn_monitoring/apps/registry_dashboard/app.mduses_functions sincronizado con CMakeLists.txt (21 deps, antes 9). Añadidas: badge, button, empty_state, icon_button, modal_dialog, page_header, process_runner, process_state_machine, select, text_input, toast, toolbar, tree_view. Removido: fps_overlay (vive en fn_framework, no se declara).

Decisions

  • ADR 0003-orphan-tu-as-separate-function-entry.md — cuando una funcion del registry necesita partir 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. El parent declara la nueva entrada en uses_functions. Razon: el indexer asume 1 .cpp = 1 .md; un file_path multi-archivo rompe la convencion y deja apps nuevas sin saber que TUs enlazar.

Added — sesion NER+RE para graph_explorer (tarde, 980 → 990 funciones)

18 funciones nuevas sobre el ecosistema NER+RE, en dos rondas de fn-constructor:

Ronda 1 — extraccion de relaciones (mREBEL/REBEL/MarianMT):

  • python/functions/datascience/parse_rebel_output.py (pure) — parser wire <triplet> REBEL/mREBEL.
  • python/functions/datascience/align_relations_to_entities.py (pure) — string-match aligner.
  • python/functions/datascience/mrebel_load_model.py (impure, CC BY-NC-SA 4.0 — NO comercial).
  • python/functions/datascience/mrebel_base_load_model.py (impure, misma licencia).
  • python/functions/datascience/rebel_load_model.py (impure, Apache 2.0, EN-only).
  • python/functions/datascience/marianmt_es_en_load_model.py (impure) — Helsinki-NLP/opus-mt-es-en.
  • python/functions/datascience/translate_es_to_en.py (impure) — wrapper traduccion frase a frase.
  • python/functions/datascience/extract_relations_mrebel.py (impure) — pipeline mREBEL frase-a-frase + alineamiento.
  • 21 tests pytest verdes.

Ronda 2 — pipeline GLiNER2 + OpenIE schema-less + composicion (tarde):

  • python/functions/core/clean_pdf_text.py (pure) — limpia artefactos PyPDF2.
  • python/functions/core/chunk_with_overlap.py (pure) — sliding window con avance forzado.
  • python/functions/core/merge_entity_aliases.py (pure) — coreferencia normalize+substring.
  • python/functions/core/filter_relations_by_entity_types.py (pure) — post-filter typed.
  • python/functions/core/aggregate_extraction_results.py (pure) — dedupe + Counter sobre N chunks.
  • python/functions/datascience/gliner2_load_model.py (impure, Apache 2.0) — fastino/gliner2-large-v1.
  • python/functions/datascience/extract_graph_gliner2.py (impure) — wrapper schema + threshold + include_confidence.
  • python/functions/datascience/spacy_es_load_model.py (impure) — es_core_news_md cacheado.
  • python/functions/datascience/extract_triples_spacy_es.py (impure) — OpenIE schema-less ES por reglas de dependencia (verbo del texto = predicado).
  • python/functions/pipelines/extract_graph_from_text.py (impure pipeline) — composicion E2E: chunk → extract_graph_gliner2 (×N) → aggregate → filter typed → merge aliases → grafo final.
  • 39 tests pytest verdes.

Added — analysis gliner_glirel_tuning

projects/osint_graph/analysis/gliner_glirel_tuning/ — investigacion empirica de modelos NER/RE. 9 notebooks ejecutados:

# Notebook Hallazgo clave
01 01_gliner_glirel_tuning.ipynb Calibracion de thresholds GLiNER+GLiREL
02 02_e2e_spanish_graph.ipynb E2E texto ES — descubrimiento del fail de GLiREL en castellano
03 03_mrebel_vs_glirel.ipynb mREBEL gana a GLiREL pero CC BY-NC-SA
04 04_gliner2_winner.ipynb GLiNER2 (Apache 2.0, NER+RE joint, 340M) elegido como motor principal
05 05_long_text_and_pdf.ipynb Pipeline PDF E2E sobre politica_proteccion_datos.pdf (BBVA, 89.882 chars)
06 06_improvements.ipynb Threshold 0.3 (vs default 0.5) → +187% relaciones; coref reduce 18% aislados
07 07_nuextract_vs_gliner2.ipynb NuExtract GPU 2.6× mas lento, calidad similar — descartado por defecto
08 08_improving_gliner2.ipynb snake_case verbal labels + post-filter typed = mejor combo
09 09_spacy_es_openie.ipynb spaCy ES dep-rules: schema-less, predicado = verbo del texto

Added — vault osint_nlp_models

projects/osint_graph/vaults/osint_nlp_models (symlink a ~/vaults/osint_nlp_models/):

  • models/ — fichas de gliner, glirel, mrebel, gliner2, candidates a probar.
  • decisions/ — 3 ADRs cortos del 2026-05-04 (mrebel-over-glirel mañana, gliner2-over-mrebel tarde, license-constraint).
  • benchmarks/corpus_v1.md + results_log.csv (15 filas de experimentos).
  • test_documents/politica_proteccion_datos.pdf (PDF de BBVA copiado para reproducibilidad).

Added — playground HTML

projects/osint_graph/analysis/gliner_glirel_tuning/playground/:

  • server.py — FastAPI con GLiNER2 cacheado, endpoints GET / (HTML) y POST /extract (texto → grafo).
  • index.html — UI: textarea, KPIs (nodos/aristas/tiempo), grafo Sigma.js, JSON exportable.
  • static/sigma.min.js + graphology.umd.min.js (servidos localmente para evitar bloqueo CDN por extensiones tipo MetaMask/SES).

Stack aplicado por el server:

  1. snake_case verbal labels (works_at, ceo_of, headquartered_in, agreement_with...)
  2. threshold 0.3 (configurable)
  3. chunking automatico > 1500 chars
  4. post-filter typed ((person, organization) validos por relacion)
  5. coreferencia normalize+substring
  6. layout server-side via networkx.spring_layout
  7. render Sigma.js (sin fisica → sin loops de ResizeObserver)

Added — issues

  • dev/issues/0050-jupyter-exec-collab-client-failure.md — bug jupyter_exec con cliente colaborativo + workaround documentado.
  • projects/osint_graph/apps/graph_explorer/issues/0041-split-confidence-thresholds.md — split confidence_threshold en entity_threshold + relation_threshold.
  • projects/osint_graph/apps/graph_explorer/issues/0042-gliner2-unified-extractor.md — sustituir GLiREL por GLiNER2 en extract_graph_hybrid. Reemplaza 0042-mrebel.
  • projects/osint_graph/apps/graph_explorer/issues/0042-mrebel-relation-extractor.md.superseded — version mREBEL del 0042 archivada al ganar GLiNER2.

Changed

  • cpp/CMakeLists.txt_GE_DIR y _DASH_DIR sobreescribibles via -D<...>=<path> para builds en worktrees (commit e72d6364). Habilita parallel-fix-issues sobre apps C++.
  • python/functions/datascience/glirel_load_model.py — workaround compat huggingface_hub 1.x: classmethod monkey-patch idempotente para inyectar proxies/resume_download que el HF nuevo dejo de pasar (commit 3b3378cf).
  • Sub-repo dataforge/graph_explorer master local: merges --no-ff de issue/0035e-polish-and-tests (commit f614a51) + issue/0013-paste-extract-panel (commit 2a49c2b). 125/125 tests pytest verdes. Sin push aun — pendiente confirmacion + validacion Windows.

Fixed (bugs encontrados + raiz + fix)

Bug Raiz Fix
chunk_with_overlap bucle infinito Frase mas larga que max_chars, no avanzaba i, OOM-killed por overlap acumulado Avance forzado: meter al menos UNA frase aunque exceda max_chars
NuExtract degenera en texto largo Sin repetition_penalty, decoder entra en bucle de tokens repetidos hasta agotar 2048 max_new_tokens repetition_penalty=1.15 + chunking obligatorio (179/179 chunks parsed OK tras fix)
NuExtract AutoProcessor.from_pretrained rota en transformers 5.x Sub-processor de video tira TypeError: argument of type 'NoneType' is not iterable (Qwen2-VL) Bypass: AutoTokenizer + AutoModelForImageTextToText directamente
Vis-network ResizeObserver loop spam (en SES/MetaMask) Vis-network usa physics simulation → ResizeObserver dispara warnings amplificados por SES Migrar a Sigma.js + layout server-side via networkx.spring_layout (sin fisica frontend)
jupyter_exec append HTTP 405 jupyter_nbmodel_client espera collab WebSocket Y.js, no soportado al 100% por jupyter-collaboration nuevo Documentado en issue 0050; workaround actual: build_notebook scripts con nbformat + nbconvert --execute
Kernel startup shadows pip packages 00_fn_registry.py añade cada subdir de python/functions/ a sys.path top-level → bigquery/datasets.py shadows HF datasets package needed by transformers Workaround per-notebook: sys.path = [p for p in sys.path if not p.startswith(_pf+'/')] + añadir solo el padre. Issue futuro pendiente.

Decisions — vault ADRs

Decision Razon
GLiNER2 (Apache 2.0) sustituye a GLiREL en extract_graph_hybrid 6/8 relaciones correctas vs 0/1 de GLiREL en es_corporate_short, 1.18s vs 22s de mREBEL, NER+RE en una pasada
mREBEL queda como fallback (no comercial) 4/5 correctas pero CC BY-NC-SA 4.0 + 25× mas lento
spaCy ES dep-rules para OpenIE schema-less Predicado = verbo del texto (querer, abrazar), 5ms/frase, sin alucinaciones
Threshold 0.3 (vs default 0.5) sweet spot +187% relaciones manteniendo precision; 0.2 mete +22% entidades dudosas
Coreferencia normalize+substring + post-filter typed = gratis y decisivos Coref 18% aislados; post-filter elimina Madrid president_of Persona
Translate ES→EN + triplet-extract EN NO vale la pena Pierdes verbos del texto (quererloves), +500ms-1s, +300MB MarianMT, riesgo nombres propios

2026-04-28

Added

  • cpp/functions/core/app_about (app_about_cpp_core) — ventana flotante About con about_window_set_info(project, version, description), about_window_menu_item("About...") y about_window_render(). Render automatico via fn::run_app (cableado en cpp/framework/app_base.cpp).
  • bash/functions/infra/ensure_repo_synced (ensure_repo_synced_bash_infra) — pipeline idempotente que compone gitea_create_repo + gitea_push_directory: crea repo Gitea si falta, inicializa .git local si falta, commitea cambios pendientes y pushea. Defaults: owner dataforge, branch master.
  • analysis.md para 6 analyses que estaban en disco pero sin indexar: agent_coding_eval, estudio_embeddings, estudio_mercados, ontology_graph, pruebas_jupyter, retrieving_graphs. Ahora ./fn index reporta 8 analyses (antes 2).
  • Repos dataforge/<name> creados en Gitea para apps y analyses que no estaban subidos: agents_and_robots, element_matrix_chat, deploy_server, shaders_lab, voice_guide, agent_coding_eval, ontology_graph, turismo_spain. Cada uno con .gitignore apropiado para excluir binarios, .venv/, node_modules/, .jupyter*, operations.db*.

Changed

  • cpp/functions/core/app_menubar: el item top-level Settings... pasa a ser un BeginMenu("Settings") con dos subitems: Settings... (ventana de app_settings) y About... (nuevo, ventana de app_about). Las apps que usan fn_ui::app_menubar(nullptr, 0, nullptr) heredan el cambio sin tocar nada.
  • projects/fn_monitoring/apps/registry_dashboard/main.cpp: cablea fn_ui::about_window_set_info("fn_registry Dashboard", "0.2.0", "...") antes de fn::run_app. Tabla Apps gana columna Git con valores remote (repo_url poblado), local (.git/ presente) o -.
  • data.h/data.cpp/data_http.cpp del dashboard: AppRow extendido con repo_url y dir_path.
  • 10 repos migrados de branch main a master para unificar convencion: apps/{docker_tui,fuzzygraph,metabase_registry,pipeline_launcher,rapid_dashboards,script_navegador}, analysis/{estudio_embeddings,estudio_mercados,pruebas_jupyter,retrieving_graphs}. Default branch en Gitea actualizado via API (PATCH /repos/{owner}/{repo} con {"default_branch":"master"}), branch main remota borrada.
  • git config --global init.defaultBranch master para que los proximos git init sean consistentes.
  • /full-git-push: descubre apps/analyses sin .git y ofrece inicializarlos con ensure_repo_synced automaticamente. Excluye subrepos/ para evitar duplicacion (mirrors upstream).
  • /full-git-pull: tras fn sync, segunda pasada que clona los dataforge/<name> registrados en apps/analysis que no existan localmente — soluciona el "no pude recuperar la app en el otro PC".
  • bash/functions/infra/ensure_repo_synced.sh: localiza dependencias via FN_REGISTRY_INFRA_DIR o FN_REGISTRY_ROOT, robusto a sourcing desde zsh/bash.

Fixed

  • projects/fn_monitoring/apps/sqlite_api/handlers.go|main.go|handlers_test.go + nuevos handlers_mutations.go y handlers_projects.go: cableados endpoints POST /add_app|add_analysis|add_vault|reindex y GET /projects para que el dashboard pueda crear artefactos y navegar projects desde la actions bar (estado pendiente de varios dias en uncommitted, ahora versionado en dataforge/sqlite_api).
  • Bug operativo en sqlite_api (Windows): SO_RCVTIMEO se pasaba como struct timeval cuando Windows espera DWORD ms → timeout efectivo de 5 ms. Ya documentado en app.md del dashboard.

2026-04-24

Added

  • 6 funciones bash/infra/systemd_local_* (install_unit, enable, start, restart, status, uninstall) para gestionar servicios systemd del sistema desde el registry (complementa las versiones remotas SSH ya existentes).
  • Pipeline install_systemd_service_bash_pipelines que compone las anteriores: genera unit file + install + enable + start + status.
  • Servicio systemd sqlite_api.service instalado y habilitado en aurgi-pc — arranque automático al iniciar WSL en 127.0.0.1:8484.
  • projects/fn_monitoring/launcher.sh — launcher del dashboard (arranca API si no está + lanza ventana + cleanup).
  • Regla .claude/rules/kiss.md — filosofía KISS para proyectos y apps.
  • Documentación ADR en docs/adr/ con plantilla y ADR 0001 (experimento GitButler).
  • Diario en docs/diary/ + slash command /entrada_diario para añadir entradas.
  • CHANGELOG.md (este archivo).
  • Submódulo cpp/vendor/glfw re-registrado con path limpio (antes heredado con path absoluto /home/lucas/...).
  • aurgi-pc registrado en el server centralizado (registry.organic-machine.com) con 18 pc_locations.

Changed

  • registry.db ahora está gitignorada. Es regenerable con fn index + completable con fn sync. Evita conflictos entre ramas y PCs.
  • sqlite_api ahora se distribuye como binario compilado (projects/fn_monitoring/apps/sqlite_api/sqlite_api) en lugar de go run al vuelo.

Fixed

  • http_client.cpp del dashboard: añadido #include <cstdint> requerido por mingw-w64 para cross-compile Windows (g++ Linux lo incluía transitivamente).
  • registry_dashboard.exe (Windows) ya no abre ventana de consola al lanzarse — enlazado como GUI app (WIN32_EXECUTABLE TRUE / -mwindows).

Added (design system C++)

  • cpp/functions/core/tokens — design tokens para dashboards ImGui (colors, spacing, radius, font_size) inspirados en @fn_library (Mantine v9). Paleta dark + indigo primary. apply_dark_theme() aplica los tokens al ImGuiStyle global.
  • cpp/functions/core/badge — etiqueta inline con 6 variantes (Default/Success/Warning/Error/Info/Outline). Equivalente a <Badge> de @fn_library.
  • cpp/functions/core/empty_state — placeholder centrado para tablas/listas vacías.
  • cpp/functions/core/page_header — header de página con título/subtítulo + hueco para acciones + separator.
  • registry_dashboard migrado a los nuevos componentes: page_header_begin/end en el header, empty_state en las 4 tablas cuando están vacías, apply_dark_theme() al primer frame. Sin hardcode de colores disperso.
  • systemd_local_{enable,start,restart}: stdout de systemctl redirigido a stderr para no contaminar el JSON capturado por el pipeline.
  • .gitmodules: entry fantasma cpp/vendor/glfw con path absoluto /home/lucas/... que bloqueaba git submodule status y el cross-compile Windows.

Removed

  • Integración de GitButler de Claude Code — binario ~/.local/bin/but, plugin gitbutler-tools, skill .claude/skills/gitbutler/, hooks en settings.json, ramas gitbutler/* + e-branch-*, estado interno .git/gitbutler/. Ver ADR 0001 para motivos.