Skip to content

Retención intencional de watch/update — 20 octubre 2026

Motivo y alcance

Tras cinco resets watchdog de pmx50, el updater natural de las04:00 podía añadir pulls y recreaciones sin una guarda de estabilidad. watch cada cinco minutos también puede recrear contenedores ausentes/restaurar redes. El flock común evita solapamiento, pero no reconoce el incidente. Ninguna de estas funciones actualiza kernel o reinicia el host.

Se retienen sólo homelab-ctl y homelab-ctl-2: sus comandos ahora son exactamente:

/bin/sh -c 'echo HOMELAB_LIFECYCLE_HELD_PMX50_WATCHDOG >&2; exit 75'

La contrapartida es que queda pausada la autorreparación de watch durante el incidente; las otras tareas gestionadas continúan. Los horarios */5 * * * * y 0 4 * * *, las19 tareas, daemon, campos restantes y otras17 tareas se conservan. Es una retención visible con salida75, no un éxito artificial. No se dispararon jobs, pulls, recreaciones, backups ni notificaciones como prueba. git_autocommit03:17 y originales11:10 quedan intactos. El autocommit publica Git; no se encontró una cadena fuente que lo convierta en despliegue Ansible: el repositorio GitOps es homelab-infra y homelab_tools lleva never.

Fuente y aplicación por coordinador

Fuente publicada c13b09c: scripts/original-backups/hold-homelab-lifecycle.py, SHA256 <REDACTED>. Catorce pruebas locales pasan: perfiles exactos, conservación de campos, drift, inflight, pre-rename CAS, rollback por reload/señal, recibos, restauración manual y no-daemon stdout/stderr. La prueba de señales inyecta SIGHUP real durante instalación/restauración de handlers; las transiciones bloquean TERM/INT/HUP mediante pthread_sigmask.

El primer intento con helper3eb8 abortó antes de escribir configuración (task_profile_mismatch): faltaban los comentarios inline reales de catch_up/on_overlap en el perfil literal. Hash63af e inode3425805 se conservaron. La corrección exige esas líneas exactas, sin aflojar hash ni campos. Una primera lectura posterior falló sin resultado agregado; el diagnóstico siguiente acreditó PermissionError al leer el ledger root0600, sin fallo de configuración.

El coordinador aplicó el helper6fdced bajo el mismo flock existente, no bloqueante, sin crear/reemplazar el lock: propietario, regularidad, nlink y correspondencia inode/path comprobados. Se rechazan procesos watch/update existentes. Backup privado, CAS antes/después de staging, fsync y reemplazo atómico; recarga nativa con CONFIG/DATA/socket explícitos, sin restart. Fallo/señal activa rollback condicionado al hash candidato; drift ajeno impide sobrescribir.

Evidencia aplicada Valor
Helper instalado /home/monxas/.local/state/lifecycle-hold-20261020-59sxhut_/hold-homelab-lifecycle.py
Backup y recibo /home/monxas/runwisp/rollbacks/lifecycle-hold-l_la19l1
SHA previo <REDACTED>
SHA retenido <REDACTED>
Resultado held, reload_rc0

Verificación de lectura a03:09:20,980726 CEST

Configuración regular/nlink1, UID/GID1000:1000, modo0600, inode3426519, SHA retenido exacto. Original y recibo privados1000:1000/0600; recibo identifica ambos hashes y resultado held/reload0. Parseo TOML local en RAM:19 tareas; tras retirar sólo los dos campos run, todo el documento coincide, incluido daemon y las otras17 tareas. No se imprimió configuración completa ni variables.

RPC status: rc0, healthy=true, scheduling_active=true, config_stale=false, versión0.14.0 y19 tareas. Próximas ejecuciones reportadas: watch20oct03:10 y updater20oct04:00. RPC no expone sus comandos: los runs se acreditan en disco más configuración no obsoleta. Cero procesos exactos homelab-ctl.py watch/update en esa observación. No equivale a observar todavía la salida75 natural posterior.

Ledger de originales: únicamente metadata acreditada, UID/GID0:0,0600,nlink1,inode1891771; monxas no puede leerlo (PermissionError). No se afirma SHA actual ni se modificaron sus permisos. El SHA613875 histórico sigue siendo evidencia de la fase anterior, no de esta comprobación.

Primer tick natural observado

A las 03:10:43,937842 CEST una lectura de estado del daemon registró homelab-ctl.last_run.exit_code=75, duración128ms y próxima ejecución03:15. El scheduler seguía activo, healthy=true, config_stale=false y19 tareas. No se invocó el job manualmente: es la primera salida de retención observada tras el horario natural de03:10. La API no expuso un timestamp del resultado en los campos seleccionados; no se inventa una hora exacta de inicio.

