Skip to content

Copias, capacidad y recuperación: aplicación 19 octubre 2026

Revisión/aplicación posterior a review-next-backups-20261019.md, alrededor de 22:28–22:35 CEST. Usuario autorizó aplicar las mejoras con agentes simultáneos. No se ha interrumpido ni relanzado la copia de originales; no se ejecutó scrub, no se borraron generaciones y no se modificó la autenticación del NAS.

Aplicado y verificado

  • backup_originals.py publica --metrics: éxito y antigüedad por los cuatro grupos, actividad observada, estado, muestras, reserva y bytes de E/S del proceso. Estos últimos son E/S del proceso, no bytes de archivos verificados ni un porcentaje fiable. El observador reconoce también la transferencia antigua.
  • Cliente mantenido: escritura atómica privada del estado, heartbeat cada10s, progreso E/S, error persistido sin argumentos/rutas privadas y lock ocupado identificado mediante skipped_locked/exit75. El mismo lock protege el cliente y la continuación ya en espera. Un timeout abrupto puede impedir persistir el error: la alerta de proceso ausente cubre ese caso.
  • Muestreo futuro: tres archivos diarios rotativos más un archivo grande de hasta 4GiB si existe candidato. SHA256 completo en origen/destino y restauración aislada completa; ya no se eligen siempre los primeros nombres. El límite evita que una muestra agote los41GB libres observados en VM208. Un archivo vivo cambiante hace fallar la validación y conserva staging; no se publica como bueno.
  • Colector existente pvesr-collect.sh, mismo cron cada5min: pmx51 observa VM208 vía acceso SSH ya existente; pmx50 consulta statvfs de CT186. No se añade cron, daemon, base de datos ni plataforma. VM208 tiene textfile deshabilitado: se reutiliza el textfile existente de los hosts Proxmox.
  • Ocho alertas añadidas a Prometheus existente: colector ausente/fallido, transferencia detenida, error, frescura de originales, reserva de originales, reserva PBS, proyección PBS y colector de capacidad PBS. Primer ciclo de originales tiene24h de gracia; después se exige éxito dentro de48h por grupo. PBS avisa con menos de64GiB o15% libres. Proyección a14d usa7d de datos y no actúa hasta disponer de3d de muestras. No cambia rutas ni receptores de avisos.
  • promtool check rules confirma81reglas válidas. Prometheus recoge los dos colectores con valor1; no había alertas nuevas activas. Diecisiete tests locales pasan: nueve del receptor restringido y cinco del cliente y tres del verificador nativo Paperless.

La copia inicial y su continuación ya habían cargado código antiguo antes de esta aplicación. No adquieren retroactivamente el heartbeat/muestreo nuevo; sí son observadas pasivamente por las métricas nuevas. El cliente instalado y la tarea RunWisp diaria existente usarán las mejoras en invocaciones posteriores.

Ensayo PBS real cerrado

Coordinado con el responsable RAM antes de iniciar, para evitar medir N-1 durante el ensayo. Ejecutado directamente el motor común en pmx50, sin wrapper de avisos:

python3 /usr/local/bin/pbs_restore_drill.py lxc --target 123

Resultado: status=ok, isolated=true,22s. Restauró la copia reciente de CT123 (~828MB comprimidos), eliminó red/mounts/hooks/dispositivos del invitado temporal, arrancó con512MiB/1core y comprobó estado running. Eliminación posterior confirmada: config9901, volúmenes9901 y lock de cluster ausentes. Producción no se modificó. Esto acredita ese arranque aislado desde PBSmain, no el funcionamiento completo de todas las aplicaciones ni de los originales NFS.

Estado y retención conservadora

  • main: aproximadamente179GiB disponibles,63%usado; daily2/weekly1.
  • archive:229GiB disponibles,85%usado; daily7/weekly8/monthly12.
  • GC/prune/sync y verify recientes ya habían finalizado correctamente.
  • Se conserva esa política; no se recorta la historia por el porcentaje aislado. Las métricas nuevas permiten medir tendencia y alertan antes de agotar reserva.
  • Originales: una primera generación; documentos/proyectos completos, fotos copiándose y pics pendiente en continuación. No hay generaciones anteriores elegibles para poda segura. Se conserva todo y la reserva64GiB bloquea nuevas copias según el presupuesto estimado, sin garantizar espacio real frente a todos los layouts o cambios concurrentes (véase revisión de estimación abajo). No se ha instalado una poda automática: habilitar borrado con la clave de escritura ampliaría sus permisos sobre las generaciones completadas. Su restricción actual se mantiene.
  • Para una poda futura: exigir al menos dos generaciones completas verificadas, preservar las dos últimas buenas y la base diaria/semanal/mensual elegida, ejecutar primero inventario/estimación de bloques realmente recuperables, conservar parciales de fallo para revisión y comprobar restauración antes de retirar historia. No usar suma de tamaños aparentes de hardlinks como ahorro.

