Requisitos — Py-PDF-Compare

Requisitos Fase 1 · 1.1 · Versión 3 · Generado: 2026-08-17 09:28 CEST · Vista generada el 2026-08-17 · El .md es la fuente de verdad

30Requisitos funcionales
12No funcionales
7Fuera de alcance
33 dEsfuerzo estimado (11 items)
1Bloqueantes
7Preguntas abiertas
Documento de Fase 1 (AIDD · paso 1.1). Generado por aidd requirements.
Entrada: no existe docs/cliente-requisitos.md — requisitos derivados por ingeniería inversa del código, el README.md y el workflow de CI. Salida hacia: docs/mapa-historias-usuario.md.
Alcance: estado actual (as-is). Este catálogo formaliza lo que el producto ya hace; toda evolución posterior entra como change de AISDD.
Pendiente de aprobación humana.

#1. Descripción del sistema y objetivos

Py-PDF-Compare es una herramienta de escritorio y línea de comandos que compara dos ficheros PDF y genera un informe PDF de diferencias, con las dos versiones enfrentadas lado a lado y las diferencias de texto resaltadas por color.

Problema que resuelve: revisar qué ha cambiado entre dos versiones de un documento PDF sin depender de herramientas comerciales, sin subir el documento a ningún servicio externo y sin perder la calidad del original.

Objetivos medibles (derivados del comportamiento actual):

  • O-1 — El informe conserva el contenido vectorial de los originales: el texto del informe sigue siendo seleccionable y buscable.
  • O-2 — El informe evita la rasterización: el tamaño de fichero resultante es entre 20 y 70 veces menor que el del enfoque basado en imágenes que sustituyó (pdf_compare/config.py).
  • O-3 — La instalación no requiere dependencias nativas externas al ecosistema Python (sin Poppler ni binarios de sistema).
  • O-4 — El producto es consumible por tres vías con el mismo núcleo: aplicación de escritorio, CLI y librería Python.

#2. Usuarios y roles

El sistema no tiene autenticación ni control de acceso: es una herramienta local monousuario. Los "roles" son perfiles de uso, no permisos.

RolDescripciónInterfazPermisos / responsabilidades
Usuario de escritorioPersona que compara dos documentos de forma puntual y visualGUI (pdf-compare-gui)Selecciona ficheros, lanza la comparación, previsualiza, descarga o abre el informe
Usuario de CLI / automatizaciónPersona o script que integra la comparación en un flujo por lotes o en CICLI (pdf-compare)Pasa rutas de entrada y salida, interpreta el código de salida del proceso
Desarrollador integradorProgramador que embebe la comparación en otra aplicaciónAPI Python (PDFComparator) o submódulo gitInstancia el comparador, consume los bytes del informe y decide su persistencia
MantenedorResponsable del repositorio y de las publicacionesGitHub Actions, PyPIVersiona en pyproject.toml, dispara release de binarios y publicación en PyPI

#3. Requisitos funcionales

Prioridad orientativa: A (nuclear, define el producto), M (relevante), B (accesorio).

3.1 Núcleo de comparación

IDRequisitoActorPrio
RF-01El sistema debe comparar dos ficheros PDF (original y modificado) y producir un informe PDF con ambos enfrentados lado a lado, página a páginaTodosA
RF-02El sistema debe alinear las páginas por similitud de contenido textual, no por número de página, de modo que un desplazamiento de páginas no se interprete como cambio masivoTodosA
RF-03El alineado debe clasificar cada pareja de páginas como equivalente, sustituida, insertada o eliminada, explorando páginas siguientes para encontrar la correspondencia realTodosA
RF-04Una página presente solo en el original debe aparecer en el panel izquierdo etiquetada como ausente, con el panel derecho en blancoTodosA
RF-05Una página presente solo en el modificado debe aparecer en el panel derecho etiquetada como añadida, con el panel izquierdo en blancoTodosA
RF-06El sistema debe resaltar las diferencias a nivel de palabra, localizándolas por su caja delimitadora en la página: rojo para lo eliminado sobre el original, verde para lo añadido sobre el modificadoTodosA
RF-07Cuando la página del original y la del modificado no ocupan la misma posición, el informe debe señalarlo visualmente como página desplazadaTodosM
RF-08Cada panel debe llevar una etiqueta con su origen (original / modificado) y el número de página correspondiente en su documentoTodosM
RF-09El informe debe construirse insertando el contenido vectorial de las páginas originales, sin convertirlas a imagenTodosA
RF-10El sistema debe detectar que no existen diferencias entre ambos documentos e informar de ello al usuario en lugar de entregar un informe sin valorTodosM
RF-11El sistema debe ofrecer, en la API, una comparación textual en formato unified diff entre el contenido de ambos documentosDesarrollador integradorB

