Files
fn_registry/docs/diary/2026-05-16.md
T

13 KiB

2026-05-16

02:00 — Framework C++ anti-jitter v2 + floating panel survival + Alt drag/resize + bulk redeploy

Extensiones al anti-jitter del framework C++ (cpp/framework/app_base.cpp + .h):

  • Multi-HWND subclass. g_subclassed ahora unordered_map<HWND, WNDPROC>. Scan per-frame en pio.Viewports instala subclass en cada HWND nuevo (cubre main + cada viewport flotante). prune_dead_subclassed() con IsWindow limpia stale. uninstall_sizemove_subclass_all() al exit restaura cada HWND. Fix del temblor en paneles arrastrados fuera del main.
  • Iconified main + flotantes vivos. El legacy glfwWaitEvents+continue paraba todo el frame loop. Con multi-viewport activo eso congelaba los flotantes. Ahora detecta secondary viewports y, si existen, fall-through al frame normal (main GL clear en HWND minimizado es harmless, contexts GL secundarios siguen pintando).
  • Alt + RMB resize anywhere. WndProc detecta WM_RBUTTONDOWN + GetAsyncKeyState(VK_MENU) & 0x8000, calcula direccion por cuadrante del cursor (WMSZ_TOPLEFT/TOPRIGHT/BOTTOMLEFT/BOTTOMRIGHT relativo al centro del client rect), ReleaseCapture() + PostMessage(WM_SYSCOMMAND, SC_SIZE|dir). Modal nativo, gate sizemove existente pausa render automaticamente.
  • Alt + LMB move anywhere. Misma estructura para WM_LBUTTONDOWN. Posta WM_SYSCOMMAND, SC_MOVE | HTCAPTION. Modal MOVE nativo.
  • io.ConfigWindowsMoveFromTitleBarOnly = true en fn::run_app. Floating panels (OS window borderless + UNA ventana ImGui rellenandolo) ahora respetan "solo header arrastra". Fix del drag-anywhere-sin-alt en flotantes.
  • 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. En test mode los handlers de Alt cuentan pero NO postean SC_SIZE/SC_MOVE.

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

Pipeline nuevo: redeploy_all_cpp_apps_bash_pipelines (bash/functions/pipelines/redeploy_all_cpp_apps.sh + .md). Cross-compila TODO el arbol cpp/ en un solo cmake pass + redeploy de cada .exe al Desktop. Filtro opcional por substring. Tolerante a fallos (build best-effort, summary OK/SKIPPED/FAILED). Composicion: build_cpp_windows_bash_infra + loop taskkill.exe + deploy_cpp_exe_to_windows_bash_infra. Primera corrida: 12 OK / 1 SKIP / 0 FAILED.