No se confunde la antigua sincronización pics con una copia acreditada actual: la línea nueva tiene generaciones distintas. No se contrata ni se presupone un destino offsite.

Recuperación de aplicaciones: Paperless verificado, Immich pendiente

Corrección verificada a23:03CEST: Immich v3.2.0 tiene14dumps nativos *.sql.gz bajo photos/backups,2.570.127.148bytes en total; último19oct00:00:31UTC, 184.550.835bytes, CRC gzip correcto. El recuento anterior incluía un sentinel de13bytes y atribuía su mtime a un dump. Ese directorio forma parte de la fuente de fotos en curso. DB runtime: Postgres16 con imagen vectorchord0.4.3/pgvectors0.2.0. Originales y biblioteca externa necesitan, respectivamente, los grupos photos y pics. Paperless usa Postgres17; media/consume están bajo documents, data/export y BD están en VM208. La copia de media sola no equivale a exportación recuperable.

Procedimiento de recuperación: para Immich esperar photos/pics completos; Paperless puede usar su exportación nativa con documents ya completo (ensayo ejecutado y detallado debajo):

  1. Confirmar manifiestos publicados y frescura; comprobar CRC del dump Immich elegido y obtener imagen/digest exactos, sin exportar env/credenciales.
  2. Asociar el dump a su generación de archivos. La copia rsync en caliente no constituye por sí sola un punto transaccional entre BD y archivos; ante cambios concurrentes se necesita una ventana coherente o snapshot coordinado.
  3. Paperless: preparar exportación nativa a un directorio nuevo privado; preservar usuarios, metadatos, originales y manifiesto. No sobrescribir exportaciones anteriores ni usar opciones de borrado sobre producción.
  4. Restaurar en espacio temporal independiente, sin IP pública/red compartida, sin montar NFS de producción con escritura y sin tocar bases vigentes. Dimensionar RAM/espacio y coordinar antes de arrancar otros servicios de prueba.
  5. Importar en una BD vacía del mismo tipo/versiones; verificar conteos y una muestra de originales/documentos abriendo su contenido. Eliminar únicamente recursos temporales identificados como propios; conservar evidencia del fallo.

El ensayo completo de Immich no se declara ejecutado: fotos/pics siguen pendientes. Paperless sí se ha exportado e importado de forma aislada como se detalla debajo. No se ha parado ninguna aplicación para forzar una copia durante la transferencia.

Fuentes oficiales: Immich backup/restore y Paperless administración/exporter.

Recuperación de la configuración

  • VM208 cliente anterior: /home/monxas/scripts/backup_originals.py.before-observability-20261019.
  • Ambos hosts colector anterior: /usr/local/bin/pvesr-collect.sh.before-originals-20261019.
  • CT217 reglas anteriores: /home/monxas/appdata/prometheus/alerts.yml.before-originals-20261019.
  • Revertir solo grupos nas-originals/pbs-capacity, validar con promtool y recargar Prometheus mediante HUP. No sobrescribir otras reglas cambiadas después.
  • La reversión no borra copias, manifests, staging ni cambia calendarios RunWisp.

Corrección tras publicación: entorno cron del colector

El coordinador detectó PBSDataCapacityCollector pending tras publicar: bajo cron, el nuevo bloque ejecutaba pct sin /usr/sbin en PATH. La primera validación interactiva había dado1 pero no cubría cron. Se reprodujo con entorno mínimo: timeout devolvía127 por herramienta ausente. /datastore y /archive existían correctamente en CT186; no era un fallo del almacenamiento.