3.2 Interfaz de línea de comandos

IDRequisitoActorPrio
RF-12La CLI debe aceptar la ruta del PDF original y del modificado como argumentos posicionales obligatoriosUsuario de CLIA
RF-13La CLI debe permitir indicar la ruta del informe de salida mediante una opción, con un valor por defecto cuando se omiteUsuario de CLIA
RF-14La CLI debe validar que ambos ficheros de entrada existen antes de procesar y terminar con error y mensaje explícito si alguno faltaUsuario de CLIA
RF-15La CLI debe informar del progreso y, al terminar, del tamaño del informe generadoUsuario de CLIB
RF-16Ante un fallo durante la comparación, la CLI debe informar del error y terminar con código de salida distinto de cero, para poder encadenarse en scriptsUsuario de CLIM

3.3 Aplicación de escritorio

IDRequisitoActorPrio
RF-17La aplicación debe permitir seleccionar cada documento mediante un diálogo del sistema filtrado a ficheros PDFUsuario de escritorioA
RF-18La aplicación debe impedir lanzar la comparación si falta alguno de los dos documentos, avisando al usuarioUsuario de escritorioM
RF-19La comparación debe ejecutarse sin bloquear la interfaz, mostrando un indicador de progreso mientras duraUsuario de escritorioA
RF-20La aplicación debe previsualizar el informe generado dentro de la propia ventana, página a página y con desplazamiento verticalUsuario de escritorioA
RF-21La aplicación debe permitir descargar el informe a la carpeta de descargas del usuario, resolviendo su ubicación real en cada sistema operativo y sin sobrescribir ficheros previosUsuario de escritorioM
RF-22La aplicación debe permitir abrir el informe con el visor de PDF por defecto del sistema operativoUsuario de escritorioM
RF-23La aplicación debe permitir guardar el informe en una ubicación elegida por el usuario mediante diálogoUsuario de escritorioM
RF-24La aplicación debe comunicar los errores tanto en el área de estado como en un diálogo modal, y volver a dejar la interfaz operativaUsuario de escritorioM
RF-25Las acciones sobre el informe deben permanecer deshabilitadas mientras no exista un informe generadoUsuario de escritorioB

3.4 API, empaquetado y distribución

IDRequisitoActorPrio
RF-26El paquete debe exponer una clase comparadora como API pública estable, construible a partir de las rutas de ambos documentos y capaz de devolver el informe en memoriaDesarrollador integradorA
RF-27El proyecto debe publicarse como paquete instalable desde PyPI, declarando los dos puntos de entrada ejecutables (CLI y GUI)MantenedorA
RF-28El proyecto debe poder integrarse en otro repositorio como submódulo git e importarse directamenteDesarrollador integradorB
RF-29El proyecto debe generar ejecutables autónomos para Windows, Linux y macOS (Apple Silicon), sin requerir Python instalado en la máquina destinoMantenedorM
RF-30La publicación de binarios y del paquete debe dispararse automáticamente al integrar en la rama principal una versión nueva, y no repetirse para una versión ya publicadaMantenedorM

#4. Requisitos no funcionales

