## fn doctor: diagnostico del registry y artefactos

`fn doctor` es el entrypoint unico para auditar la salud del sistema de forma read-only. Compone funciones del registry (`functions/infra/`) y formatea su salida. No modifica nada.

### Cuando usar

- Despues de un deploy: confirmar que servicios siguen vivos y artefactos intactos.
- Despues de `git pull` o `fn sync`: detectar drift entre BD y disco.
- Antes de `fn index` masivo: confirmar que apps Go/Py siguen declarando bien sus deps.
- Periodicamente (cron): listar funciones del registry sin consumidores para limpiar.
- Como gate antes de crear proposals: si `fn doctor` esta verde, las metricas del bucle reactivo son fiables.

### Comandos

```bash
fn doctor                  # Corre TODOS los checks (artefacts + services + sync + uses-functions + unused + cpp-apps)
fn doctor artefacts        # Solo artefactos: git/venv/app.md/upstream
fn doctor services         # Solo apps con tag 'service' + systemctl + puerto
fn doctor sync             # Solo drift pc_locations BD vs disco local
fn doctor uses-functions   # Solo audit imports reales vs uses_functions
fn doctor unused           # Solo funciones huerfanas del registry
fn doctor cpp-apps         # Conformidad C++ con cpp/PATTERNS.md (cfg.about/log, no app_menubar manual, no DockSpace duplicado)
                           # + check BeginTable inline: CANDIDATE (no migrado) / MIXED (parcial) / silencio (limpio)

fn doctor --json           # Salida JSON (cualquier subcomando) — para agentes/scripts
```

`fn doctor cpp-apps` produce dos secciones:
1. Conformance (cfg.about/log, fn::run_app, menubar, DockSpace) — una fila por app imgui.
2. BeginTable migration (issue 0081) — solo apps con `ImGui::BeginTable` inline:
   - `CANDIDATE`: N tablas inline sin `data_table_cpp_viz` en uses_functions. Considerar migracion.
   - `MIXED`: N tablas inline con `data_table_cpp_viz` ya declarado. Migracion parcial OK.
   - silencio: 0 BeginTable inline (limpio o completamente migrado).

### Mapeo subcomando → funcion del registry

| Subcomando | Funcion |
|---|---|
| `artefacts` | `artefact_doctor_go_infra` |
| `services` | `services_status_go_infra` |
| `sync` | `pc_locations_drift_go_infra` |
| `uses-functions` | `audit_uses_functions_go_infra` |
| `unused` | `find_unused_functions_go_infra` |
| `cpp-apps` (conformance) | `audit_cpp_apps_go_infra` |
| `cpp-apps` (table migration) | `audit_cpp_table_migration_go_infra` (inline en `audit_cpp_apps.go`) |

Cada subcomando es un wrapper fino. Toda la logica vive en la funcion. Si quieres usar la salida en otro programa Go, importa la funcion directamente.

### Salida

Texto humano por defecto (tabwriter). `--json` produce array/objeto serializable para `jq`, agentes o pipes.

### Idempotente y seguro

- Read-only: ningun subcomando escribe, mata procesos ni cambia estado.
- `services` abre conexiones TCP a `127.0.0.1:<port>` con timeout 500ms — no genera trafico saliente.
- `artefacts` ejecuta `git rev-parse @{u}` con timeout 3s por artefacto.

### Acciones complementarias (NO son `fn doctor`)

`fn doctor` solo diagnostica. Las acciones derivadas son verbos separados:

| Si `fn doctor` reporta... | Accion |
|---|---|
| `directory_missing` | Marcar `pc_locations.status='missing'` o re-clonar via `/full-git-pull` |
| `git_not_initialized` | `gitea_create_repo_bash_infra` + `ensure_repo_synced_bash_infra` |
| `venv_broken_path` | `cd <analysis_dir> && rm -rf .venv && uv sync` |
| `service active=inactive` | `systemctl --user start <unit>` o investigar logs |
| `port not listening` | `port_kill_bash_infra <port>` (si zombie) y relanzar |
| `missing_in_app_md` | Editar `app.md` y añadir el ID a `uses_functions` |
| `unused` (funcion huerfana) | Decidir: usar, deprecar (tag), o borrar |
| `manual_app_menubar_call` | Borrar `fn_ui::app_menubar(...)` del render — el framework ya lo dibuja |
| `manual_DockSpaceOverViewport_*` | Borrar la llamada o setear `cfg.auto_dockspace = false` si la app gestiona docking propio |
| `missing_cfg_about` / `missing_cfg_log` | Anadir `cfg.about = {...}` / `cfg.log = {"<name>.log", 1}` antes de `fn::run_app` |
| `app.md_missing_*` | Regenerar via plantilla del scaffolder (`/new-cpp-app`) o anadir campos a mano |
| cpp-apps BeginTable `CANDIDATE` | App tiene N `ImGui::BeginTable` sin migrar. Abrir rama TBD, reemplazar tablas por `data_table::render()` via `fn_table_viz`, añadir `data_table_cpp_viz` a `uses_functions` en `app.md` |
| cpp-apps BeginTable `MIXED` | Migracion parcial en curso. Continuar wave por wave hasta que no queden BeginTable inline |
| Backup viejo | `backup_all_bash_pipelines ~/backups/fn_registry` |

### Para agentes

Patron recomendado tras una accion no trivial (deploy, sync, mass edit):

```bash
fn doctor --json > /tmp/doctor.json
# Agente parsea JSON, decide si crear proposals o avisar al humano
```

Si el agente quiere actuar sobre los hallazgos, abre proposals con `fn proposal add` referenciando los IDs afectados — NO toca artefactos directamente sin aprobacion humana.