Se añadió al inicio del colector export PATH=/usr/sbin:/usr/bin:/sbin:/bin, desplegado en ambos hosts y publicado por el coordinador en 515801a. Prueba exacta con env -i HOME=/root PATH=/usr/bin:/bin /bin/bash …: capacidadPBS1, originales1 y réplicas presentes en el nodo con jobs origen. En pmx50 sin jobs origen es correcto que pvesr.prom solo tenga las cabeceras. Tras el siguiente scrape Prometheus devuelve ambos colectores1 y ninguna alerta Originals/PBSData.

Paperless: exportación nativa y restauración aislada desde cero

Cerrado alrededor de22:49CEST. Producción3.3.2,146documentos. Exportación nativa nueva privada en VM208:400archivos/84.596.701bytes, batch25, un CPU y límite virtual 512MiB solo al proceso exportador; conexión PostgreSQL con PGOPTIONS read-only. Una primera carpeta vacía falló por permisos y quedó preservada; la exportación buena no sobrescribe ninguna anterior. Producción siguió running/healthy/OOMfalse.

Bundle privado: /home/monxas/appdata/paperless/export/recovery-20261019T203532Z. Copia independiente del NAS en CT218: /root/paperless-recovery-20261019T203532Z/input. El verificador mantenido paperless-verify-export.py comprueba todos los originales contra checksums del manifiesto y produce únicamente conteos/hash agregado.

Ensayo final de la fuente mantenida paperless-recovery-drill.py desde destinos vacíos, no reparación de una importación previa: migraciones SQLite, importador nativo, reconstrucción del índice, lectura/validación. EntradaRO, directorios temporales propios, usuario1000, cap-dropALL/no-new-privileges, filesystem raízRO, sin puertos y sin credenciales de conexión a producción. Se omite /init para no iniciar workers/web/supervisor. El fixture crea explícitamente el directorio del índice y emplea Redis efímero en el mismo namespace networknone:768+64MiB, sin swap adicional, CPU conjunto1. No hay acceso al NAS ni a la BD de producción.

Imagen de origen 48c4b518…, destino b20d8cd1…: Docker de origen y destino representan los IDs con formatos diferentes. Antes de ejecutar se compararon RootFS, Config, arquitectura y OS idénticos, no solo tag3.3.2/latest. SHA256 canónico RootFS: <REDACTED>; Config: <REDACTED>.

Cobertura Exportado Restaurado
Documentos y originales con checksum completo 146 146
Tags 44 44
Corresponsales 14 14
Tipos documentales 9 9
Notas 37 37
Usuarios exportados 3 3
PDFs abiertos y páginas comprobadas — 3

Guardian crea además su usuario AnonymousUser durante las migraciones. El validador exige los tres PK de usuarios exportados y permite únicamente ese usuario generado; cualquier otro extra falla. No se excluyó una diferencia sin explicarla: la tabla tiene cuatro usuarios, tres restaurados y uno generado.

SHA256 agregado de todos los originales, ordenados porPK, idéntico en export e import: <REDACTED>. Se abrieron3PDF con pikepdf y páginas no vacías, sin publicar su contenido. La prueba comprueba importación, datos, archivos e índice; no incluye login/UI ni integraciones externas, precisamente porque la red del fixture está aislada.

Tentativas previas expusieron requisitos del fixture: Redis para migraciones, UID1000 para leer el bundle privado y directorio de índice al omitir /init. No hubo OOM. Una validación provisional detectó el AnonymousUser antes de ajustar la comparación a usuarios exportados. La ejecución final pasó desde cero con la fuente final completa; no se declara reproducible basándose solo en reparar un directorio parcialmente importado.

Limpieza confirmada: los dos contenedores de la ejecución buena se eliminaron; se retiraron otros siete contenedores propios de pruebas detenidas y la imagen importada2,5GB. No queda contenedor homelab.recovery, daemon ni namespace de prueba activo. Redis previo de producción no cambió. Se mantienen bundle/input, SQLite/media restaurados, resultados y logs privados bajo el directorio del ensayo. El bundle ya es una copia independiente del NAS; aún no se ha publicado como nueva línea Synology ni como exportación nativa diaria automática. No se amplían permisos de su clave ni se contamina una generación originals completada.

La fuente del drill y el verificador están versionados para repetir el ensayo. Los resultados privados contienen la evidencia detallada sin copiar documentos, nombres personales, URLs privadas ni contenido a este informe.

Estimación y observación de capacidad: candidato20oct sólo en fuente