IDRequisitoCategoríaVerificación
NFR-01El informe debe preservar el texto como texto: seleccionable y buscable en cualquier visorCalidad de salidaBuscar una cadena conocida en el informe generado
NFR-02El informe no debe rasterizar el contenido original; el tamaño resultante debe mantenerse en el orden de magnitud de los documentos de entradaRendimientoComparar tamaño del informe frente a la suma de las entradas
NFR-03La instalación no debe requerir dependencias nativas externas al ecosistema PythonPortabilidadInstalación limpia en un sistema sin herramientas PDF
NFR-04El sistema debe funcionar sobre Python 3.12 o superiorCompatibilidadDeclarado en el empaquetado y ejercitado en CI
NFR-05El sistema debe funcionar en Windows, macOS y Linux, incluidas las rutas específicas de cada sistema para descargas y apertura de ficherosPortabilidadEjecución en las tres plataformas
NFR-06La interfaz gráfica no debe congelarse durante la comparación: el trabajo pesado se ejecuta fuera del hilo de interfaz y la comunicación entre hilos es seguraUsabilidad / robustezComparar un documento extenso y verificar que la ventana responde
NFR-07La previsualización debe renderizarse a resolución reducida para acotar el consumo de memoria, sin afectar a la calidad del informe entregadoRendimientoInspección del uso de memoria con documentos de muchas páginas
NFR-08Los documentos abiertos deben cerrarse siempre al terminar el proceso, sin dejar descriptores abiertosRobustezComparaciones encadenadas en un proceso de larga vida
NFR-09Todo el procesamiento debe ser local: el sistema no envía los documentos ni su contenido a ningún servicio externoPrivacidad / RGPDAusencia de tráfico de red durante una comparación
NFR-10La publicación en PyPI debe realizarse sin credenciales de larga duración almacenadas en el repositorioSeguridadRevisión del workflow de publicación
NFR-11El proceso de publicación debe ser idempotente: una versión ya publicada no vuelve a publicarse aunque se repita la ejecuciónFiabilidadReejecución del workflow sobre una versión existente
NFR-12El código fuente debe permanecer en un único paquete Python sin dependencias circulares entre interfaz, CLI y núcleo de comparaciónMantenibilidadRevisión de imports: el núcleo no importa CLI ni GUI

#5. Restricciones técnicas no negociables

IDRestricciónMotivo
RT-01La manipulación de PDF se realiza con PyMuPDF; es la dependencia estructural del núcleo y la que hace innecesarias las herramientas nativasSustituye al enfoque previo basado en Poppler e imágenes; cambiarla implica reescribir el núcleo
RT-02La interfaz gráfica se construye con CustomTkinter sobre Tcl/Tk, con hooks propios de runtime en el empaquetado para Linux y macOSYa resuelto en los scripts de build; cambiar de framework invalida el empaquetado actual
RT-03Los parámetros --dpi y --quality de la CLI, y las constantes PDF_RENDER_DPI y JPEG_QUALITY de pdf_compare/config.py, se mantienen aunque no tengan efecto en el render vectorialCompatibilidad hacia atrás: la API y la CLI ya están publicadas en PyPI y retirarlas rompería a consumidores existentes
RT-04La versión del producto es la declarada en pyproject.toml y debe mantenerse sincronizada con pdf_compare/__init__.py; el CI la lee de pyproject.toml para etiquetar y publicarEl release automático depende de esa única fuente
RT-05El empaquetado usa hatchling como backend de construcción y uv como gestor de entorno en CIFijado en el workflow y en los scripts de build
RT-06El versionado sigue un esquema calendario (AAAA.M.P), no semánticoVersión actual 2026.2.3; condiciona cómo se comunican los cambios incompatibles
RT-07La compatibilidad de licencias entre el código propio y PyMuPDF condiciona la distribución del productoVer P-01 en la sección 8: hay una contradicción sin resolver

#6. Alcance