Fix resolve_cpp_app_dir_bash_infra v1.1.0: ahora busca apps en apps/<X>/ (canonical issue 0096), luego cpp/apps/<X>/ (legacy), luego projects/*/apps/<X>/. Antes solo veia los dos ultimos → ./fn run compile_cpp_app dag_engine_ui fallaba. Deduccion desde CWD tambien cubre los tres layouts.

Pitfalls / gotchas registrados

  • ImGui_ImplGlfw subclassea el HWND DESPUES que nuestro framework. Captura nuestro WndProc como bd->PrevWndProc y chainea via CallWindowProc → todos los mensajes nos llegan en orden correcto. NO re-subclassear despues de ImGui init (genera recursion infinita por cycle).
  • keybd_event(VK_MENU) no es fiable para drivear GetAsyncKeyState desde tests headless cross-compilados (sesion de input no foreground). Usar set_force_alt_for_test(true) + SendMessageW sincrono mismo-hilo. PostMessage(WM_RBUTTONDOWN) sintetizado tambien es dropeado por el kernel input filter.
  • Pre-existing build break en cpp/tests/test_llm_anthropic.cpp + cpp/tests/test_graph_icons.cpp por setenv() no disponible en mingw-w64. NO bloquea redeploy_all_cpp_apps (build best-effort). Candidato a guard #ifdef _WIN32 + _putenv_s o skip cross-compile.

Lo siguiente que pega

  • Resolver el build break de test_llm_anthropic.cpp + test_graph_icons.cpp con _putenv_s bajo #ifdef _WIN32. Quitar el SKIP del log de redeploy_all_cpp_apps.
  • Considerar regla nueva sobre ImGui io flags criticos (ConfigWindowsMoveFromTitleBarOnly, ConfigViewportsNoAutoMerge, ConfigDragClickToInputText, etc.) que cambian comportamiento de viewports. Sub-seccion en cpp_apps.md o archivo separado en .claude/rules/imgui_io_flags.md.
  • Documentar en cpp/PATTERNS.md que add_imgui_app ya embebe el icono appicon.ico si esta en el <app_dir> (verificado en sesion; el usuario lo mantuvo entre redeploys).

Archivos tocados

  • cpp/framework/app_base.cpp (multi-HWND, iconified-gate, Alt+RMB, Alt+LMB, ConfigWindowsMoveFromTitleBarOnly, fn::internal::*)
  • cpp/framework/app_base.h (declaracion de fn::internal::*)
  • apps/altsnap_jitter_test/main.cpp (phases 3-6)
  • apps/altsnap_jitter_test/app.md (6 phases doc)
  • bash/functions/pipelines/redeploy_all_cpp_apps.sh (nuevo)
  • bash/functions/pipelines/redeploy_all_cpp_apps.md (nuevo, growth log v1.0.0)
  • bash/functions/infra/resolve_cpp_app_dir.sh (v1.1.0)
  • bash/functions/infra/resolve_cpp_app_dir.md (v1.1.0 + growth log)
  • .claude/rules/cpp_apps.md (seccion 7.1 ampliada con v2)
  • docs/capabilities/cpp-windows.md (tabla + seccion bulk redeploy + layouts)
  • CHANGELOG.md (entrada 2026-05-16)

01:05 — Iconos .ico para apps C++ + funcion del registry

Las 11 apps C++ desplegadas a Windows no tenian icono → imposible distinguirlas en Desktop/taskbar (todas con el icono generico de exe).

Pipeline build-time end-to-end

  1. Fuente de glyphs: clonado phosphor-icons/core (MIT) en sources/phosphor-core/ con git clone --depth=1. 1512 SVGs en 6 weights. Registrado en sources/sources.yaml.

  2. Mapping inicial en dev/gen_app_icons.py (script reproducible, NO es del registry — vive en dev/). Tabla APPS = [(app_id, dir, phosphor_icon, accent_hex), ...] con un Tailwind color 500-700 por app:

    • chart_demo → chart-bar / sky-500
    • dag_engine_ui → tree-structure / violet-600
    • data_factory → factory / orange-500
    • engine_smoke (no aplicado: usa raw add_executable, no add_imgui_app)
    • graph_explorer → graph / cyan-600
    • navegator_dashboard → compass / blue-600
    • odr_console → terminal-window / zinc-600
    • primitives_gallery → shapes / pink-600
    • registry_dashboard → gauge / emerald-600
    • runtime_test (no aplicado: raw add_executable)
    • shaders_lab → palette / orange-600
    • text_editor_smoke → note-pencil / teal-600
    • altsnap_jitter_test → arrows-clockwise / red-600
  3. Funcion del registry: generate_app_icon_py_infra (python/functions/infra/generate_app_icon.py). Lo escribe fn-constructor. Signature generate_app_icon(phosphor_icon_name, accent_hex, out_ico_path, *, weight='fill', sizes=None, phosphor_root=None) -> str. Tags cpp-windows, icon, phosphor. Deps cairosvg + Pillow ya en python/.venv (uv pip install cairosvg en python/). Validado con ./fn show + smoke test /tmp/test_icon2.ico.

  4. Wiring CMake (cpp/CMakeLists.txt):

    • Linea 1-5: project(... LANGUAGES C CXX RC) solo en WIN32. Linux ignora.
    • Macro add_imgui_app (linea ~241): si WIN32 AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/appicon.ico, genera ${target}_appicon.rc en build dir con IDI_ICON1 ICON "<full_path>" y lo anade a add_executable. x86_64-w64-mingw32-windres (ya en toolchain) lo compila a .res y se enlaza al .exe como seccion .rsrc.
  5. Rebuild + redeploy: cmake --build cpp/build/windows -- -j$(nproc) + deploy_cpp_exe_to_windows para las 11. Verificacion: x86_64-w64-mingw32-objdump -h <exe> | grep rsrc muestra la seccion en todas.

Decision: build-time vs post-build

Existia set_exe_icon_go_infra (Go puro, embebe .ico post-build modificando PE). Descartado porque:

  • Falla si el .exe ya tiene seccion .rsrc (limita robustez).
  • Anade paso extra al pipeline redeploy.
  • Build-time es atomico: el .exe recien linkeado YA tiene el icono.

Gotchas

  • engine_smoke y runtime_test usan add_executable raw, no add_imgui_app — no reciben icono automatico. Son smoke tests, no apps user-facing. Skip aceptable.
  • shaders_lab vive en apps/shaders_lab/, no en cpp/apps/shaders_lab/ (confusion inicial del mapping; corregido).
  • Pillow save(format='ICO') con append_images: si pasas la imagen 16x16 como base, el .ico final solo tiene 16x16. Hay que pasar la imagen MAS GRANDE (256x256) como base + lista de variants per-size. Variants per-size dan crispness en 16/24 mejor que dejar Pillow downscalear.
  • Cache iconos Windows (iconcache.db): tras desplegar nuevo .ico, Explorer puede seguir mostrando el viejo. Refresh: ie4uinit.exe -show o restart explorer.

Para anadir icono a una app nueva

# 1. Elegir nombre Phosphor desde sources/phosphor-core/assets/fill/
ls sources/phosphor-core/assets/fill/ | grep <keyword>

# 2. Generar el .ico
./fn run generate_app_icon "<phosphor-name>" "#<accent_hex>" "<app_dir>/appicon.ico"

# 3. Rebuild + redeploy
./fn run redeploy_cpp_app_windows <app_name> <app_dir> --build

Archivos tocados

  • sources/phosphor-core/ (nuevo, clonado)
  • sources/sources.yaml (entry phosphor-icons/core)
  • dev/gen_app_icons.py (nuevo, script reproducible con mapping inicial)
  • python/functions/infra/generate_app_icon.py (nueva funcion registro)
  • python/functions/infra/generate_app_icon.md (idem)
  • python/functions/infra/__init__.py (export)
  • cpp/CMakeLists.txt (project LANGUAGES + add_imgui_app icon wiring)
  • 11 x <app_dir>/appicon.ico (nuevos, multi-res)
  • .claude/rules/cpp_apps.md (§11 Icono Windows)
  • CHANGELOG.md (entrada 2026-05-16 Added: iconos .ico)
  • 11 x .exe rebuildeadas + redesplegadas a /mnt/c/Users/lucas/Desktop/apps/

Lo siguiente que pega

  • Anadir icono tambien a engine_smoke y runtime_test si se promueven a apps user-facing (hoy son smoke tests).
  • Considerar fn doctor cpp-apps check: app C++ sin appicon.ico → warning.
  • Si aparecen iconos antiguos en Explorer tras redeploy, anadir ie4uinit.exe -show al final de deploy_cpp_exe_to_windows.

20:54 — dag_engine — fix function-not-found nocturno + panel Logs en RunDetail

  • Hecho: diagnostico de 3 fallos nocturnos (fn_backup x2 2026-05-15/16, daily-registry-audit 2026-05-16) que reportaban error: function "<id>" not found (tried as ID and name) aunque audit_capability_groups_go_infra, backup_all_bash_pipelines y cdp_extract_recipe_py_pipelines existen en registry.db raiz.
  • Hecho: raiz identificada en cmd/fn/ops.go:1597-1628 tryOpenRegistryDB — sin FN_REGISTRY_ROOT el resolver cae al walk-up go.mod y devuelve apps/dag_engine/ donde habia una copia stale apps/dag_engine/registry.db (262 KB, May 15) que violaba .claude/rules/db_locations.md (registry.db SOLO en raiz).
  • Hecho: stale db borrada.
  • Hecho: ~/.config/systemd/user/dag_engine.service ampliado con Environment=FN_REGISTRY_ROOT=/home/lucas/fn_registry, FN_BIN, PATH=/usr/local/go/bin:... (sin PATH go vet fallaba con exec: "go": executable file not found), HOME. daemon-reload + restart.
  • Hecho: apps/dag_engine/executor.go belt-and-suspenders — steps function: exportan FN_REGISTRY_ROOT en env del spawn y default dir = fnRegistryRoot si step.Dir/dag.WorkingDir vacios; rebuild CGO_ENABLED=1 go build -tags fts5 -o dag_engine ..
  • Hecho: smoke test POST /api/dags/daily-registry-audit/run -> step audit_capabilities SUCCESS 387 ms (era el step que fallaba con not-found). audit_unused SUCCESS, audit_artefacts falla con exit 1 (bug aparte) y fn_backup run_backup_all exit 4 sin respetar continue_on.exit_code (bug aparte).
  • Hecho: panel "Logs" anadido a apps/dag_engine/frontend/src/pages/RunDetail.tsx<Paper> final con <Code block> (max-h 480 scrollable) + CopyButton Mantine (icono toggle copy/check teal 1.5s). Helper buildLogText(run, steps) compone texto plano con metadata del run (dag/path/status/trigger/started/finished/duration/error) + por-step ([status] name exit=N Nms, stdout/stderr indentado 4 espacios). Type-checkea limpio.
  • Hecho: documentadas BBDDs canonicas — dag_engine.db en apps/dag_engine/, data_factory.db en apps/data_factory/ (tablas nodes/connections/runs/databases), navegator_dashboard NO tiene BD propia (solo layouts.db del framework via fn::local_path).
  • Hecho: append en apps/dag_engine/app.md (seccion fechada + "Lo siguiente que pega"), apps/dag_engine/README.md (Function steps: aviso sobre FN_REGISTRY_ROOT y PATH en systemd), CHANGELOG.md (Added panel Logs + Fixed function-not-found bug).
  • Pendiente: investigar exit 1 real de audit_artefacts en daily-registry-audit (probable artefacto huerfano o git drift).
  • Pendiente: bug en executor — continue_on.exit_code: [4] no se respeta; solo se mira step.ContinueOn.Failure (bool). Parsear ContinueOn.ExitCode []int y comparar con result.ExitCode antes de marcar runFailed=true.
  • Pendiente: frontend pnpm build roto por API drift de Mantine (<Collapse in={opened}> en StepTimeline.tsx:49) y CSS type import en main.tsx:1. Bloquea ver el panel Logs en vivo; type-check ya pasa.