El preflight anterior usaba bloques du -sk: podía infravalorar ficheros sparse que rsync copia sin -S y aliases hardlink que rsync copia sin -H. Una fixture local de64MiB sparse más dos rutas al mismo fichero de1MiB contabilizaba1MiB, frente66MiB lógicos por ruta. No se transfirió ni examinó ningún dataset real.

El candidato recorre metadatos una sola vez, con DFS por FD y sin seguir enlaces; suma max(st_size, st_blocks*512) por entrada, incluidos directorios/symlinks y cada alias hardlink. Detecta ciclos de directorios entre ancestros; conserva sólo FDs/iteradores proporcionales a la profundidad y los cierra al fallar o cancelar. No otorga ahorro por --link-dest, no añade -H/-S ni modifica el receptor. No hay caps nuevos de número, profundidad o tiempo: conserva el timeout de tarea y observa cancelación TERM/INT/HUP entre operaciones. Si falla parcialmente la instalación de handlers, restaura los anteriores bajo máscara bloqueada antes de recuperar la máscara previa. Un syscall bloqueado en kernel no tiene una nueva garantía de terminación inmediata.

Es una estimación según el origen, no una cota exacta del espacio del destino: no se conocen aquí su granularidad de asignación, metadatos, compresión o cambios concurrentes. Se mantiene la reserva64GiB. La suma de tamaños de generaciones hardlinked tampoco mide ahorro físico liberable; no autoriza poda ni garantiza capacidad sostenida. Generaciones completas, última buena e incompletas conservan su política anterior: no se elimina nada.

Cada intento marca capacity_known=false antes de prepare. Tras obtener una estimación válida y espacio disponible entero no negativo, persiste ambos bytes, capacity_known=true, timestamp UTC y política antes de rechazar por reserva. Así la copia fallida conserva el dato que la rechazó. Un cero real puede ser conocido; datos ausentes/erróneos no se convierten en estimación0. La métrica aditiva originals_capacity_known no se reconstruye desde manifiestos legacy ni se hereda accidentalmente al fusionar su evidencia. No altera las métricas de configuración/histórico de publicación ni el reloj del primer ciclo.

La fuente de OriginalsDestinationReserve se adapta en snippet y plantilla: usa originals_capacity_known == 1 y compara disponible menos estimación con la reserva64GiB. Mantiene los15min y el mismo nombre/severidad; un cero conocido avisa, uno desconocido no inventa una medida. La ausencia del indicador nuevo tampoco se interpreta como observación válida. El backend anterior y los estados legados no aportan este indicador: publicar la fuente no acredita cobertura runtime hasta coordinar instalación/lectura natural de backend y consumidor.

Validación local:14 casos de estimación/observación,56 tests backend (uno omitido en Mac por GNU rsync),17 de configuración,3 contratos de alerta y8 escenarios Promtool correctos. Promtool valida las91reglas. Los escenarios cubren cero real, desconocido/ausente, umbral exacto, un byte por debajo, margen amplio, grupos incompatibles y recuperación. La CI incorpora el nuevo test de capacidad y los fixtures de alerta. Sin copia, poda ni despliegue runtime en esta fase.

Instalación de capacidad del20oct13:33–13:35 CEST

La fuente anterior quedó publicada y sus cinco comprobaciones CI terminaron correctamente, incluidas las pruebas Linux Python3.10/3.12. A13:33:46 se instaló únicamente backup_originals.py en VM208, SHA256 <REDACTED>, con root:root0755. Se adquirió el lock existente sin crearlo ni truncarlo y se compararon identidad y hash antes de reemplazar. Respaldo privado: /root/rollback-originals-capacity-20261020T113346Z-aqoavdtk.

La doble lectura posterior13:34:44 acredita el mismo archivo instalado y los 13 archivos regulares inmediatos de estado, incluido el lock, sin cambios frente al preflight. No se recorrieron subdirectorios. La configuración RunWisp conserva identidad y SHA256 <REDACTED>. Compilación nativa correcta; sólo se probaron los caminos de despacho seguros: help→0, argumento desconocido→2 y mezcla metrics/status→2. No se invocaron metrics, status, estimación, copia, publicador o retención durante la instalación.

