Consola: procesos de sondeo y consultas simultáneas¶
2026-10-19. Fuente homelab-maint/app.py, rama main; runtime CT212,
/opt/homelab-maint/app.py. Se corrige un timeout/cancelación que podía dejar
vivos ping, curl o el shell SSH local. Cada proceso tiene grupo propio, se recoge
su handle incluso al cancelar durante spawn y se termina/recolecta el grupo en
finally. Esto no garantiza detener comandos remotos que el servidor SSH haya
desvinculado: las sondas actuales son de lectura y sus comandos NFS ya tienen timeout.
/api/probes comparte el mismo lote entre peticiones concurrentes y conserva
su resultado cinco segundos. Cancelar una petición no cancela el lote de otra
pestaña. La fecha at conserva la hora real del lote; no se renueva al servir caché.
Se conserva el significado HTTP anterior: un 4xx demuestra respuesta HTTP, no
login funcional. Una sonda TCP tampoco demuestra salud completa del servicio.
34 pruebas pasan: las 32 anteriores y dos nuevas que ejecutan timeout/cancelación con procesos locales reales, prueban ausencia del PID tras cleanup, caché, caducidad y desconexión de un consumidor concurrente. Sin acciones sobre NAS, servicios multimedia ni notificaciones como prueba.
Desplegado con deploy.sh tras API running=[]; se preservan estado/logs. API tras
reinicio: L0, running=[], recovery=null. Hash local/instalado coincidente:
<REDACTED>.
Rollback: copia fechada más reciente /opt/homelab-maint-rollback-* creada por
deploy.sh; restaurar app.py únicamente con running=[] y reiniciar el servicio.
No se activan las transiciones L2–L4 pendientes.
Estado manual y falsos positivos: 20 octubre, 07:56 CEST¶
Las fuentes fcf3426 y edf71bd de homelab-maint corrigen tres casos:
- Los endpoints manuales de nivel/marcado preparan una copia del estado y sólo actualizan memoria después de guardarla. Un OSError no publica un nivel u OK que no haya podido persistirse. No se añade garantía de durabilidad ante corte eléctrico ni coordinación entre varios workers.
- La sonda Docker de VM208 propaga el error de
docker ps; cero contenedores sigue siendo un resultado válido si Docker respondió correctamente. - La sonda Vera conserva el RC remoto: se retiró
| tail -1, que convertía unsystemctl is-activeinactivo o un error deguesten un falso saludable.
Doce pruebas nuevas del conjunto reciente usan estado privado, ASGI en proceso sin lifespan y helpers SSH/Docker/guest falsos. El conjunto completo suma 74 pruebas, correcto en Python3.12 y3.14 en CI39377261624. No se llaman sondas reales como validación.
Aplicación protectora selectiva a las 07:56 CEST, tras revalidar CT212
running en proxmox2, unidad active/running, RUNS0, L0 y recovery sin pendiente.
Sólo se sustituyeron app.py y tasks.yaml, con backup privado, CAS de hashes
metadatos e identidad, compilación nativa sin importar app y YAML safe_load.
No se ejecutó deploy.sh, pip ni se cambiaron unidades, static, bin o venv.
Se reinició únicamente homelab-maint.service después de instalar ambos archivos.
| Archivo | SHA256 instalado |
|---|---|
| app.py | <REDACTED> |
| tasks.yaml | <REDACTED> |
Postcheck de servicio/API/hash correcto: RUNS0, L0, recovery sin pendiente y
11 estados persistidos. state.json conserva hash e identidad completos:
<REDACTED>.
El GET se limitó a /api/tasks; no se llamó /api/probes, portada, HA ni Sablier.
Recuperación: /root/homelab-maint-protective-g0i8gx8z dentro de CT212, directorio
0700, originales y recibo0600. Para volver atrás, revalidar ausencia de tareas,
estado y fuentes actuales antes de reponer únicamente esos dos originales y
reiniciar la consola. No restaurar state.json ni repetir tareas. Los reemplazos
son individuales y la comprobación de API no bloquea clientes concurrentes;
la ventana debe mantenerse ociosa. No se han habilitado transiciones L2–L4.
Timeout o señal no pueden terminar en OK: fuente del20oct18:32¶
La PR1 de homelab-maint
se fusiona18:32:39 CEST en <REDACTED>.
Antes, un paso con ignore_rc podía agotar timeout, activar recovery y continuar
hasta actualizar last_ok o elevar el nivel. La regresión se reprodujo únicamente
con procesos locales y estado privado, sin ejecutar ha-update, NAS ni otra
tarea real. La revisión añadió también el caso de terminación local por señal.
Ahora timeout o rc negativo detienen el lote antes de pasos/verificación, conservan nivel y último éxito y exigen revisión para tareas mutativas. Un sondeo read-only interrumpido falla sin imponer recovery mutativa. Los RC ordinarios expresamente tolerados, incluidos42/255 en fixtures, mantienen su comportamiento; no se interpreta137 como prueba de señal local. Una operación SSH remota puede continuar pese a terminar el proceso local: no hay reintento ni certificación de terminación remota.
Las81 pruebas completas pasan en copia temporal local y repetición independiente;
CI de PR39458215379
y CI posterior39458375727
pasan en Linux Python3.12/3.14. App fuente SHA256
<REDACTED>.
Las pruebas ejecutan grupos locales reales y comprueban ausencia de marcadores
posteriores y persistencia del estado; no importan el runtime desplegado ni
activan lifespan, probes o productos. El estado de aplicación se documenta
separadamente: merge y CI no demuestran despliegue.
Aplicación protectora18:39 y verificación independiente18:40 CEST¶
El20oct18:39:46,538772 CEST se sustituyó sólo
/opt/homelab-maint/app.py de CT212, tras revalidar propietario proxmox2,
unidad activa y API ociosa/L0/sin recovery. La baseline coincidía exactamente
con la app edf71bd y los archivos preservados de las07:56. El candidato es
el blob exacto de main 9616b37, compilado con Python nativo3.13.5 sin importar
la aplicación. Se conservaron UID:GID501:50 y modo0644; respaldo privado,
CAS de identidades/hashes, sustitución atómica y fsync. Se reinició únicamente
homelab-maint.service después de volver a comprobar estado/API ociosos.
La lectura independiente 18:40:32,576600 CEST acredita propietario actual, active/running, PID2485→2806 e inicio monotónico35847028573→74453434769. App instalada SHA9da441… exacta (22295bytes), L0/RUNS0,11 estados y sin recovery pendiente. State SHA2eae… y tasks f2db… conservan identidad y hash completos de baseline; también unidad31f489…, configuración venv aede…, metadatos seleccionados de venv y de17 logs. No se leyó contenido de logs ni se importó la app. No se ejecutaron tareas, probes, HA, llamadas al NAS, deploy.sh o pip; no se cambiaron unidades ni otros archivos.
Recuperación: dentro de CT212,
/root/homelab-maint-app-killguard-s7gcrhjy modo0700,
app.py.before y receipt.json0600. El original conserva hash8c3c65… y el
recibo declara verified/ok, SHA256
<REDACTED>.
Para recuperar, revalidar propiedad, ausencia de tareas y configuración actual;
restaurar únicamente el archivo acreditado con sus permisos, sin state/logs,
y reiniciar sólo la consola. No repetir tareas como prueba de recuperación.
Evidencia privada en
~/.local/state/ct212-app-protection-preflight-20261020-inegqfak/:
- Preflight SHA256
<REDACTED>. - Instalador revisado
<REDACTED>; siete fixtures de transacción pasan también en revisión independiente, sin runtime. - Resultado de aplicación
<REDACTED>. - Postverify independiente
<REDACTED>.
El flock sólo coordina instaladores cooperantes: las lecturas idle no bloquean nuevos clientes API; la ventana se mantuvo ociosa y el estado posterior coincide. Un resultado incierto exige inspeccionar recibo y runtime, sin retry ni rollback automático. No se habilitan transiciones L2–L4 ni se resuelve por esto el watchdog.
Checkout CI sin credenciales persistentes: 18:48 CEST¶
PR2 de homelab-maint,
merge <REDACTED>, añade únicamente
persist-credentials: false al checkout de CI. Conserva pin, permisos de
lectura, matriz y comandos. Las81 pruebas pasan en Linux Python3.12/3.14,
CI de PR
y CI posterior.
No cambia el blob de app, instalado previamente con hash9da441…;
no requiere otro despliegue ni reinicio de la consola.
Contención de las transiciones L1, 22 octubre 19:00 CEST¶
La revisión de L1 encontró un riesgo distinto de los timeouts anteriores:
exit-l1 despausaba todos los contenedores, arrancaba RunWisp en tres hosts,
retiraba el marcador de Vera, activaba una automatización HA y expiraba silencios
sin un recibo que identificase los cambios propios de enter-l1. Podía revertir
pausas o protecciones anteriores. L2–L4 ya estaban bloqueados y sus comandos
antiguos permanecen como borradores inactivos; no se ejecutaron al revisarlos.
La PR3 de homelab-maint, main
dd94d12a, bloquea también ambas transiciones L1 con disabled_reason.
Los pasos activos conservan sólo el preflight de lectura; los comandos anteriores
quedan en draft_steps/draft_verify, que el runner no utiliza. La UI respeta el
bloqueo y la API rechaza409 antes de ejecutar. El preflight independiente de
lectura sigue disponible. La restauración selectiva de L1 no está implementada:
esta entrega contiene la reanudación global, no acredita un ciclo L0→L1→L0.
Las dos regresiones ASGI nuevas fallaban antes; verifican409 sin runner, procesos, escrituras de estado ni logs. La suite de83 pruebas pasa localmente en Python3.14 y la CI en Python3.12/3.14. Dos fixtures de cancelación usan ahora una transición sintética habilitada, conservando la cobertura de abort antes del arranque y doble abort idempotente sin depender de una tarea L1 bloqueada.
Entrega a CT212 el22oct a las19:00:44: únicamente tasks.yaml, mediante backup
privado y CAS, sin reinicio. La aplicación relee el YAML en cada petición.
SHA256 instalado <REDACTED>,
UID501/GID50 y modo0644 conservados. El GET local confirma exactamente las dos
tareas cambiadas; PID2806, L0/RUNS0, state.json y metadata de17 logs intactos.
No se invocó L1 ni su preflight en producción; tampoco se consultó HA o Vera.
Retorno privado en /root/maint-l1-containment-20261022-db6mfkty/ dentro de CT212.
Antes de restaurar una versión, revisar su seguridad: el backup conserva las
órdenes antiguas y no es una recomendación de reactivarlas.
Persistencia durable de estado, 22 octubre 19:41 UTC¶
La PR4 de homelab-maint,
main <REDACTED>, corrige el registro que precede
a los comandos. El temporal es exclusivo y privado, se sincroniza el archivo,
se publica con replace y se sincroniza el directorio. La evidencia de un estado
ilegible se publica sin sustituir otra copia y también se sincroniza antes de
reemplazar el original. Un archivo previo distinto o un symlink falla cerrado.
Ocho regresiones nuevas cubren errores de fsync/replace antes del arranque,
revisión que conserva el bloqueo en memoria, archivo corrupto, colisiones y
reutilización de evidencia. Pasan 91 pruebas en Python 3.12 y 3.14, sin conexiones
externas en las suites locales; ambos jobs de la CI
39840853939
terminaron SUCCESS para el head f760f99a. Un error de fsync del directorio tras
replace deja publicación incierta: el archivo nuevo puede ser visible aunque la
API conserve su bloqueo en memoria. No se promete que el archivo antiguo siga
publicado en ese caso ni se ha ensayado un corte físico de alimentación.
Entrega única a CT212 a las 19:41 UTC: sólo app.py, con CAS y retorno privado
en /root/maint-app-only-1c6tjodk/. SHA instalado
<REDACTED>,
UID 501/GID 50 y modo 0644 conservados. Una fixture nativa de las tres funciones,
extraídas por AST sin importar la aplicación, comprobó publicación, modo 0600 y
archivo/reutilización de bytes corruptos en un temporal del mismo filesystem.
El archivo real de estado no se reescribió para probarlo.
La consola se paró y arrancó una vez. PID 3635 estable durante diez segundos, Result success y NRestarts 0. Estado, tareas y unidad conservados byte a byte y con full9; del directorio de logs sólo se verificó metadata, no los bytes de sus archivos. Revisión independiente 19:42:17 UTC: código exacto, UID/modo, estado y tareas intactos, API L0/RUNS0 sin transición ni recuperación, ambos bloqueos L1 conservados y boots de host/CT estables. No se ejecutaron tareas o probes, ni se consultaron HA o Vera.
Recibos locales maint-app-only-delivery-cos65wln/native.json, SHA
<REDACTED>,
e independent.json, SHA
<REDACTED>.
Este cambio no implementa recuperación selectiva L1. Siguen faltando recibos
por operación y recurso realmente cambiado, con identidad, estado previo y
efecto confirmado; no basta invertir una lista de acciones previstas.
Autenticación por LAN, revisión del 22 de octubre¶
La política viva de Cloudflare para maint.monxas.casa conserva una sola regla
allow limitada al propietario, con PocketID como IdP y sesión de 24 horas.
Se consultaron aplicación y política por API, sin modificarlas. Esto protege
la entrada por Cloudflare; no prueba autenticación por la ruta local.
La fuente revisada de la consola (da342e4c) no autentica peticiones. La unidad
escucha en 0.0.0.0:8800, ejecuta como root y la ruta Caddy mantenida en
d96e0eb8 sólo reenvía al backend. La confirmación de una tarea y las guardas
L1 no verifican identidad.
La comprobación desde Mac con destino TLS fijado a la VIP .250, sin cookies,
Authorization ni redirecciones, devolvió HTTP 200 en /api/tasks; el JSON
contenía el esquema esperado de la aplicación. Queda confirmado el acceso
anónimo a la API por esa entrada LAN. El intento directo a .212:8800 produjo
un error de conexión: no demuestra la política del firewall ni permite extender
el hallazgo a todas las rutas de red. Sólo se emitieron GET, sin tareas o probes.
La PR5 de homelab-maint, main
<REDACTED>, incorpora validación criptográfica
del JWT de Access en origen para todas las rutas funcionales, con audiencia y
emisor específicos y rechazo de peticiones sin identidad. Sólo la salud mínima
/api/health queda exenta desde el peer socket loopback.
La decisión es aceptar el header de Access, sin habilitar una alternativa por
cookie directa en LAN. Por ello la entrada LAN que evita Cloudflare recibirá un
rechazo; no se promete login automático con DNS local ni autenticación OIDC
nativa independiente de Internet. La documentación de Cloudflare
describe la validación de firma, emisor, audiencia y claves públicas.
Preflight de CT212: propietario proxmox2, boot del invitado 1ef89884…,
PID 3635 activo y NRestarts 0, L0 y ninguna tarea en curso; ambos bloqueos L1
conservados. Recibo local maint-auth-preflight-t341f3kv/before.json.
Pasan 111 pruebas en Python 3.12 y 3.14 con conexiones externas bloqueadas en
las suites locales. Ambos jobs de la
CI 39845793760
terminaron SUCCESS para db0a4e60; los ocho archivos del merge son idénticos a
los revisados. Las regresiones incluyen la aplicación real configurada para
producción, firmas RSA, claims incorrectos, rechazo antes de ejecutar tareas o
probes, caché y límites JWKS, y caducidad del SSE real conservando la tarea.
Ensayo aislado previo en CT212 con Python 3.13: 20 pruebas de autenticación correctas con red bloqueada, más una lectura separada de las claves públicas de Access por HTTPS. Se comprobaron dos claves compatibles. El ensayo mantuvo la producción intacta y fijó las versiones de las 15 dependencias existentes.
Entrega 20:13:11–26 UTC: sólo app.py, el módulo access_auth.py, requisitos y
unidad fuente/instalada; una parada y arranque de la consola. Se añadieron
PyJWT 2.15.1, cryptography 50.0.2, cffi 2.1.1 y pycparser 3.12 desde las ruedas
del ensayo; las versiones existentes no cambiaron. El servicio quedó en PID
3724, activo y NRestarts 0, estable diez segundos. Salud mínima por loopback:
HTTP 200 y cero tareas; /api/tasks anónimo, también por loopback: HTTP 401.
proxy_headers=False conserva el peer socket real para la salud mínima.
Estado y tareas conservaron hash y full9, además de la metadata del directorio
de logs; no se afirman los bytes de todos sus archivos. No se ejecutaron tareas,
probes o POST productivos, ni se accedió a HA o Vera. Retorno privado de código
y unidad en /root/maint-auth-staging-<REDACTED>/backup;
no restaurarlo sin revisar que devolvería la versión sin este filtro.
Recibo nativo maint-auth-preflight-t341f3kv/native-apply.json, SHA256
<REDACTED>.
Verificación independiente 20:15:17–25 UTC: propietario y boots estables,
cinco archivos instalados exactos, PID 3724 activo/NRestarts 0, configuración
MAINT cargada exacta y ninguna unidad drop-in. Las 15 versiones anteriores y
las cuatro añadidas coinciden con el ensayo; estado, tareas y metadata del
directorio de logs conservados. Salud loopback 200/cero tareas y API anónima
401. Desde Mac, tres GET por VIP con TLS validado devolvieron 401: anónimo,
email de identidad sin firma y assertion malformado. No se probaron credenciales
reales. Recibo maint-auth-preflight-t341f3kv/independent.json, SHA256
<REDACTED>.
La verificación de firmas y ASGI con identidades sintéticas no equivale a un login real de producción, que sigue pendiente. El cambio no habilita L1 ni implementa autenticación OIDC nativa independiente de Access/JWKS.
Sondeos sin lectura NFS, 23 de octubre 00:43 UTC¶
La PR6 de homelab-maint
quedó integrada en main como <REDACTED>.
El sondeo automático anterior hacía ls de /mnt/nfs_media/nopor en cada
consulta de la consola. Ahora consulta la tabla local de montajes con
findmnt --kernel --nocanonicalize, limita columnas y comprueba ruta/tipo
exactos. La documentación de findmnt
distingue la lectura de mountinfo y la canonicalización de rutas. No se recorren
directorios NFS ni se dispara autofs para comprobar datos. Vera se retira del
sondeo automático mientras el propietario trabaja en paralelo.
El indicador NFS montado en 208 (metadatos) sólo acredita el registro de un montaje NFS/NFS4 en esa ruta. No prueba lectura/escritura, respuesta del NAS ni resolución del estado HELD de recuperación. La prueba TCP es independiente. Pasan 109 pruebas locales y los dos jobs CI Python 3.12/3.14; los fixtures privados ejecutan el pipeline real y cubren NFS, NFS4, ruta equivocada, autofs y fallo del lector. La consulta nativa previa de metadatos fue correcta.
Entrega 00:43:05 UTC: sólo tasks.yaml, sustituido atómicamente tras admitir
L0, cero tareas y ausencia de recuperación requerida. Se conservan UID501,
GID50 y modo0644, además de estado, app, autenticación y proceso. No se reinicia
la consola ni se ejecutan probes, preflight o tareas para verificar la entrega.
El archivo queda con SHA256
<REDACTED>.
Retorno privado en /root/maint-quiet-probes-20261023-ck8vrxas.
Revisión independiente 00:44:12 UTC: CT212 sigue en proxmox2, boots estables,
archivo exacto y metadata conservada, sondeo NFS limitado a metadatos, Vera
fuera del sondeo y bloqueos L1 presentes. PID3724 activo, Resultsuccess,
NRestarts0; salud loopback HTTP200 y cero tareas. No se consultó la API de
probes ni se accedió al NAS o a Vera. Recibo privado
maint-quiet-independent-o8w1l729/selected.json, SHA256
<REDACTED>.
Preview de rutas sin mutaciones locales explícitas, 23 de octubre¶
La PR215 está integrada como
<REDACTED>. El sync --dry-run del controlador
central antes creaba/truncaba el lock, protegía/escribía cachés y añadía log.
Ahora conserva en RAM las etiquetas y las proyecciones de cachés anteriores,
sin cambiar caché, permisos, anfitriones aceptados, log o lock. SSH en preview
exige claves conocidas y desactiva su actualización, conexiones multiplexadas y
comandos locales. No se hace reload ni smoke de aplicaciones.
Es una vista sin bloqueo, no una autorización reutilizable: el sync real conserva su cerrojo y revalida. Las consultas SSH y GET de Cloudflare siguen siendo consultas remotas, que sus sistemas pueden registrar. No se promete instantánea atómica ni ausencia de toda escritura implícita del sistema operativo.
Validación: 42 pruebas correctas y una prueba Caddy opcional omitida en Python 3.12 y 3.14; las cuatro comprobaciones CI del head revisado terminaron bien. Los fixtures ejecutan el preview completo con transportes falsos y rechazan mutaciones; incluyen caché previa/offline, deriva, excepciones, argumentos SSH y preservación del lock/cache en el camino real. Revisión independiente correcta.
Entrega 01:04:23 UTC: sustitución atómica exclusiva de
/usr/local/bin/homelab-ctl, SHA256
<REDACTED>.
Sintaxis compilada en RAM con el Python nativo, UID/GID/modo preservados.
La metadata de 21 rutas de configuración, caché, log, cerrojo, claves y consola
se mantuvo igual; PID3724 y NRestarts0, cero tareas. No se invocó el controlador,
ni se ejecutó sync, smoke, probes, preflight o reinicio. El retorno del código
está en /root/controller-preview-20261023-c0m2khhe; revalidar la ruta en el
recibo privado antes de usarlo. La comprobación de comportamiento corresponde
a fixtures aislados; no se afirma un preview funcional real contra el homelab.
Revisión independiente 01:06:06 UTC: CT212 en proxmox2, boots estables,
ejecutable exacto SHA anterior, UID0/GID0/modo0755 y metadata estables. Sintaxis
compilada en RAM sin ejecutar el controlador. Consola PID3724 activa, Resultsuccess,
NRestarts0 y salud loopback HTTP200/cero tareas. No se consultaron rutas, tokens,
probes o configuración privada. Recibo privado
controller-preview-independent-5p1p851g/selected.json, SHA256
<REDACTED>.
Smoke de rutas sin falso éxito, 23 de octubre 01:18–01:20 UTC¶
El controlador central podía aceptar un error de curl con salida HTTP 000
como éxito. Además usaba TLS sin verificar y seguía redirects. La
PR218, integrada como
<REDACTED>, corrige ese contrato: cualquier
error de transporte, salida inválida/000, 1xx sin respuesta final o 5xx falla.
TLS/SNI se verifica contra la VIP, sin curlrc, proxy de entorno ni seguimiento
de redirects. Se comprueba la respuesta de entrada; 401/403 no acredita login
y 3xx no acredita el destino.
smoke y el smoke posterior al sync omiten las rutas bajo demanda, incluso
si ya están activas, para no despertar servicios ni renovar sesiones Sablier.
Muestran entradas comprobadas, fallos y omisiones por separado; lo omitido no
se cuenta como OK. Un inventario incompleto o incompatible bloquea el smoke
antes de cualquier petición; los orígenes de caché y avisos siguen visibles.
No se usa este cambio para declarar sanos todos los servicios.
Pruebas de fuente: 52 correctas y una Caddy opcional omitida en Python3.12/3.14;
cuatro checks CI correctos. Los fixtures ejecutan un curl privado con los
argumentos reales y cubren fallos, estados, omisiones y ambos callers. Entrega
01:18:22 UTC: sustitución exclusiva del ejecutable, SHA256
<REDACTED>.
Nueve casos adicionales con Python nativo y transporte aislado sin capacidad
de crear procesos/sockets pasaron antes de publicarlo. Metadata de 21 rutas
protegidas, unidad y PID3724 conservados; sin sync, smoke HTTP, cambios de rutas
ni reinicios. Retorno de código en /root/controller-smoke-20261023-ve4mtmvo.
La consola también ignoraba todo error del paso rutas-smoke. La
PR8 de homelab-maint, integrada
como <REDACTED>, elimina sólo ese ignore_rc
y precisa el nombre de la tarea. Pasan 128 pruebas Python3.12/3.14 y ambos jobs
CI. La regresión ASGI/runner usa un CLI privado: salidas1/2 producen fallo y
conservan el último éxito; salida0 se acepta, sin probes ni productos reales.
Entrega del catálogo 01:20:12 UTC, después del ejecutable: sólo cambia una
línea de tasks.yaml, SHA256
<REDACTED>.
UID/GID/modo, bytes de estado, app y autenticación conservados; PID3724 estable,
NRestarts0, cero tareas y L1 bloqueado. Retorno privado en
/root/maint-smoke-result-20261023-bm0vzuwr. No se ejecutó la tarea productiva:
esto demuestra entrega y comportamiento aislado, no login E2E ni salud global.
Revisión independiente 01:21:18 UTC: CT212/proxmox2 y boots estables, ambos
archivos con SHA exacto y metadata estable; ejecutable root:root0755 y catálogo
501:50/0644. La tarea contiene un único paso homelab-ctl smoke sin ignore_rc
y conserva los bloqueos L1. PID3724 activo, Resultsuccess y NRestarts0; salud
loopback HTTP200/cero tareas. Sin ejecutar controlador, probes o smoke ni
consultar productos/tokens/configuración privada. Recibo privado
controller-smoke-independent-sszfz9_e/selected.json, SHA256
<REDACTED>.
Resultado parcial de sincronización, 23 de octubre¶
El controlador podía avisar de un fallo de Cloudflare, de recarga Caddy o de
copia managed, y después terminar con código 0 y «Hecho» si el smoke pasaba.
La PR220, integrada en
<REDACTED>, acumula las fases fallidas y devuelve
código 3 con «sync parcial». Un éxito HTTP posterior no convierte las otras
fases en correctas. Cloudflare requiere el booleano success: true.
Cinco fixtures reproducían el falso éxito antes del cambio. La suite corregida pasa 59 casos y omite uno Caddy opcional en Python3.12/3.14; los cuatro checks CI del commit exacto pasan. Las siete pruebas nuevas cubren cada fase, fallos combinados, tipos de respuesta Cloudflare y el caso completo correcto. Conservan el orden de las acciones; no se añaden reintentos, reinicios ni rollback. Estas son pruebas aisladas, no una incidencia observada ni un sync productivo.
Entrega 01:38:04 UTC: sustituido únicamente /usr/local/bin/homelab-ctl,
SHA256 <REDACTED>.
Sintaxis compilada en memoria y 16 fixtures nativos aislados correctos: nueve
smoke y siete sync, con fronteras remotas simuladas. UID0/GID0/modo0755
conservados, metadata de 21 rutas protegidas sin cambios y consola PID3724
activa, NRestarts0, cero tareas. Sin invocar el controlador productivo, recargar
rutas ni reiniciar servicios. Copia de retorno del código en
/root/controller-sync-result-20261023-48_honlm; no implica rollback de rutas.
Recibo privado controller-sync-publish-n55y4wu9/applied.json, SHA256
<REDACTED>.
Comprobación independiente 01:39:22 UTC: CT212/proxmox2 y boots estables,
CLI con hash exacto, root:root0755, un único enlace y metadata estable. Sintaxis
compilada en RAM sin ejecutar el código; PID3724/Resultsuccess/NRestarts0 e
inicio del proceso estable durante la lectura, salud loopback HTTP200 y cero tareas. Sin
controlador, probes, sync, smoke ni lectura de configuración o tokens. Recibo
privado controller-sync-publish-n55y4wu9/independent.json, SHA256
<REDACTED>,
ligado al recibo de aplicación anterior. Acredita entrega, no ejecución de
una sincronización real ni salud funcional de todas las rutas.