Dentro de esta fase (as-is)

  • Comparación de dos documentos PDF con capa de texto, con alineado de páginas y resaltado de diferencias por palabra.
  • Las tres interfaces existentes: CLI, aplicación de escritorio y API Python.
  • Empaquetado y distribución actuales: PyPI, binarios autónomos para las tres plataformas y uso como submódulo.

Fuera de esta fase

  • PDF escaneados o sin capa de texto. El alineado y el resaltado dependen íntegramente del texto extraíble; sobre un documento escaneado el sistema no detecta diferencias. Es una limitación conocida y declarada: la herramienta exige documentos con capa de texto y no se compromete a incorporar OCR. Desde el 2026-08-17 el sistema sí detecta y avisa de que falta la capa de texto en lugar de entregar en silencio un informe sin diferencias (ver D-08); sigue sin haber OCR.
  • Comparación de más de dos documentos o de carpetas completas.
  • Detección de diferencias no textuales: imágenes, gráficos vectoriales, cambios de color o de tipografía sin cambio de contenido.
  • Comparación semántica o por lenguaje natural (resumen de cambios, clasificación de relevancia).
  • Cualquier funcionalidad multiusuario, de servidor o de red: autenticación, historial, almacenamiento compartido.
  • Internacionalización: la interfaz y las etiquetas del informe están en inglés y así permanecen.
  • Configuración persistente de preferencias de usuario.

#7. Variables de entorno y configuración requerida

El producto no consume ninguna variable de entorno propia en tiempo de ejecución. Toda su configuración es por argumentos de CLI o por parámetros del constructor de la API.

ElementoÁmbitoUso
pdf_compare/config.pyEjecuciónConstantes heredadas del render por imagen, sin efecto actual (ver RT-03)
Carpeta temporal del sistemaEjecución (GUI)Ubicación del informe intermedio antes de descargarlo o guardarlo
Carpeta de descargas del usuarioEjecución (GUI)Destino de la acción de descarga; se resuelve por registro en Windows y por convención en macOS/Linux
Entorno pypi-release de GitHubCI/CDEntorno protegido desde el que se publica el paquete
OIDC de GitHub ActionsCI/CDPublicación en PyPI sin token almacenado (trusted publishing)
GITHUB_TOKENCI/CDCreación de tags y releases; lo provee la propia plataforma

Sin secretos propios que gestionar en local.

#8. Preguntas abiertas y pendientes

  • P-01 · BLOQUEANTE Contradicción de licencia. El fichero LICENSE del repositorio contiene la GPL-3.0, mientras que pyproject.toml y el README.md declaran MIT. Además, PyMuPDF (RT-01) se distribuye bajo AGPL-3.0 o licencia comercial, lo que condiciona bajo qué licencia puede distribuirse un producto que la enlaza. Hay que decidir cuál es la licencia real del proyecto y alinear los tres sitios. Afecta a RT-07 y a toda la distribución (RF-27, RF-29).
  • ~~P-02 · Discrepancia entre la documentación y el comportamiento de RF-10.~~ Resuelto el 2026-08-17. compare_visuals() devuelve None cuando no hay ninguna diferencia, y la CLI y la GUI informan de ello; las ramas que antes eran inalcanzables ahora se ejecutan. Se define "sin diferencias" como: ninguna página añadida ni eliminada, y ningún cambio de texto a nivel de palabra en las páginas emparejadas.
  • P-03 · RF-11 no está expuesto. La comparación textual en unified diff existe en el núcleo pero no la alcanza ninguna interfaz. Decidir si se expone en la CLI, si se documenta como API o si se retira.
  • P-04 · Umbrales de alineado. El 2026-08-17 se corrigieron dos defectos que incumplían RF-02, RF-03 y RF-05: un off-by-one que hacía explorar 2 posiciones en lugar de las 3 declaradas, y el uso del umbral absoluto de "misma página" (0,6) también para decidir si una página está desplazada. Este segundo defecto impedía detectar una inserción cuando la página desplazada además había sido editada, con lo que la página añadida se emparejaba con la original y la verdadera equivalente se marcaba como añadida. La detección de desplazamiento es ahora relativa (el candidato debe encajar SHIFT_MARGIN veces mejor que el emparejamiento actual y superar un suelo de ruido), y las cuatro constantes están documentadas a nivel de módulo. Queda abierto: los valores concretos siguen elegidos por criterio y no por medida, y el alineado sigue siendo voraz y local, por lo que no recupera desplazamientos mayores que LOOKAHEAD_WINDOW. Decidir si se validan con un corpus de documentos reales o si se sustituye por un alineado global.
  • P-05 · No hay verificación automática. El proyecto declara pytest como dependencia de desarrollo pero no contiene ni un test, y el CI solo construye y publica: ningún requisito de este catálogo está verificado de forma automatizada. Los documentos sample-files/ cubren los cuatro escenarios de alineado y son la base natural para esa suite. Sigue abierto y es ahora más urgente: las correcciones del 2026-08-17 se validaron con comprobaciones manuales y desechables, que no protegen de regresiones futuras.
  • P-06 · Límites operativos sin definir. No hay criterio establecido de número máximo de páginas, tamaño de fichero ni tiempo de respuesta aceptable. NFR-02 y NFR-07 se han redactado como cualitativos; convendría cuantificarlos con medidas reales antes de comprometerlos.
  • P-07 · Trazabilidad de errores. El sistema informa por salida estándar y por diálogos, sin registro estructurado. Decidir si un producto de escritorio local necesita observabilidad o si basta lo actual.

