Originales: informe desconocido no equivale a colección correcta¶
Estado actual, 20 octubre 23:26:57 CEST: PR86 permanece incorporada al backend y PR87 está instalada, con rollback privado y comprobación independiente posterior a un reset natural. El primer postcheck UNKNOWN se conserva. La recogida ordinaria de las 21:15 publicó collection_success1 después de PR86; no es evidencia posterior a PR87.
Integración inicial en Git (20:37 CEST)¶
20 octubre 2026. Solo fuente desde 29f6f39; sin SSH, NAS, PBS, HTTP de apps,
jobs, alertas forzadas, secretos/configuración privada ni cambios a Vera.
Backend: scripts/original-backups/backup_originals.py. La sección final distingue
la integración inicial y la comprobación posterior del despliegue.
La PR86 se fusiona el 20 de
octubre a las 20:37:48 CEST en <REDACTED>.
La CI39476196714
termina correcta: Linux Python 3.10/3.12 y contratos de alertas con promtool.
La validación de integración repite las 100 pruebas correctas y una omisión
local; MkDocs estricto no produce avisos. En esa fase inicial el backend vivo
seguía sin sustituir:
integrar fuente no corrige todavía el comportamiento del exportador instalado.
La CI posterior39476432311
también termina correcta. La publicación documental
39476497021
acredita la revisión construida <REDACTED>.
Defecto reproducido y alcance¶
El exportador atrapaba last.json ausente/truncado como {}, devolvía rc0 y
publicaba last_success0, failed0 y first_cycle_started=hora de observación para
los cuatro grupos. Repetirlo dos días después reiniciaba esa edad otra vez:
OriginalsStale nunca vencía. El wrapper existente interpretaba rc0 como
originals_collection_success1. Esto no probaba una copia válida, pero ocultaba
el estado desconocido al criterio de colección y de primer ciclo.
Reproducción privada únicamente con datos sintéticos:
~/.local/state/originals-metrics-report-proof-20261020/proof.json (0600, padre0700).
Compara fuente base y candidata con ledger temporal ausente/truncado, reloj
simulado en dos instantes separados por172801s, /proc ficticio y configuración
simulada. No contiene datos del homelab ni credenciales.
Cambio de contrato de lectura¶
--metrics ahora devuelve rc2 y un mensaje genérico en stderr si falta el
ledger, JSON/tipos son inválidos o un manifest seleccionado no puede leerse.
La salida se acumula hasta completar toda la evaluación: no imprime métricas
parciales saludables, ceros de bytes o fechas inventadas antes de fallar.
No escribe last.json, manifests, lock o historial.
Los grupos deben pertenecer al conjunto configurado: una clave ajena no puede
aportar el ancla de los cuatro grupos reales. Un recibo de éxito exige
state=complete y completed/verified ISO válido con zona. {}, error+completed
y complete sin fecha acreditada fallan en vez de convertirse en éxito o cero.
El mismo criterio se aplica a complete en last.json. El rollover también puede
archivar complete_existing: es historial parcial legítimo, pero no aporta éxito
o fecha de verificación. Con ancla se observa como desconocimiento de éxito;
sin ancla y sin otro recibo válido produce error de colección.
Si cualquier grupo configurado carece de éxito anterior y de una fecha inicial acreditada, también falla la colección: es evidencia desconocida, no pérdida de datos ni un primer ciclo recién empezado. El ancla conserva el literal ISO con zona, o el primer started acreditado del formato legacy. No usa ahora como fallback. Todos los grupos legacy con éxito fechado siguen observables aunque no haya ancla; en ese caso omite first_cycle y la alerta usa edad del éxito.
Un ledger legítimo guardado antes de la primera copia tiene groups{} y ancla: continúa válido, con fecha estable. Grupos nuevos/parciales y complete_existing conservan compatibilidad si hay ancla acreditada. Sin ella y sin éxito son desconocidos, no sanos. No se añade una métrica huérfana o un estado persistente.
La publicación del dump ausente en recibos legacy sigue permitida. Sus tipos malformados ya no se normalizan a failed0/success0 con rc0. El test anterior que exigía ese comportamiento se divide explícitamente en ausencia compatible y corrupción desconocida; no se afloja el contrato para preservar ese test.
Wrapper y alertas, sin cambios¶
ansible/roles/observability_collector/files/pvesr-collect.sh conserva su contrato:
rc distinto de0 de la CLI remota produce únicamente collection_success0 y la
hora del intento, sin inventar métricas de grupos. El archivo Prometheus se
reemplaza como ya hacía; el backend no modifica ningún archivo Prometheus.
La salida global del wrapper sigue siendo la de PVE, no certifica originales.
OriginalsCollectorMissing ya consume collection_success0 durante15m, tanto en
scripts/original-backups/alerts.yml como en el template de alertas. No se
cambian expresiones, plazos, canales, wrapper, calendario o jobs. No se fuerza
la alerta ni se presume que vaya a recibirse una notificación real.
Despliegue: efecto potencial de publicar la fuente¶
- Backend VM208 conocido:
/home/monxas/scripts/backup_originals.py. Las fichas anteriores acreditan instalación manual/reemplazo atómico. En esta base no existe tarea Ansible que copie este backend; RunWisp solo referencia la ruta. Merge de este cambio no contiene mecanismo para reemplazarlo automáticamente. No se revalidó el binario vivo ni su hash después de los reinicios. - Wrapper: el rol observability_collector lo copia a
/usr/local/bin/pvesr-collect.shen los nodos. Play ordinario observability, sin never; main/Ansible-pull cada15m podría desplegar cambios de ese archivo. Este cambio lo conserva idéntico, igual que su cron de cinco minutos. - Tests se añaden a la matriz GitHub existente, sin nuevo job operativo. Publicar fuente solo ejecuta la CI ordinaria. El hold runtime posterior a los reinicios sigue vigente: no instalar backend, reiniciar ni ejecutar colección como smoke test por el mero merge.
Una instalación futura exige coordinar procesos/copia actual, preservar estado, reconciliar hash de destino y sustituir únicamente backend con rollback privado. No hay que borrar informes para probar un error. Rollback de fuente restaura también el blindspot; no acredita recuperación o coherencia de originales.
Verificación offline¶
test_metrics_report.py: once pruebas con ficheros privados, sin lectura de
/proc real ni configuración. Incluyen falta/truncado/esquemas, ancla constante,
éxitos legacy sin ancla, grupo nuevo desconocido, fallo con éxito previo y
manifest corrupto. Wrapper real con comandos simulados comprueba CLIrc2 →
collection_success0 y el contrato de OriginalsCollectorMissing15m existente.
Cada lectura conserva bytes/inodos de los estados locales.
Se repiten las suites existentes de backup, capacidad y configuración; las fixtures minimalistas incorporan anclas reales cuando esperan métricas válidas. No se modifica el escritor del backup ni su interpretación de recibos de copia. Resultado local: backup59 (uno omitido por transporte rsync del Mac), capacidad14, configuración17 y métricas11: 100 correctas y una omitida. La CI conserva la matriz Python3.10/3.12 existente e incorpora el test nuevo en paths y ejecución. Su resultado no demuestra validación del runtime del homelab.
Cierre acotado: compatibilidad real a las 21:10 CEST¶
La comprobación del 20 de octubre a las 21:10:04 CEST confirma VM208 en
proxmox, ejecutándose; el boot de huésped sigue siendo
<REDACTED_UUID> y el padre conserva
<REDACTED_UUID>. No es prueba de estabilidad física.
El backend instalado continúa en SHA256
<REDACTED>.
El lector consume únicamente backend, ledger y hasta siete manifests por grupo,
con límites y resolución de descriptores sin seguir enlaces sobre filesystem
local. Selecciona exactamente el patrón grupo-????????.json del backend;
la primera versión del lector sólo admitía fechas numéricas y se corrigió
antes de utilizar esta comprobación para desplegar. Los validadores extraídos
por AST de 26315bb aceptan el ledger y los tres manifests seleccionados;
existe ancla de ciclo. No se importó ni ejecutó la aplicación, no se escribió
estado ni se accedió al NAS.
La comparación AST entre el backend instalado y la fuente de PR86 acredita
que sólo difieren las declaraciones de métricas y la rama CLI --metrics.
Escritor, copia, imports y ejecución superior son iguales. Por ello el candidato
acotado es PR86 (26315bb), SHA256
<REDACTED>.
En esa intervención PR87 con fsync quedó excluida: su coste de I/O aún no
estaba medido. Su admisión e instalación posteriores se describen al final.
Recibo privado de compatibilidad (0600 en directorio0700):
~/.local/state/originals-metrics-final-uozdfeq3/compatibility.json.
SHA256 del recibo: <REDACTED>.
Esta lectura cambia la decisión de compatibilidad, pero no acredita una
instalación; no se ejecutan jobs ni se fuerza el colector como prueba.
Instalación real de PR86 a las 21:13 CEST¶
El backend se sustituye el 20 de octubre a las 21:13:22 CEST por el
candidato PR86 exacto de 26315bb. Se acredita el hash nuevo f33f1b…6651,
propietario root:root, modo0755, enlace único y 37422 bytes. No se instala la
PR87 ni se ejecuta la aplicación para comprobarlo.
El instalador conserva el lock existente con flock exclusivo, comprueba dos veces ausencia de escritores y hace CAS del inode, nueve campos de identidad y hash del backend antes del reemplazo. Recibos de propietario PVE antes y después y boot del huésped coinciden con la comprobación de compatibilidad. Se conserva el estado: ledger y tres manifests, cuatro archivos de control, coinciden en bytes e identidad antes/después. No se escribe configuración, se reinician servicios ni se ejecutan copias, productor o colector.
Antes de ejecutar el instalador, el preflight inicial abortó: exigía por error
root:root al lock, cuyo propietario histórico y vivo es1000:1000. Se corrigió
esa condición sin modificar la exigencia root:root del backend, y otro agente
revisó el diff. Un intento del lanzador local tampoco llegó a ejecutar el
instalador por la licencia Xcode pendiente de /usr/bin/python3 del Mac;
la lectura posterior confirmó backend antiguo intacto. Se usó el Python
operativo de la sesión. No se aceptó ni modificó ninguna licencia del sistema.
Rollback local privado en VM208:
/root/rollback-originals-metrics-20261020T191322Z-8codc05m/backend.before.
Directorio0700, archivo0600 root:root y hash antiguo completo verificado.
El recibo hermano receipt.json acredita fase installed, reemplazo confirmado,
sin aplicación ejecutada y sin revisión manual pendiente. No se ejecuta rollback:
restaurarlo reintroduciría el defecto de métricas y exige nueva reconciliación.
La lectura independiente posterior confirma backend, controles y rollback.
Recibos locales privados:
~/.local/state/originals-metrics-install-drevdm52/.
SHA256 de postverify-independent.json:
<REDACTED>.
La compilación nativa y los hashes prueban instalación; el comportamiento
ordinario del colector requiere su siguiente ejecución normal. Ningún recibo
acredita que las copias, NAS, hardware o restauración de Immich estén resueltos.
Recogida ordinaria posterior, 21:15 CEST¶
Prometheus CT217, con propietario fresco en proxmox2 y boot del observador
sin cambios, contiene a las 21:15:37 CEST una muestra de las21:15:29.666.
Los timestamps del productor y del intento son 21:15:02 CEST, posteriores
al reemplazo21:13:22. originals_collection_success=1 y process_running0.
No se ejecutó el colector manualmente: se consultó su resultado ya almacenado.
La lectura anterior21:15:02 aún contenía productor21:10:01 y se descartó como
prueba de recogida posterior; una muestra reciente no equivale a productor nuevo.
Recibo privado:
~/.local/state/originals-metrics-postdeploy-collected-eegsmz77/projection.json,
SHA256 <REDACTED>.
Acredita compatibilidad de la colección ordinaria con registros válidos. El
rechazo de corrupción se probó offline; no se corrompió el ledger de producción.
Siguen firing en la selección consultada PBSDataReserveLow, nas_nfsd_dstate_degraded, OriginalsCopyFailed y OriginalsDumpPublicationRequired. No se presenta este despliegue como reparación de esos cuatro problemas, prueba de entrega de alertas o recuperación del hardware/NAS/Immich.
Actualización posterior: PR87 instalada a las 23:23:47 CEST¶
El backend se actualiza una única vez de PR86 f33f1b…6651 a PR87
<REDACTED>,
root:root, modo 0755, enlace único y 41366 bytes, sin ejecutar el backend, jobs ni
colector. Preflight fresco, lock existente, dos scans sin escritores y CAS
protegen el reemplazo; controles del estado y propietario/boots se conservan
durante esa instalación, antes del reset posterior.
La corrección de métricas de PR86 permanece; este cambio añade durabilidad al
writer y tratamiento explícito del checkpoint incierto.
La admisión previa de las 23:21:23 usa tres muestras sintéticas de 64 KiB en un sibling local del mismo dispositivo: dos fsync cada una, totales 6,226 / 9,883 / 6,810 ms, cleanup propio confirmado, sin NAS ni lectura de contenidos del estado. No es prueba de picos, resets, recuperación de almacenamiento o estabilidad física. El informe de cancelación conserva los hashes completos de instalación/admisión y los límites.
Rollback privado:
/root/rollback-originals-checkpoint-20261020T212347Z-lq5gdmmk/backend.before.
Recibo ~/.local/state/originals-durable-checkpoint-install-ofk29bx3/install-result.json,
SHA256 <REDACTED>.
El primer postcheck quedó UNKNOWN al fallar el guard del padre tras el
reset natural de las 23:24:41 CEST, sin llegar a leer el huésped. Se conserva
postverify-aborted.json, SHA256
<REDACTED>.
No se repite la instalación. VM208 completó su arranque automático a las 23:25:20 CEST;
boots nuevos: padre <REDACTED_UUID>, huésped
<REDACTED_UUID>.
La única lectura independiente posreset de las 23:26:57 CEST confirma
backend PR87 exacto, identidad instalada (inode 829863), rollback PR86 y su
recibo fase installed, lock y cuatro controles intactos en bytes/identidad;
diferencias vacías. Recibo postreset-independent.json en el mismo stage,
SHA256 <REDACTED>.
No se importa/invoca la aplicación, métricas, jobs, NAS ni escrituras.
Sólo acredita persistencia observada del archivo tras este reset natural:
no prueba picos/checkpoints de copia real ni causalidad fsync/reset. El mecanismo
watchdog está acreditado, pero la causa del keepalive perdido sigue desconocida.
La muestra ordinaria 21:15 anterior sólo acredita PR86; no se fuerza recogida.