Skip to content

Consola de mantenimiento y coordinación eléctrica — 2026-10-19

Autorización: aplicar las prioridades de review-next-20261019.md, con agentes. Fuente consola ~/Dev/homelab-maint; runtime CT212 /opt/homelab-maint. No se han ejecutado apagados, evacuaciones, reinicios de nodos, cortes Meross, pruebas de batería ni cambios de estado HA para probar estos cambios.

Aplicado en consola

  • Timeout cubre consumo de stdout y espera del proceso. Al vencer o abortar, termina el grupo local, escala a SIGKILL y recoge el proceso. Se advierte que una operación remota que ya arrancó exige comprobar su estado remoto.
  • Exclusión mutua de tareas; no se pueden ejecutar transiciones simultáneas.
  • Transiciones L1–L4 fallidas conservan el último nivel confirmado y muestran CAMBIO PARCIAL/FALLIDO en la UI y transition.status=partial_or_failed en API. La transición exige el nivel de origen correcto.
  • Preflight L1 antes de cualquier mutación: Vera, Alertmanager CT217, Docker VM208 y los tres schedulers RunWisp accesibles.
  • Silencios dirigidos al propietario CT217, con autor propio homelab-maint; la salida sólo expira silencios de ese autor. Ya no expira todos los silencios.
  • Fallos de RunWisp y de las llamadas a HA dejan de quedar ocultos por echo. Pausar escritores que están corriendo propaga el error real de docker pause.
  • Evacuación pmx51 comprueba quórum, afinidades estrictas y memoria antes de tocar flags o HA. Usa límites configurados y reserva de 2 GiB; no presupone recuperación balloon. El timeout de vaciado ahora falla explícitamente.
  • Reinicio local es una operación distinta: exige shutdown_policy=conditional; indica interrupción local de servicios estrictos, sin prometer evacuación.
  • Salir de evacuación respeta failback individual; ya no espera que HAOS y todos los recursos vuelvan forzosamente a pmx51.
  • Despliegue falla si la API no responde o está malformada; no interpreta error como cero tareas. Guarda rollback y copia sólo fuentes explícitas, sin borrar estado, logs, virtualenv ni ficheros runtime desconocidos.

Despliegue: API running=[], código original comparado con fuente, snapshot /opt/homelab-maint-rollback-20261019T*, copia selectiva y reinicio sólo consola. Después: API accesible, running=[], nivel L0. No se sobrescribieron state/logs.

Validación: cinco pruebas locales aisladas (éxito, timeout con salida, timeout silencioso, aborto y guardas de afinidad/capacidad) correctas. El PID del proceso terminado deja de existir. Sintaxis Python/YAML y diff sin errores. Preflight L1 real y reinicio-local reales pasan, ambos sólo lectura. Preflight real evacuación termina rc1 con ct:110,ct:172,ct:217,ct:218 estrictos, antes de mutaciones. No se pulsaron las acciones de mantenimiento para verificarlo.

SAI: evidencia adicional y límite de activación

El código Proxmox instalado (PVE/HA/LRM.pm) confirma que conditional congela HA al reiniciar, pero permite failover al apagar. Paralelizar pct/qm conservando el script viejo no basta: podría competir con HA. Existe también la operación nativa ha-manager crm-command disarm-ha freeze|ignore y arm-ha, que tampoco se ha ejecutado porque requiere una recuperación coordinada del armado.

NUT tiene NOTIFYCMD upssched, pero NOTIFYFLAG ONLINE sólo SYSLOG+WALL y no EXEC; no hay hook ONLINE activo para restaurar una política temporal. Cambiar a freeze sin restauración comprobada modificaría el comportamiento normal tras el corte. El role power_safety tampoco gestiona actualmente shutdown_policy.

Meross usa /config/packages/pmx50_autorrecuperacion.yaml: sólo consulta el boolean local, conectividad y límite temporal, sin comprobar bandera de mantenimiento ni NUT. No se ha activado un apagado nuevo hasta coordinar también esa guarda. Los MCP HA de escritura/servicios y hab no están expuestos en esta sesión. Las instrucciones de /config/AGENTS.md requieren write_config_safe y call_service, y prohíben sustituirlos por shell cuando el perfil no los expone. No se han leído secretos ni estado interno HA.

Propuesta de activación pendiente: inhibir autoencendido y Meross antes de operar, serializar cambio de política, conservar conditional y demás propiedades HA, establecer freeze sólo durante parada por energía, delegar la parada a LRM y pve-guests, y restaurar conditional únicamente con estado OL verificable y reconciliación del peer. Debe soportar primario caído, quorum ausente, doble notificación y pérdida de alimentación durante la restauración. No convertir desired=started a stopped persistentemente. No se ha ensayado autonomía ni acreditado protección física de los dos NAS.

Guardas eléctricas independientes aplicadas después

Sin cambiar NUT, HA ni Meross:

  • bin/maintenance-preflight poweroff lee el boolean de autorrecuperación por API y comprueba ambos flags. Si Meross no está explícitamente off o la lectura falla, bloquea la parada intencionada. Insertado antes de p51-poweroff. Prueba read-only actual: rc1 por Meross on, sin cambiar el boolean ni flags.
  • node-autowake.sh ahora bloquea WoL cuando NUT confirma OB/LB/FSD o existe /run/ups-shutdown-in-progress, además del flag persistente de mantenimiento. Si NUT no responde o el primario está caído, conserva la recuperación previa: impedir WoL en ese caso anularía la recuperación de pmx50, que aloja NUT. No permite inferir energía segura cuando NUT está desconocido; la coordinación Meross/SAI completa sigue pendiente. El nuevo flag de apagado está preparado para un futuro coordinador; el SHUTDOWNCMD actual aún no lo establece.
  • Template de power_safety y ambos runtimes sincronizados mediante inserción acotada, sin regenerar ni sobrescribir otras líneas. Rollback en cada nodo: /usr/local/bin/node-autowake.sh.pre-energy-guard-20261019.
  • Ocho fixtures aisladas correctas: OL, desconocido y fallo del primario conservan WoL simulado; OB, LB, FSD, bandera manual y bandera de apagado lo impiden. Los mocks sustituyen ping, upsc y etherwake; no hubo paquete WoL real ni consulta de batería como prueba de corte. bash -n correcto en ambos nodos.

Total de pruebas de esta actuación: 5 consola + 8 autowake = 13 correctas. La secuencia nueva de apagado UPS queda sin activar por la dependencia Meross pendiente y la restauración freeze/conditional aún no acreditada. El script SHUTDOWNCMD sigue siendo el anterior; estas guardas no lo sustituyen.