Change 3 of issue 0133 — rewire compute_visible_rows, filter eval, and sort comparators to read from the SnapshotCache when available. Hot paths rewired: - compute_visible_rows (overload with snap): filter eval uses compare_snap (fast i64/f64 numeric compare for Int/Float cols; id-compare for low-cardinality string Eq/Neq; raw cells fallback for Contains/StartsWith/EndsWith). - Sort comparators: direct i64/f64 array compare for Int/Float cols (goto sort_done skips string fallback); string sort uses uint32_t id compare with pool lookup only on mismatch. - Stage>0 filter/sort: same snapshot overload. Materialization paths (build_so, s0_backing, mat_backing, config popup) kept on raw cells — they copy into std::string anyway, no benefit from snapshot and snprintf-per-cell was 2M extra calls per frame. Bug fixes (required for correctness): 1. StringPool::intern() realloc safety: force reserve before emplace_back so string_view keys in the map never go dangling. 2. SnapshotCache::pool_size_built sentinel: detects when a new State is created with an empty pool but same cells pointer (begin_scenario pattern). Prevents str_ids from indexing into an empty pool (SIGSEGV). 3. Cardinality cap (2048 uniques / 25% sample): high-cardinality string cols (timestamps-as-strings, UUIDs, names) skip interning — str_ids stays empty and compare_snap falls back to raw cells. Prevents 30MB+ pool bloat that hurt cache for filter/sort on other cols. Bench delta vs baseline (100k rows, LIBGL_ALWAYS_SOFTWARE=1): linear_scroll: 16.0 -> 15.5 fps p50 (-3%, baseline already FAIL) filter_like: 59.7 -> 56.0 fps p50 (-6%, still PASS at 56fps) sort_numeric: 3.9 -> 9.0 fps p50 (+131%, snapshot i64 sort) color_rule: 15.2 -> 14.8 fps p50 (-3%, baseline already FAIL) Build: green for all 10 available Linux consumers (text_editor_smoke linker failure is preexisting, not caused by this change). API public intact. TableEvent.row indexing TableInput preserved. Pointer-identity invalidation preserved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Modulos C++ del registry
Bundles versionados de funciones del registry expuestos como static libs cmake. Apps opt-in via app.md::uses_modules + target_link_libraries(... fn_module_<X>).
Catalogo
| Modulo | Version | Static lib | Header | Entry | Linkage | Descripcion | Contrato |
|---|---|---|---|---|---|---|---|
| framework_cpp | 1.1.0 | fn_framework |
framework/app_base.h |
fn::run_app(cfg, render) |
transitivo via add_imgui_app |
Shell ImGui (GLFW+OpenGL+ImGui+ImPlot+themas+layouts+logger) | framework_cpp |
| data_table_cpp | 2.1.0 | fn_module_data_table |
data_table/data_table.h |
data_table::render(id, tables, state, events_out, show_chrome) |
explicito | Tabla completa TQL + 9 renderers declarativos + viz + drill + AI + button events | data_table_cpp |
Diferencia members vs uses_functions (post 0107d)
Cada module.md declara DOS listas:
members: funciones del registry que el modulo POSEE. Viven encpp/functions/<dominio>/y NO se usan fuera del modulo. Apps consumidoras del modulo NO listan estos miembros en suuses_functions(cobertura transitiva).uses_functions: funciones del registry que el modulo CONSUME pero NO posee. Utiles fuera del modulo. Si una app necesita estas STANDALONE, las declara en su propiouses_functionsdirectamente (no es duplicacion — es uso independiente).
Ejemplo data_table_cpp v2.1.0:
members: las 7 sub-funcionesdata_table_*_cpp_viz(renderizan dentro del modulo).uses_functions:lua_engine,llm_anthropic,join_tables,auto_detect_type,tql_*,compute_*,viz_render(consumidas por el modulo pero utiles solas).
Como anadir un modulo
-
mkdir modules/<name>/con:module.md(frontmatter: name, version, description, members, uses_functions, dir_path).CMakeLists.txtdefiniendoadd_library(fn_module_<name> STATIC ...).<name>.cpp+<name>.h(entry function).<name>_internal.hsi tiene >1 archivo + UiState compartido.
-
Anadir
add_subdirectory(${CMAKE_SOURCE_DIR}/../modules/<name> ${CMAKE_BINARY_DIR}/modules/<name>)encpp/CMakeLists.txt. -
Anadir fila en este catalogo + seccion en
docs/MODULES_API.mdsiguiendo el template. -
fn indexregistra el modulo enregistry.db::modules. -
Cada bump de version:
/version modules/<name> <major|minor|patch> "<reason>". Editamodule.md::version+## Capability growth log.
Auditoria
fn doctor modules(0107a): detecta driftuses_modulesvsuses_functionsen apps. Hoy: 0 drift en 8 apps consumidoras dedata_table_cpppost-0107b.audit_data_table_usage_go_infra(capability del registry): audita patrones de uso del modulodata_tableen apps. Detectainline_begintable,state_not_persistent,no_child_host,no_event_sink,cmake_missing_link. Output endev/data_table_integration_audit.md.
Ciclo de vida + version policy
Ver docs/MODULES_API.md::Ciclo de vida de un modulo y .claude/rules/cpp_apps.md.
Semver estricto:
- Major = breaking ABI/API publica del modulo (entry function, State struct expuesto, eliminacion de members).
- Minor = additive backward-compatible (nuevo renderer, nuevo evento, refactor interno sin cambio de API).
- Patch = bugfix sin cambio de API.
Slash command para bumpear: /version modules/<name> <bump-type> "<reason>".
Modulos en roadmap (post 0107)
chat_ia_cpp— sera el siguiente modulo. Bloqueado hasta cierre completo de 0107 (estandarizacion modulos). Issue 0109 cuando 0107 cierre.- Otros candidatos detectados por uso repetido en apps: TBD (auditar con
audit_data_table_usagepattern para otros bundles).