#9. Decisiones tomadas en el paso 1.1

#PreguntaOpcionesDecisiónOrigenJustificación
D-01¿El documento cubre solo el estado actual o también la evolución prevista?as-is / as-is + to-beSolo el estado actual (as-is)usuarioEl repositorio es brownfield sin backlog definido; la línea base trazable es lo que permite que cada evolución entre después como change de AISDD
D-02¿Cómo se recoge la incapacidad de tratar PDF escaneados?fuera de alcance / degradación controlada / OCR futuroFuera de alcance, explícitousuarioSe declara como limitación conocida en la sección 6 sin comprometer OCR, que añadiría una dependencia pesada al producto
D-03¿Qué comportamiento se formaliza cuando no hay diferencias?informar / generar siempre el informeInformar de que no hay cambios (RF-10)usuarioSe toma como correcto lo documentado en el README.md; la implementación actual queda registrada como deuda en P-02
D-04¿Qué estatus tienen los parámetros heredados --dpi, --quality y config.py?restricción de compatibilidad / deprecados a eliminarRestricción de compatibilidad (RT-03)usuarioLa API y la CLI ya están publicadas en PyPI; retirarlas sería un cambio incompatible para consumidores existentes
D-05¿Cómo se trata la ausencia de docs/cliente-requisitos.md?bloquear / continuar por ingeniería inversaContinuar por ingeniería inversadefaultEl producto existe y es la fuente de verdad más fiable; se deja constancia de que no hubo brief formal de cliente
D-06¿Se documentan roles con permisos?sí / no aplicaNo aplica: perfiles de usodefaultLa herramienta es local y monousuario, sin autenticación ni control de acceso que modelar
D-07¿Se resuelve la contradicción de licencia detectada?resolver ahora / registrar como bloqueanteRegistrar como bloqueante (P-01)defaultEs una decisión legal del propietario del proyecto, no derivable del código
D-08¿Se avisa de la ausencia de capa de texto?mantener D-02 estricto / avisarAvisarusuarioCorrige D-02. La revisión de código del 2026-08-17 (hallazgo F8) mostró que ratio('','') == 1.0 hace que un escaneado produzca un informe que afirma que no hay cambios: un fallo silencioso. El usuario aprobó aplicar los hallazgos de la revisión, lo que introduce la degradación controlada que D-02 había descartado. Sigue sin haber OCR, así que el alcance de la sección 6 no cambia