A13:35:02 se sustituyó sólo la expresión de OriginalsDestinationReserve en CT217, propietario revalidado proxmox2. Las otras90reglas conservan su semántica. Promtool nativo valida91reglas; una recarga local devuelveHTTP200, sin reinicio. El archivo conserva inode1029537,1000:1000 y0664, y el contenedor conserva ID y bind de sólo lectura. SHA256 final de alerts.yml: <REDACTED>. Respaldo privado /root/rollback-originals-capacity-alerts-20261020-11fr6ie0. La escritura conserva el inode requerido por el bind: no es una sustitución atómica ante caída durante escritura. No hubo reintento ni rollback automático.

La primera posverificación agregada terminó incompleta (exit2): el wrapper suprimía el diagnóstico remoto. No se pudo atribuir la causa y no se repitieron instalación ni reload. Una lectura instrumentada independiente13:42:47 y13:43:07 pasó las mismas precondiciones, sin relajarlas: archivo e identidad intactos, contenedor/bind esperados,91/91reglas health=ok y dos evaluaciones distintas de las cinco reglas seleccionadas. Reserva y cuatro reglas de publicación están inactive/sin error. OriginalsCopyFailed figura pending con una alerta activa: no se declara resuelto el fallo de copia de11:10 ni verde global.

La observación exportada es13:40:02; su edad es166–186s en esas lecturas (el sample timestamp de una consulta instantánea no prueba la fecha del scrape). Colección=1, proceso=0, configuración conocida=1/habilitada=1. Las cuatro series originals_capacity_known están presentes y valen0. Los estados legacy no aportan una medida de capacidad nueva hasta un intento real posterior; reserva inactiva en este estado no acredita margen libre del NAS.

Recuperación: comprobar runtime y backups contra los hashes registrados y usar los locks/identidades originales antes de restaurar sólo el archivo afectado. No revertir estados, configuración ni horarios. No se ha acreditado una copia incremental real tras corregir el receptor ni una publicación diaria exitosa.

Publicador: cancelación y propiedad de procesos (fuente, 20 octubre)

Una fixture local sintética reprodujo que SIGHUP terminaba el padre (exit -1) y dejaba vivo su hijo de transferencia: el scope anterior sólo capturaba TERM. La corrección fuente cubre TERM/INT/HUP, conserva salida no cero y restaura handlers/máscara incluso ante instalación parcial. Durante spawn registra la cancelación hasta asignar el hijo; no bloquea la máscara heredada por el hijo ni usa preexec_fn. El cleanup acotado TERM/KILL/reap actúa sólo sobre el grupo creado por esta invocación; señales repetidas no lo interrumpen ni convierten un fallo anterior en éxito. Una primera señal durante cleanup tampoco devuelve éxito. Sin pthread_sigmask o fuera del hilo principal se rechaza antes de publicar o lanzar un hijo, sin fallback desprotegido.

Validación:46 tests del publicador, incluidos procesos reales sintéticos para las tres señales, grupo ajeno intacto, handoff y transiciones de handlers;56 backend (uno omitido en Mac por GNU rsync) y17 configuración correctos. No se ejecutaron transferencias, jobs ni accesos NAS. Sigue sin garantizar cleanup ante SIGKILL, fallo del kernel o proceso en D-state; no acredita cancelación de trabajos ya iniciados en un servidor remoto. Este cambio no altera retención, históricos, configuración de publicación ni límites de captura de stdout. Fuente revisada por pares y publicada en main0a3a85f. Su CI Linux Python3.10/3.12 y contratos PBS termina correctamente: 39417996724. Las pruebas sintéticas no acreditan una publicación real.

Publicador instalado y verificado,20oct13:53–13:54 CEST

A13:53:35 se reemplazó sólo /home/monxas/scripts/immich-dump-publisher.py en VM208, preservando root:root0644. SHA256 final: <REDACTED>. El baseline9063a799 coincidía con la fuente anterior. Se adquirió el lock de originales existente sin crear/truncar y no se observaron procesos conocidos de copia/publicador/lectores ni cmdlines ilegibles durante la instalación. Respaldo privado: /root/rollback-originals-publisher-cancellation-20261020T115335Z-rxeaw9oc.

La lectura independiente13:54:09 confirma el archivo exacto contra el recibo, 19810bytes y un enlace; backup9063a799 regular root:root0600 dentro de directorio root0700. Compilación nativa correcta en instalación; no se ejecutó ni importó el publicador, tampoco su CLI. Las dos lecturas posteriores confirman los 13archivos de estado inmediatos, incluido lock, y RunWispf7b3a3ad idénticos al preflight y recibo. No se recorrieron subdirectorios ni se llamó al NAS.

