Repair
Aplicar la reparación que {@see AppDoctor} recomendó — sin necesitar que la app arranque. ── POR QUÉ VIVE JUNTO AL DOCTOR ──────────────────────────────────────────────────────────────── Porque son la misma conversación. El doctor dice qué falta y de dónde sacarlo; esto lo trae. Vivían en paquetes distintos —el diagnóstico aquí, la reparación en `milpa/framework`— y eso dejaba la reparación fuera del alcance de toda app que no se hubiera creado desde esa plantilla: **la que más la necesitaba, un host viejo con el grafo abierto, era justo la que no la tenía.** ── Y POR QUÉ NO PUEDE SER UNA OPERACIÓN ──────────────────────────────────────────────────────── Una operación se despacha con el kernel arriba, y esto existe para el caso en que el kernel NO levanta. Medido el 2026-08-04 en un host con una capacidad requerida sin proveedor: coa coa:doctor → [Initialization Error] MILPA_CAPABILITY_MISSING coa repair → [Initialization Error] MILPA_CAPABILITY_MISSING coa <cualquiera> → [Initialization Error] MILPA_CAPABILITY_MISSING Es el argumento que el doctor ya había ganado —«la herramienta que explica por qué algo no arranca no puede necesitar que arranque»— un paso más adelante: la que lo arregla, tampoco. ── LO QUE DECIDE, Y ES LO QUE LA DEFINE ──────────────────────────────────────────────────────── **La puerta sólo abre para lo que el diagnóstico de HOY pidió**, recalculado en cada llamada: una acción de hace diez minutos puede describir un problema que ya no existe, y aplicarla sería reparar una foto. Sin esa restricción sería un instalador general con nombre de reparación — la puerta ancha que después nadie se atreve a cerrar. El paquete NO sale de un catálogo escrito a mano: sale del diagnóstico, que lo derivó del grafo. Un catálogo aquí sería una tercera lista que puede envejecer aparte de las otras dos. ── LAS DOS COSAS QUE NO SE DAN POR HECHAS ────────────────────────────────────────────────────── Que composer salga en 0 no es que el paquete haya llegado: se relee `installed.json`, que es donde el hecho existe. Y que haya llegado no es que la app siga en pie: se corre el diagnóstico **en un proceso nuevo**, porque el autoloader de éste se armó antes de que composer escribiera nada y contestaría sobre el mundo de hace un minuto con cara de actual.
Repair::apply()
public static function apply(string $raiz, string $paquete, bool $seco = false, ?array $recomendados = null, ?callable $corredor = null): arrayAplica una de las reparaciones que el diagnóstico recomienda, y verifica que la app siga en pie.
Parameters
| Name | Type | Description |
|---|---|---|
| $raiz | string | |
| $paquete | string | |
| $seco | bool | |
| $recomendados | (null | list<string>) | costura de prueba |
| $corredor | (null | callable(string): array{0: int, 1: list<string>}) | costura de prueba: lo que una prueba no puede arreglar, lo inyecta — y nombrado |
Repair::recommendedPackages()
public static function recommendedPackages(string $raiz, ?array $clases = null): arrayLos paquetes que el diagnóstico de HOY recomienda instalar.
Parameters
| Name | Type | Description |
|---|---|---|
| $raiz | string | |
| $clases | (null | list<string>) | las clases de plugin, si el host sabe cuáles son |