Recuperación acotada de la caché Git de Ansible, 20 de octubre de 2026¶
Avería y alcance¶
El fetch de Ansible-pull de pmx50 falló a las14:45 con objetos vacíos e index-pack
inválido, antes de ejecutar el playbook. Es una avería separada de los resets;
no demuestra su causa. El inventario completo15:12:10 encontró32 objetos loose
vacíos entre4897 entradas en /root/.ansible/pull/proxmox.monxas.casa/.git/objects.
El checkout se conservó: no se hizo reset, checkout, reclone, fetch, limpieza,
actualización de referencias ni ejecución de roles.
Todos los32 objetos estaban disponibles en el Git local sano y son alcanzables
desde el commit ya publicado
Instalación15:19:51 CEST¶
Plan local sin red y11 fixtures correctos, más revisión independiente de
procedencia,32 objetos y protecciones. Instalador privado fijado por SHA256
<REDACTED>;
parte nativa932cd9a7; payload18a38477; procedencia publicada bab35178.
La ejecución se realizó una sola vez.
Se exigió bootdecded74, ausencia de Git/Ansible y cmdlines ilegibles, servicio sin ejecución (failed/failed en la verificación), timer con más de 120 s de margen, inventario exacto de32 vacíos, HEAD y metadatos de30 packs intactos. Cada objeto requería identidad completa y un enlace, root:root, archivo regular vacío y cadena de directorios sin symlinks ni escritura de grupo/otros. La publicación usa temporal exclusivo propio, fsync y reemplazo relativo al descriptor del padre.
Antes del primer reemplazo se guardaron32 copias vacías0600, identidades y recibo
en /root/rollback-ansible-cache-20261020T131951Z-3c195a1f16d8, directorio 0700.
Cada reemplazo registra primero inflight y después el resultado con fsync.
No hay atomicidad global de los32renames ni exclusión de un escritor root ajeno;
una interrupción puede dejar estado parcial y exige inspección, sin reintento o
rollback automático. No se tocaron refs, index, packs, árbol de trabajo,
configuración del servicio o timer ni aplicaciones.
Resultado:32reemplazos, estado objects_replaced_integrity_pending. El recibo original conserva manual_review_required=true y fsck_executed=false; esos campos describen la instalación, no la verificación posterior.
Posverificación independiente15:21:18 CEST¶
Una tanda de lectura comprobó identidad exacta del recibo y bytes comprimidos, SHA Git, zlib y payload para32/32 objetos; backups0600/directorio 0700 correctos. HEAD y origin/main siguen en ba701c46 y los metadatos de30 packs no cambiaron. Bootdecded74 y ausencia de escritores se conservaron durante la observación.
git fsck --connectivity-only --no-dangling, offline, sin optional locks,
fsmonitor ni lazy fetch: rc0, sin salida,0,377s. No es fsck del filesystem,
no verifica el contenido de todos los blobs y no prueba salud física del disco.
La proyección privada de posverificación tiene SHA256
<REDACTED>.
El recibo de instalación no se modificó; sus datos se contrastan con esta
posverificación separada.
A las15:21 el status podía leerse de nuevo, pero conservaba16 archivos tracked modificados; los untracked no se inspeccionaron en esa fase. La clasificación de las15:25 acreditó que los 16 son archivos regulares vacíos, root:root 0644, y su índice y HEAD esperan blobs no vacíos del commit ba701c46:270382 bytes en total. No se encontraron cambios no vacíos desconocidos entre esos 16. Ocho difieren en la fuente publicada3c662710, por lo que no se mezclan versiones: el plan de reparación usa sólo los blobs antiguos que espera ese checkout, no las versiones actuales de main.
La reparación posterior de esos 16 vacíos se describe abajo. El siguiente ciclo natural de Ansible-pull sigue pendiente: no se relanza el playbook para probar. La unidad no usa --clean ni --force: no se presupone permiso de sobrescritura de cambios de trabajo. Estas opciones tienen significados distintos en Ansible-pull; --force permite continuar tras fallo de checkout, no equivale a forzar Git.
Restauración del árbol de trabajo15:34:56 CEST¶
Se restauraron una sola vez los 16 archivos vacíos con los 270382 bytes que esperaban el HEAD y el índice existentes, ambos del commit ba701c46. No se actualizó la caché a main ni se mezclaron los ocho archivos distintos de3c662710. Los blobs antiguos también son alcanzables desde ese commit publicado. Esta operación sólo repara archivos de la caché; no sustituye los helpers más nuevos ya instalados en el sistema.
Se exigieron bootdecded74, cero procesos Git/Ansible o cmdlines ilegibles, servicio sin ejecución y timer con más de 120 s de margen. Antes de modificar se contrastaron los 16 archivos regulares vacíos root:root 0644, sus identidades, HEAD, referencias, índice y blobs esperados. Cada publicación empleó temporal exclusivo propio, fsync, rename relativo al padre y recibo durable antes de cambiar el archivo. El índice se mantuvo abierto sólo para lectura y se revalidó; no se ejecutaron checkout, reset, update-index, fetch, pull ni roles.
Respaldo privado: /root/rollback-ansible-workingtree-20261020T133456Z-1842f496141e,
directorio 0700 con 16 copias vacías y recibo 0600. El instalador tiene SHA256
<REDACTED>.
Su recibo conserva files_restored_integrity_pending y
manual_review_required=true: no se reescribió tras la verificación separada.
No hay transacción global de los 16 renames ni exclusión de un escritor root
ajeno; una interrupción exige inspección manual, sin reintento automático.
Posverificación independiente15:37 CEST¶
A las 15:37:07,454 se comprobaron 16/16 archivos y 270382 bytes contra payload, recibo, SHA del blob Git y SHA256. Todos eran regulares root:root 0644, con un solo enlace; las16 copias conservaban los vacíos originales. HEAD y origin/main seguían en ba701c46, el índice conservaba identidad y SHA256 y los metadatos de los 30 packs no cambiaron. No se modificaron refs, índice, packs, aplicaciones, configuración del servicio ni timer.
A las 15:37:07,659, Git 2.47.3 devolvió rc0 para
fsck --connectivity-only --no-dangling, sin salida, en 0,074 s. El status
--porcelain=v1 -z --untracked-files=normal dio rc0 con cero registros tracked
y cero untracked. Es una observación limpia con ese alcance normal, no un
inventario exhaustivo de todos los descendientes untracked, verificación de
todos los blobs, fsck del filesystem o prueba de salud física. El recibo y el
índice permanecieron intactos durante ambas lecturas.
Las proyecciones privadas tienen SHA256
<REDACTED>
(archivos) y
<REDACTED>
(Git). El siguiente Ansible-pull natural no está verificado; la causa de los
resets sigue sin resolver.
Primer ciclo natural recuperado15:50 CEST¶
Observación independiente15:51:02: Ansible-pull arrancó por su timer a las
15:50:00 y terminó a las15:50:51, unidad inactive/dead, Result=success y
ExecMainStatus=0. La InvocationID fue <REDACTED>.
El journal de esa invocación, 354 registros sin truncamiento observado, contiene
20 plays, 89 tareas y un recap: ok71, changed0, failed0, unreachable0,
skipped17, rescued0 e ignored0. No se arrancó manualmente el servicio.
HEAD y origin/main avanzaron naturalmente a
<REDACTED>. El status volvió a dar rc0, con
cero tracked y cero untracked en alcance normal. El índice cambió durante
esa ejecución natural; no se exige que conserve la identidad anterior a ella.
El boot continuó siendo decded74 y el timer permanecía activo. La proyección
privada tiene SHA256
<REDACTED>.
Este ciclo acredita que Git y el playbook pudieron terminar tras las dos reparaciones. Sustituye el estado pendiente de las observaciones anteriores; no acredita estabilidad física, ejecución de roles omitidos ni funcionamiento completo de todas las aplicaciones. El publicador v2 sigue sin instalar y la causa de los resets continúa abierta.
Durabilidad pendiente¶
A las15:37, Git nativo 2.47.3 no tenía configurados core.fsync ni
core.fsyncMethod. Se evalúa core.fsync=all con core.fsyncMethod=fsync:
la documentación versionada incluye los componentes Git enumerados, pero no
ofrece persistencia del árbol de trabajo ni de la configuración general.
El código de escritura del checkout no añade fsync por esa opción.
Fuentes primarias: configuración2.47.3
y escritura del checkout2.47.3.
No se escribió configuración. La opción puede añadir I/O; no se ha medido aquí
ni evita resets o repara bytes perdidos.
El primer candidato local pasó24 fixtures, incluidas nueve transacciones del helper real sobre archivos sintéticos. Entonces faltaban comprobaciones del entorno de la unidad y de la configuración Git externa efectiva; un lector preliminar seguía includes antes de rechazarlos y no sirve como evidencia. El intento de preflight real abortó en la primera guarda por cambio de boot, antes de leer configuración. El nuevo arranque15:55 mantiene retenida cualquier aplicación del candidato; no se cambió el pin para sortear la guarda.
A las16:18, la fuente completa de revisión incluye la biblioteca pura, el adaptador nativo y la transacción con baseline del fundamento efectivo. Comprueba fuentes físicas, unidad y entornos antes del Git en contexto, rechaza includes y perfiles desconocidos y relee después. No acepta una cadena declarativa como sustituto de evidencia. El parser admite archivos globales/system vacíos válidos para Git; la configuración local vacía continúa rechazada. Se reprodujeron60 pruebas en Python3.12, con revisión independiente. CI39438143984 sobre62547c9 terminó correctamente:60 pruebas en Linux Python3.10 y60 en3.12, además del plan local sin red y con hashes correctos. El wrapper sigue bloqueado antes del transporte: faltan observaciones reales, baseline fresca y revisión operativa. La nueva fuente no leyó ni modificó configuración del host y no acredita estabilidad ni durabilidad del checkout.
Recuperación y límites¶
Los vacíos guardados son evidencia del estado corrupto: no se restauran por defecto sobre objetos o archivos válidos. Si se interrumpe la operación, comprobar el boot, recibo durable, inflight, identidad y SHA Git de cada objeto antes de cualquier paso; no volver a ejecutar el instalador a ciegas ni limpiar objetos ajenos. Cualquier acción posterior exige su propio estado y plan acotado, sin reset o checkout forzado. Esta reparación no resuelve los watchdog ni acredita las bases de datos, copias, aplicaciones o restauración completa de Immich.
Lectura acreditada y fase operativa separada: 16:52 CEST¶
La omisión de EnvironmentFiles en el formato de systemctl show bloqueó la
primera lectura; no se asumió vacío. El adaptador publicado consulta únicamente
esa propiedad por D-Bus si es la única ausente y exige tipo a(sb) y lista vacía.
La lectura de las 16:46 CEST pasó con el perfil efectivo conocido. Tras revisar
su evidencia se publicó el pin explícito del boot, sin adopción automática ni
promesa de estabilidad. CI 39443185555 pasó las 78 pruebas en Linux Python
3.10 y 3.12; las mismas 78 pruebas locales y la revisión independiente pasaron.
Una única lectura posterior, a las 16:52:19.234101 CEST, desde fuentes
85779ad, confirmó el boot revisado y la coincidencia del pin nativo; observó
30 packs y HEAD 60b10c95. El recibo privado tiene SHA256
<REDACTED>.
La baseline canónica revisada tiene SHA256
<REDACTED>.
No salieron bytes de configuración ni se modificó el host.
La fase operativa explícita
usa el transporte privado
~/.local/state/git-durability-phase3-20261020-d4wbn1hr/apply.py, SHA256
<REDACTED>.
Su plan local no usa red; el intento exige recibo y baseline aprobados, fuentes
fijadas y marcador exclusivo durable. El instalador general sigue bloqueado.
La transacción revalida sus guardas antes de agregar sólo las dos opciones Git.
A las16:52 la aplicación aún no estaba acreditada: sin reintento o rollback automático, y sin
afirmar reparación del watchdog ni durabilidad de los archivos del checkout.
Aplicación acotada de durabilidad Git: 16:55:07 CEST¶
Root ejecutó una vez el transporte revisado: SSH rc0, sin stderr, con resultado
installed_local_config_verified. El recibo local tiene SHA256
<REDACTED>.
El propio helper acreditó sólo las dos adiciones locales core.fsync=all y
core.fsyncMethod=fsync, con config previo SHA256
<REDACTED>
y posterior <REDACTED>.
El respaldo privado está en
/root/rollback-ansible-fsync-20261020T145507Z-c0be5e8ec974.
La lectura independiente de las 16:56:01.381915 CEST pasó: config posterior
exactamente igual a los bytes previos más el sufijo de dos opciones; cinco
perfiles protegidos y metadatos de 30 packs sin cambios, mismo fundamento
efectivo y boot revisado. El recibo local independiente tiene SHA256
<REDACTED>.
Acreditó backup root0700, config previo0600 y recibo nativo0600, cuyo SHA256 es
<REDACTED>.
No hubo pull manual, ejecución de roles ni cambio del timer. El instalador
general permanece bloqueado.
El cambio mejora la política de sincronización de componentes Git; no demuestra
durabilidad del checkout ni corrige la causa de los reinicios.
Primer ciclo natural con fsync aplicado: 17:06–17:07 CEST¶
Una observación de sólo lectura a las 17:18:39,079758 CEST /
15:18:39,079758 UTC mantiene el boot revisado
<REDACTED_UUID>. La unidad registra inicio natural
17:06:45 y fin 17:07:31 CEST, InvocationID
<REDACTED>, Result=success, ExecMainStatus=0,
inactive/dead y MainPID=0. El timer sigue active/waiting; no se forzó su ejecución.
Tras comprobar reposo, el lector efectivo fijado a fuentes aprobadas pasó con
allow_local_targets=True: perfil conocido, configuración efectiva verificada,
core.fsync=all y core.fsyncMethod=fsync conservados. No exigió que el índice,
HEAD o packs conservaran la baseline anterior a un pull legítimo, ni afirmó que
el fundamento fuera idéntico: el hash observado después del ciclo es
<REDACTED>.
No se ejecutó status Git, fsck ni lectura de aplicaciones; esta muestra no
contiene un recap de tareas.
La duración registrada fue 46 s frente a 49 s del ciclo observado 16:49:45–16:50:34, anterior a aplicar fsync. Son dos observaciones puntuales, no un benchmark ni prueba de mejora o coste causal de fsync. El rc0 tampoco certifica estabilidad posterior, durabilidad del checkout, salud física o resolución de los resets.
Proyección privada 0600
~/.local/state/git-workingtree-restore-20261020-m9hyfrod/natural-after-fsync-151839.json,
SHA256 <REDACTED>.
No hubo escrituras de configuración, jobs manuales, sondas ni cambios de timers.