Recuperación manual: bajo el mismo lock y sin copia/publicador activo, comprobar hash instalado3d704db2 y backup9063a799 antes de restaurar únicamente publisher.before al destino mediante temporal y rename, preservando root:root0644. No restaurar estados, recibos de copias, configuración ni horarios. No se reintentó el instalador ni se ejecutó rollback automático. Primera publicación diaria y siguiente incremental real siguen pendientes de ejecución natural.

Fallo de una ejecución y propiedad del informe,20oct14:11 CEST

Una reproducción local con dos procesos y dos descripciones de archivo demostró una carrera: run_backup soltaba su flock al propagar una excepción, y el catch de main leía después last.json sin ese bloqueo. El siguiente propietario podía entrar y guardar copying/pending antes de que el anterior marcase su informe como error. No se ha acreditado un incidente real con ese resultado.

El candidato8581a6dc persiste el fallo antes de liberar el mismo flock adquirido por esa ejecución. Usa su informe local sólo después de activar su primer guardado; no relee el informe del sucesor ni intenta adquirir un bloqueo nuevo. Los fallos anteriores a la adquisición/activación y LegacyHistoryError no reescriben estados anteriores. La salida75 por bloqueo ocupado y los caminos CLI de lectura se conservan. Cancelaciones mantienen su clase y registran el fallo bajo ownership; sólo se guarda la clase de error, sin texto ni argv.

La prueba de dos propietarios falla con la fuente anterior y pasa con el candidato: el sucesor conserva su propio flock y su informe intacto, y observa el fallo del anterior ya persistido al entrar. Validación local y revisión independiente:58tests backend (uno omitido en Mac por GNU rsync),14capacidad, 17configuración y46publicador correctos, más gramática Python3.10. Sin red, NAS, copias o publicaciones reales. Instalación y CI Linux se acreditarán separadamente; esta prueba no certifica la siguiente copia incremental.

Instalación y verificación20oct14:40 CEST

Fuente publicada en main y CI Linux de copias correcta 39423177307. Instalación acotada14:40:11: backend8581a6dc, root:root0755, compilación nativa correcta y dispatch permitido0/2/2 (help, argumento desconocido y conflicto metrics/status; no se ejecutó ninguno de esos lectores ni una copia). El instalador retuvo el flock existente y verificó identidad/hash completos antes del reemplazo. Copia previa a09097db en /root/rollback-originals-failure-lock-20261020T124010Z-g18yej0g/backend.before, 0600 y directorio0700; recibo instalado sin revisión manual pendiente.

Verificación independiente14:40:51: archivo instalado idéntico al candidato y al recibo, 13 archivos de estado —incluido el lock— y RunWisp idénticos a la referencia en dos lecturas. Digest agregado de estados <REDACTED>; configuración RunWisp siguef7b3a3ad. Evidencia privada de posverificación SHA256 <REDACTED>. No se ejecutaron copias, publicadores, métricas/status del backend ni accesos NAS. La siguiente incremental y primera publicación diaria conservan su verificación pendiente; instalar este arreglo no convierte el fallo anterior en éxito.

Recuperación manual: comprobar el recibo y la identidad/hash actuales8581a6dc, sin escritor activo y bajo el mismo lock, antes de restaurar únicamente backend.before mediante temporal y rename, root:root0755. No restaurar estados, configuración ni horarios. Sin reintento o rollback automático.

Publicador v2 instalado sin ejecución: 20 octubre 17:32–17:33 CEST

La fase de identidad v2 ya está instalada: sólo el helper pasó de 3d704db2… a a3acd931… a las 17:32:26, con verificación independiente a las 17:33:50. Root:root0644, compilación sin ejecutar y backup privado acreditados. Backend 8581a6dc…, RunWisp f7b3a3ad…, trece archivos de estado, incluido el lock quedaron intactos. No se disparó publicación, copia, CLI o consulta NAS. El fallo real de las 11:10 fue anterior al hook y su corrección de receptor no se reintentó. Primera publicación y siguiente incremental real siguen pendientes; no se modifica ni se declara resuelta la alerta Required por instalar código.