close issue 0081: tables promoted to registry + fn doctor cpp-apps BeginTable check

- docs/TQL.md: añadidas secciones joins, views, main_source, 24 viz tokens completos
  (extraidos de tql_helpers.cpp), color_rules, fn.* builtins completos (20 funciones),
  funciones bloqueadas del sandbox, tabla de estado de implementacion actualizada.
  Nota al pie referencia los 129 checks roundtrip (41 emit + 88 apply).

- functions/infra/audit_cpp_apps.go: añadida AuditCppTableMigration() que escanea
  .cpp de cada app imgui buscando ImGui::BeginTable; status CANDIDATE/MIXED/clean
  segun si usa data_table_cpp_viz en uses_functions.

- cmd/fn/doctor.go: fn doctor cpp-apps ahora incluye seccion BeginTable migration
  con tabwriter CANDIDATE/MIXED; --json produce {conformance, table_migration}.
  doctorAll incluye cpp_table_migration en el mapa JSON.

- .claude/rules/fn_doctor.md: tabla de subcomandos y acciones complementarias
  actualizadas con el nuevo check.

- dev/issues/0081 movido a completed/ con status done y notas de deuda documentadas.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-15 14:49:56 +02:00
parent fad7b2fccc
commit acecbbc821
5 changed files with 470 additions and 26 deletions
+117
View File
@@ -157,3 +157,120 @@ func cppHasAutoDockspaceFalse(src string) bool {
return strings.Contains(src, "auto_dockspace = false") ||
strings.Contains(src, "auto_dockspace=false")
}
// CppTableMigrationAudit holds the BeginTable migration status for a single C++ app.
type CppTableMigrationAudit struct {
AppID string `json:"app_id"`
DirPath string `json:"dir_path"`
BeginTableCount int `json:"begin_table_count"`
UsesDataTableViz bool `json:"uses_data_table_viz"`
Status string `json:"status"` // "clean", "candidate", "mixed"
Message string `json:"message"`
}
// AuditCppTableMigration scans C++ apps (imgui framework) for inline
// ImGui::BeginTable calls and checks whether the app already declares
// data_table_cpp_viz in its uses_functions.
//
// Status values:
// - "clean" — no ImGui::BeginTable found (fully migrated or never had tables)
// - "mixed" — has ImGui::BeginTable AND declares data_table_cpp_viz
// (partial migration OK, wave N in progress)
// - "candidate" — has ImGui::BeginTable but does NOT declare data_table_cpp_viz
// (migration not started; consider data_table_cpp_viz, issue 0081)
func AuditCppTableMigration(registryRoot string) ([]CppTableMigrationAudit, error) {
dbPath := filepath.Join(registryRoot, "registry.db")
dsn := fmt.Sprintf("file:%s?mode=ro&_foreign_keys=on", dbPath)
db, err := sql.Open("sqlite3", dsn)
if err != nil {
return nil, fmt.Errorf("audit_cpp_table_migration: open db: %w", err)
}
defer db.Close()
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("audit_cpp_table_migration: ping db: %w", err)
}
rows, err := db.Query(`SELECT id, dir_path, COALESCE(framework,''), COALESCE(uses_functions,'') FROM apps WHERE lang = 'cpp' ORDER BY id`)
if err != nil {
return nil, fmt.Errorf("audit_cpp_table_migration: query apps: %w", err)
}
defer rows.Close()
var results []CppTableMigrationAudit
for rows.Next() {
var id, dir, framework, usesFunctions string
if err := rows.Scan(&id, &dir, &framework, &usesFunctions); err != nil {
continue
}
if framework != "imgui" {
continue
}
absDir := dir
if !filepath.IsAbs(absDir) {
absDir = filepath.Join(registryRoot, dir)
}
if _, err := os.Stat(absDir); os.IsNotExist(err) {
continue // directory_missing already reported by AuditCppApps
}
// Count ImGui::BeginTable occurrences across all .cpp files (excluding tests/).
count := 0
err := filepath.WalkDir(absDir, func(path string, d os.DirEntry, walkErr error) error {
if walkErr != nil {
return nil
}
// Skip test directories.
if d.IsDir() && (d.Name() == "tests" || d.Name() == "test") {
return filepath.SkipDir
}
if d.IsDir() {
return nil
}
if !strings.HasSuffix(d.Name(), ".cpp") {
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
}
src := string(data)
for start := 0; ; {
idx := strings.Index(src[start:], "ImGui::BeginTable(")
if idx < 0 {
break
}
count++
start += idx + len("ImGui::BeginTable(")
}
return nil
})
if err != nil {
continue
}
usesViz := strings.Contains(usesFunctions, "data_table_cpp_viz")
audit := CppTableMigrationAudit{
AppID: id,
DirPath: dir,
BeginTableCount: count,
UsesDataTableViz: usesViz,
}
switch {
case count == 0:
audit.Status = "clean"
audit.Message = ""
case usesViz:
audit.Status = "mixed"
audit.Message = fmt.Sprintf("%d ImGui::BeginTable inline (partial migration OK — data_table_cpp_viz already declared)", count)
default:
audit.Status = "candidate"
audit.Message = fmt.Sprintf("candidate to migrate: %d ImGui::BeginTable inline detected, consider data_table_cpp_viz (issue 0081)", count)
}
results = append(results, audit)
}
return results, nil
}