El updater conserva próxima ejecución04:00; su last_run muestra exit1 y duración 194977ms, sin timestamp seleccionado. Es un resultado anterior, no una ejecución nueva de las04:00 ni una prueba del hold de ese horario. El comando retenido y la configuración cargada sí están acreditados; la observación natural queda pendiente.

Persistencia y restauración

Retención intencional sin caducidad automática. Los taskruns originales permanecen en ansible/host_vars/media-208.yml; hay drift operativo deliberado. No aplicar el role RunWisp completo: podría levantar el hold. No se editó esa política declarativa para convertir una contención de incidente en nuevo comportamiento permanente.

Cuando se levante la suspensión runtime y se acrediten las precondiciones de estabilidad, restaurar mediante el helper corregido para Linux indicado abajo y el recibo original, como monxas, conservando copia/recibo:

python3 /home/monxas/.local/state/lifecycle-hold-linuxfix-20261020-uujeqxui/hold-homelab-lifecycle.py --execute --restore-receipt-directory /home/monxas/runwisp/rollbacks/lifecycle-hold-l_la19l1

El helper toma el flock, valida recibo/original/perfil y exige CAS contra el hash retenido; restaura sólo ese baseline y recarga. Si cambió el TOML, aborta: reconciliar la diferencia, sin force. Comprobar después hash/campos/RPC; no disparar update/watch como prueba. Esta instrucción no se ejecutó en esta fase.

Corrección posterior y validación Linux

El run39353192687 falló en dos pruebas de hold con Linux/Python3.12. Un mock global de os.listdir ocultaba también los fragmentos TOML a Path.iterdir en3.12; el fixture ahora intercepta exclusivamente /proc y delega los demás directorios al sistema real. El segundo fallo acreditó una diferencia real de señales: SIGHUP pendiente podía entregarse al restaurar handlers después del rollback y provocar una segunda recarga, degradando el resultado a rollback_unverified.

La finalización agrupa rollback, resultado de recarga y escritura/fsync del recibo bajo la misma sección de señales ignoradas. Sólo marca el resultado como finalizado después de persistir el recibo. Una cancelación entregada al restaurar handlers después de ese punto no repite CAS ni reload; antes de ese punto se mantiene la recuperación y los fallos siguen visibles. No se presupone que cambiar handlers y desbloquear señales sea una operación atómica del sistema.

Se conservaron las14 pruebas y añadieron dos: cancelación posterior al terminal duradero con reload exactamente dos veces y recibo rolled_back, tanto tras reload fallido como tras cancelación inicial; y fallo de escritura del recibo, que impide afirmar éxito y conserva la configuración original. La prueba con SIGHUP real durante instalación/restauración conserva sus expectativas. El run39353452948, commit56af616, pasó en Linux: 72 pruebas de las suites de copia/publicación en Python3.10 y otras72 en3.12; 16 pruebas hold en3.12, sin skips.

El helper corregido tiene SHA256 <REDACTED>; el test, <REDACTED>. El coordinador lo preparó en VM208 a 03:27:41,423864 CEST en /home/monxas/.local/state/lifecycle-hold-linuxfix-20261020-uujeqxui/hold-homelab-lifecycle.py, con directorio privado0700 y compilación nativa Python3.10.12 correcta. Esta preparación no ejecutó el helper ni una restauración: el TOML retenido SHAf7b3a3… continuó idéntico byte a byte. La compilación nativa no equivale a una suite nativa en VM208; la evidencia de ejecución Linux es el runCI citado.

La ruta6fdced de la tabla anterior se conserva como evidencia histórica del helper que aplicó el hold. Para una futura restauración, una vez revisada la estabilidad, se usa la ruta corregida64dc mostrada en el comando, con el mismo recibo original. La restauración manual no se modificó en esta corrección: una cancelación tardía puede dejar un resultado de CLI conservador aun después de guardar el recibo; no se debe deducir de ello que deba repetirse la operación ni ignorar el CAS.

Ejecuciones naturales verificadas a04:48:44 CEST

Una lectura RPC de VM208 a 20oct04:48:44,231040 CEST acreditó el efecto natural del hold, sin disparar tareas manualmente:

Tarea Inicio natural CEST Resultado Duración Próxima ejecución reportada
homelab-ctl-2 updater 20oct04:00:00,001459 ended, exit75 35ms 21oct04:00
homelab-ctl watch 20oct04:45:00,007291 ended, exit75 112ms 20oct04:50

RPC rc0, healthy=true, config_stale=false, scheduling_active=true, versión0.14.0 y19 tareas. Esta evidencia acredita que ambas tareas ejecutaron su comando de retención; no acredita estabilidad futura de pmx50 ni justifica levantar la pausa. Se conservan la ausencia de caducidad, el tradeoff de autorreparación pausada y el procedimiento CAS con helper corregido indicado arriba.