Perfil del DIP Solo-PDF — Docuten eArchiving v1.1

Docuten eArchiving PDF-only DIP Profile v1.1

Metadato Valor
Versión del perfil / Profile version 1.1
Estado / Status Vigente — la 1.1 se publica con la Fase 06.7 (la 1.0 se publicó con la Fase 05.4)
Identificador del perfil / Profile URI https://docs.docuten.com/earchiving/dip-profile/v1
Versión del formato del manifiesto / Manifest format version 1.1 (campo dipFormatVersion)
Tipo de paquete cubierto / Package type covered DIP solo-PDF (derivado de un AIP conservado): los documentos de usuario son solo PDF; metadata/ lleva además el sidecar de sello, los informes de integridad y el manifiesto
Perfil relacionado / Related profile docs/governance/mets-profile.md (perfil METS del AIP de origen)
Endpoint que lo produce / Producing endpoint GET /api/v1/aip/{aipId}/dip
Fecha / Date 2026-11-02 (v1.1) · 2026-09-21 (v1.0)

1. Propósito / Purpose

Este documento es la especificación pública del formato del DIP solo-PDF que produce el servicio Docuten eArchiving. Su destinatario es quien recibe un DIP: un cliente, un auditor, o un tercero al que el cliente le ha redistribuido el paquete. Describe qué contiene el ZIP, qué significa cada campo de su manifiesto, y cómo verificar el paquete sin llamar a la plataforma.

Un DIP (Dissemination Information Package) solo-PDF es un derivado de un AIP conservado: una selección de los documentos PDF del paquete, entregada con la evidencia necesaria para acreditar que esos bytes son los que el archivo custodia.

«Solo-PDF» describe los documentos de usuario, no el paquete completo. Desde la 1.1 el ZIP lleva, bajo metadata/, además del sidecar de sello y del manifiesto, los informes de integridad (§5.6 y §5.7). Siguen sin entrar en el DIP los ficheros de datos que no son PDF y la maquinaria archivística del AIP (§4.1).

This document is the public format specification of the PDF-only DIP produced by the Docuten eArchiving service. Its audience is whoever receives a DIP — a customer, an auditor, or a third party the customer redistributed the package to. It describes what the ZIP contains, what each manifest field means, and how to verify the package without calling the platform.

1.1 No-objetivos explícitos / Explicit non-goals


2. Estatus normativo — las dos mitades, que deben leerse juntas

Estas dos afirmaciones no se contradicen; parecen contradecirse si se lee solo una.

(a) El contenido del manifiesto es un artefacto de producto. Ninguna norma prescribe qué campos lleva. eIDAS 2.0 (Art. 45i/45j del Reg. (UE) 2024/1183) exige demostrar integridad y autenticidad de origen, y eso lo sostiene la cadena sellada que el manifiesto referencia —no el manifiesto en sí—. Los campos de §5 son los que este producto ha decidido emitir.

(b) El estatus del formato sí está regulado: REQ-11-06 de CEN/TS 18170 recae sobre él. Ese requisito exige que el formato, la sintaxis y la semántica del DIP estén especificados o basados en un estándar disponible públicamente. Este documento publicado es lo que satisface ese requisito, sin convertir el DIP en un E-ARK DIP formal.

(a) The manifest's content is a product artifact: no standard prescribes its fields. eIDAS 2.0 Art. 45i/45j requires demonstrating integrity and origin authenticity, and that is carried by the sealed chain the manifest references. (b) The format's status is regulated: CEN/TS 18170 REQ-11-06 requires the DIP format to be specified or based on a publicly available standard — this published profile is what satisfies it, without turning the DIP into a formal E-ARK DIP.


3. Identificador y versión / Identifier and version

Cada manifiesto declara contra qué especificación debe leerse, igual que el sidecar de sello declara su merkleProfile. Un auditor que abra un DIP suelto, sin contexto, llega a este documento desde el propio artefacto.

Campo del manifiesto Valor en v1.1 Semántica
dipProfile https://docs.docuten.com/earchiving/dip-profile/v1 Identificador estable de este perfil. PRE-07 publica este documento en esa misma dirección; que la URI resuelva lo confirma DevOps (estado en docs/governance/published-uris.md). Ningún consumidor debe depender de que resuelva para verificar un DIP: la verificación offline (§6) no la necesita.
dipFormatVersion "1.1" Versión de este perfil, no de la aplicación que lo emite. Un DIP emitido bajo la 1.0 declara "1.0".

El identificador es estable por diseño. Viaja dentro de artefactos que terceros redistribuyen y que no se pueden reescribir una vez entregados: cambiarlo o retirarlo dejaría sin referente todos los DIP ya emitidos. Un cambio incompatible del formato se publica como un identificador y una versión nuevos (…/dip-profile/v2, dipFormatVersion: "2.0"), nunca reinterpretando este. La 1.1 es aditiva: añade entradas y un campo, no reinterpreta ninguno, y por eso conserva el mismo identificador.

3.1 Compatibilidad con 1.0

La 1.1 es compatible hacia atrás: un receptor que solo conoce la 1.0 puede ignorar el array reports y las entradas nuevas de metadata/ y procesar el resto exactamente como antes. Ningún campo ni entrada de 1.0 cambia de significado ni desaparece. Lo que cambia es la redacción de seis cláusulas, que la 1.0 contradice y que se reescriben aquí de forma explícita:

Dónde Redacción en 1.0 Redacción en 1.1
dipFormatVersion (§3, §5.1) "1.0" "1.1"
verificationNote (§5.1) La nota de 1.0 La misma nota, íntegra, con una frase añadida que remite a metadata/integrity-report.xml como puesta por escrito de lo comprobado en la emisión (no sellada y no vigente)
Fila «Estado de integridad» de §5.4 El DIP no lleva ningún estado de integridad El manifiesto sigue sin llevarlo; ese estado vive solo en metadata/integrity-report.xml (§5.6), fechado con retrievalMoment, y no es una garantía vigente
Garantía de §9 «mismo AIP → mismo ZIP salvo generatedAt» «mismo AIP → mismo ZIP salvo generatedAt del manifiesto y las entradas integrity-report.xml y integrity-report.html con sus referencias del manifiesto»; y la nota de generatedAt en §5.1 deja de decir que es el único campo que depende del reloj de la descarga
Precisión de §6 y §7.1 La plataforma no valida la firma del sidecar al emitir La plataforma sí valida que la firma del sidecar es íntegra y encadena a un ancla configurada, y no entrega si no es así (§7.1); no comprueba revocación ni cualificación, y eso consta como limitación
§8 Sin DIP_EVIDENCE_SIGNATURE_INVALID Código nuevo (§8.1) y su lugar en el orden de guardas (§8.2)

4. Estructura del paquete / Package structure

El DIP es un ZIP con una única carpeta raíz que lleva el identificador del AIP de origen —misma convención que el propio AIP y que la recomendación E-ARK para DIPs («the top-most folder carries the unique name of the DIP»).

dip-{aipId}.zip
└── {aipId}/
    ├── <documento-1>.pdf          ← contenido del usuario, en la raíz
    ├── <documento-2>.pdf
    ├── …
    └── metadata/
        ├── aip-hash-seal.xml      ← copia byte a byte del sidecar de sello del AIP
        ├── integrity-report.xml   ← informe de la emisión (siempre; NO sellado)
        ├── integrity-report.html  ← su versión legible
        ├── sealed-integrity-report.xml            ← (si existe) copia del último informe sellado
        ├── sealed-integrity-report-timestamp.tst  ← (si existe) su token de sello de tiempo
        ├── sealed-integrity-report.html           ← (si existe) versión legible de la copia
        └── manifest.json          ← SIEMPRE la ÚLTIMA entrada escrita en el ZIP
Ruta Obligatoria Contenido
{aipId}/ MUST Carpeta raíz. {aipId} es el UUID del AIP de origen.
{aipId}/*.pdf MUST (≥ 1) Los documentos PDF del paquete. Un AIP sin ningún PDF no produce DIP (§8, AIP_HAS_NO_PDF).
{aipId}/metadata/aip-hash-seal.xml MUST Copia byte a byte del sidecar de sello del AIP de origen. Es la evidencia que permite la verificación offline (§6).
{aipId}/metadata/integrity-report.xml MUST Informe de integridad de la emisión (§5.6): se genera en cada descarga y no está sellado.
{aipId}/metadata/integrity-report.html MUST Versión legible del anterior. No es evidencia (§5.6).
{aipId}/metadata/sealed-integrity-report.xml MAY Copia byte a byte del XAdES del último informe sellado del AIP, si lo hay y está completo (§5.7).
{aipId}/metadata/sealed-integrity-report-timestamp.tst MAY Copia byte a byte del token de sello de tiempo RFC 3161 de ese informe. Va siempre que va el anterior.
{aipId}/metadata/sealed-integrity-report.html MAY Versión legible de la copia sellada. No es evidencia. Va siempre que va la copia.
{aipId}/metadata/manifest.json MUST El manifiesto (§5). Debe ser la última entrada del ZIP.

Los informes se escriben después de aip-hash-seal.xml y antes de manifest.json. Todos los nombres de entrada los fija el servidor: ninguno procede de texto de usuario.

La raíz {aipId}/ contiene únicamente los PDF del usuario. Hay un solo directorio auxiliar (metadata/), no dos, para que el receptor distinga sin ambigüedad el contenido de la maquinaria.

4.1 Qué documentos entran, y cuáles no

4.2 Nombres de los ficheros entregados

El nombre con el que se entrega cada PDF se deriva, en este orden de prioridad:

  1. el nombre real persistido como metadato, si existe;
  2. si no, el basename de la entrada dentro del AIP, saneado (sin diacríticos, con el juego de caracteres [A-Za-z0-9-_], y la extensión .pdf re-pegada en minúscula);
  3. si no, {sequence}.pdf, donde sequence es el índice persistido e inmutable del fichero dentro del AIP.

Colisión de nombres: si dos documentos producen el mismo nombre entregado, el de sequence menor conserva el nombre limpio y los demás reciben el sufijo -{sequence} (contrato.pdf, contrato-7.pdf). Como sequence es persistido e inmutable, el sufijo no depende del orden de recorrido y es el mismo en todas las descargas del mismo AIP.

El nombre entregado NUNCA es evidencia por sí solo. Es un nombre saneado y potencialmente desambiguado. La evidencia es el manifiesto, que correlaciona ese nombre con la ruta real que el sello certifica (§5, deliveredFilename ↔ sourcePath).

4.3 Nombres de los documentos ingestados por POST /api/v1/ingest/file

Desde la fase 06.5, los paquetes ingestados por la ruta /file conservan el nombre real y la extensión real de cada fichero (regla versionada en docs/governance/filename-policy-v1.md: se conserva el nombre seguro y se deriva solo lo inseguro), y su premis.xml guarda el nombre declarado en originalName. En consecuencia, el DIP de /file ya entrega el nombre por la fuente (2) de §4.2 —el basename de la entrada del AIP, saneado—: por ejemplo, Factura Ñ ñ.pdf se entrega como Factura-N-n.pdf, en lugar de {sequence}.pdf. Este cambio no modifica el DIP: ni dipFormatVersion ni el esquema del manifiesto cambian.


5. Esquema del manifiesto, campo a campo / Manifest schema

Ubicación: {aipId}/metadata/manifest.json · Codificación: UTF-8 · Serialización: JSON canonicalizado según RFC 8785 (JCS).

{
  "aipId": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f",
  "dipFormatVersion": "1.1",
  "dipProfile": "https://docs.docuten.com/earchiving/dip-profile/v1",
  "fileEntries": [
    {
      "deliveredFilename": "contrato.pdf",
      "representationId": "rep-1",
      "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
      "sourcePath": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f/representations/rep-1/data/contrato.pdf"
    }
  ],
  "generatedAt": "2026-09-21T18:42:07.113Z",
  "merkleProfile": "https://docs.docuten.com/earchiving/merkle-profile/v2",
  "reports": [
    {
      "path": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f/metadata/integrity-report.xml",
      "role": "EMISSION_REPORT_XML",
      "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae"
    },
    {
      "path": "3f2b1c40-9a7e-4d21-8f55-0c1a2b3d4e5f/metadata/integrity-report.html",
      "role": "EMISSION_REPORT_HTML",
      "sha256": "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9"
    }
  ],
  "sealedMerkleRoot": "b1946ac92492d2347c6235b4d2611184…",
  "verificationNote": "Verificar hash SHA-256 de cada PDF contra fileEntries del sidecar adjunto en metadata/aip-hash-seal.xml; ver https://docs.docuten.com/earchiving/dip-profile/v1 para el procedimiento completo y la validación de la firma del sello. El informe de integridad de la emisión (metadata/integrity-report.xml) deja por escrito lo que se comprobó al emitir este DIP: no está sellado y no es una garantía vigente.",
  "sipId": "7c4e0a11-2b33-4c55-9def-0123456789ab"
}

Nota sobre el orden de las claves del ejemplo. RFC 8785 ordena las claves de cada objeto por su representación UTF-16; el ejemplo de arriba se muestra ordenado por legibilidad. Los bytes reales que se entregan están canonicalizados, no formateados como aquí.

5.1 Campos de nivel superior

Campo Tipo Obligatorio Semántica
aipId string (UUID) MUST Identificador del AIP de origen. Es la referencia de procedencia: este DIP se extrajo de ese AIP.
sipId string (UUID) | null MUST (puede ser null) Identificador del SIP del que nació el AIP. null significa «no registrado», nunca «no aplica».
fileEntries array MUST Una entrada por PDF entregado (§5.2). Ordenado por sequence ascendente (§9).
dipProfile string MUST Identificador de este perfil (§3).
dipFormatVersion string MUST Versión de este perfil (§3). "1.1" en este perfil.
verificationNote string MUST Instrucción de verificación legible que viaja dentro del artefacto, con puntero a este documento. Es un resumen: el procedimiento normativo es §6.
reports array MUST (puede estar vacío) Nuevo en 1.1. Una entrada por fichero de informe que viaja en el ZIP (§5.5). Un DIP 1.1 lleva siempre al menos las dos del informe de emisión.
sealedMerkleRoot string (hex) MUST Raíz Merkle del AIP completo tal como la declara el sidecar sellado. Es un puntero de conveniencia, no la evidencia (§5.3).
merkleProfile string | null MUST (puede ser null) Perfil de construcción del árbol Merkle, copiado del sidecar. null = el sidecar no lo declara (formato antiguo); no se infiere un valor, porque «no lo sé» no es «sé que es v2».
generatedAt string (ISO-8601 UTC) MUST Instante de generación de esta emisión concreta. Junto con el informe de emisión (§5.6), es lo que depende del reloj de la descarga (§9).

5.2 Campos de cada elemento de fileEntries

Campo Tipo Obligatorio Semántica
deliveredFilename string MUST Nombre del fichero tal como viaja en este ZIP, sin el prefijo {aipId}/.
sourcePath string MUST Ruta completa dentro del ZIP del AIP de origen. Es la clave que el sidecar sellado certifica, y por tanto la única con valor probatorio.
sha256 string (hex, 64) MUST SHA-256 del fichero, recomputado desde el contenido real mientras se copiaba a este ZIP, y contrastado contra la hoja sellada antes de entregarlo (§7).
representationId string | null MUST (puede ser null) Identificador de la representación del AIP a la que pertenece el fichero. Se deriva de sourcePath ({aipId}/representations/{repId}/data/…). null = la ruta no sigue ese layout; es un «no lo sé» explícito, nunca un valor inventado.

5.3 Jerarquía de autoridad — cuál manda si hay divergencia

El sidecar sellado (metadata/aip-hash-seal.xml) es la fuente autoritativa. Los campos sealedMerkleRoot y merkleProfile del manifiesto son punteros de conveniencia —ambos se leen del sidecar en la misma pasada, así que no pueden divergir por construcción—. Si un receptor detectara divergencia entre manifiesto y sidecar, manda el sidecar.

5.4 Lo que el manifiesto NO lleva, y por qué

No lleva Razón
Identidad del solicitante Dato personal en un fichero redistribuible. Minimización RGPD: el acto de diseminación con su autor pertenece al audit log de la plataforma, no al paquete que sale de ella.
Estado de integridad del AIP El manifiesto sigue sin llevar estado de integridad: sería un snapshot mutable que el receptor leería como garantía vigente. Ese estado vive solo en metadata/integrity-report.xml, fechado con retrievalMoment, y no es una garantía vigente: dice qué se comprobó al emitir el DIP (§5.6), nada más. La garantía real es la cadena sellada; el estado vivo se consulta en el catálogo.
Veredicto PDF/A de la ingesta Ver §10: la clave con la que se persistió es ambigua entre representaciones, y un campo que mezclase «veredicto», «no validado» y «no atribuible» confundiría más de lo que informa. La señal no se pierde: se consulta donde vive.
Firma o sello propios Por decisión explícita — ver §7.3.
tenantId Es información de aislamiento interno, no de procedencia.

5.5 Campos de cada elemento de reports

Campo Tipo Obligatorio Semántica
path string MUST Ruta de la entrada desde la raíz del ZIP ({aipId}/metadata/…). Nombre fijo generado por el servidor.
role string MUST Rol del fichero, de un vocabulario cerrado: EMISSION_REPORT_XML, EMISSION_REPORT_HTML, SEALED_REPORT_XML, SEALED_REPORT_TIMESTAMP, SEALED_REPORT_HTML.
sha256 string (hex minúsculas, 64) MUST SHA-256 de exactamente los bytes de esa entrada tal como viaja en el ZIP.
checkId string (UUID canónico) MUST en SEALED_REPORT_XML, SEALED_REPORT_TIMESTAMP y SEALED_REPORT_HTML, con el mismo valor en las tres; la clave se omite (no se escribe null) en EMISSION_REPORT_* y en todas las entradas cuando el DIP no lleva copia sellada Identificador de la comprobación de integridad de la que se copió el informe sellado. Es un identificador operativo: sirve para correlacionar con el histórico de comprobaciones del detalle del AIP y con soporte. No es evidencia: la referencia con fuerza probatoria es sha256, y el XAdES copiado lleva su propio checkId dentro del documento firmado.

El checkId de las tres entradas selladas es siempre el mismo: identifica la única comprobación de la que se copió el informe (§5.7). Un receptor que valide el manifiesto debe tratar la clave checkId como opcional y no inferir nada de su ausencia salvo «este DIP no lleva copia sellada».

El orden del array es el de escritura: informe de emisión (XML, HTML) y, si hay copia sellada, XAdES, token y HTML. El manifiesto no se sella, pero el hash del manifiesto entregado queda anclado en el audit log (§6.1): los informes quedan así anclados de forma indirecta, sin sello propio.

5.6 Informe de integridad de la emisión — metadata/integrity-report.xml

Qué es. La puesta por escrito de lo que el DIP comprobó al emitirse, generada en cada descarga. No está sellado ni firmado y no se presenta como garantía vigente del AIP: es una afirmación fechada de la plataforma sobre un instante, y su valor probatorio es el de las evidencias que referencia por hash.

Formato. XML UTF-8, espacio de nombres https://docs.docuten.com/earchiving/dip-integrity-report/v1, raíz dipIntegrityReport. Su versión legible es integrity-report.html, generada desde ese XML.

Elemento Semántica
reportId UUID aleatorio (v4) de este informe; distinto en cada descarga. Nunca derivado del contenido.
retrievalMoment Instante de la emisión del DIP.
packageId El AIP del que se extrajo el DIP.
integrityStatus VALID. Un DIP entregado solo puede decir VALID: cualquier divergencia de fixity o firma de sidecar inválida impide la entrega (§7), así que no hay DIP con un estado peor.
scope PDF_FILES_DELIVERED: lo comprobado son los PDF entregados, no el AIP completo.
sealedRoot Raíz Merkle declarada por el sidecar sellado, leída de él.
evidence Una entrada por evidencia referenciada por hash (kind, path, sha256): SEALED_SIDECAR siempre y, si hay copia sellada, SEALED_REPORT_XML y SEALED_REPORT_TIMESTAMP.
originStatus SIDECAR_SIGNATURE_VALID: la firma del sidecar es íntegra y encadena a un ancla configurada (§7.1).
limitations Códigos cerrados de lo que no se comprobó o no se pudo copiar (ver abajo).

Respalda VALID solo con: la firma del sidecar validada y el SHA-256 de cada PDF entregado contrastado contra el sidecar (§7.1).

Lo que NO dice. No declara ningún root recomputado ni «AIP íntegro»: no se recorre el AIP completo al emitir un DIP. No lleva identidad del solicitante ni ningún dato del actor que descarga (§5.4).

Limitaciones declaradas (limitations):

Código Cuándo aparece Significado
NON_PDF_FILES_NOT_REVERIFIED Siempre Los ficheros del AIP que no son PDF no se contrastan al emitir.
REVOCATION_AND_QUALIFICATION_NOT_CHECKED Siempre La validación de la firma del sidecar no comprueba revocación ni cualificación; eso es el paso 3 del receptor (§6).
NO_SEALED_REPORT El AIP no tiene ninguna comprobación de integridad terminal No hay informe sellado que copiar.
LATEST_SEALED_REPORT_INCOMPLETE La custodia muestra que a la última comprobación terminal le falta el XAdES o el token, o que no hay blobs No se copia ningún informe sellado (§5.7).
LATEST_SEALED_REPORT_NOT_ATTACHED Falló la lectura o la comprobación de la custodia del informe sellado de la última comprobación terminal en la emisión; se desconoce si hay informe custodiado y cuál es su contenido No se adjunta la copia sellada (§5.7). No afirma nada sobre la existencia ni el contenido de ese informe. Una nueva descarga puede incluirla si el fallo fue transitorio; si se repite, el suscriptor debe comunicarlo a soporte.
LATEST_SEALED_REPORT_HTML_NOT_RENDERED La copia sellada de la última comprobación terminal se leyó de la custodia, pero no se pudo generar su versión legible (HTML) en la emisión No se adjunta la copia sellada: una copia sellada viaja siempre con su versión legible y no se entrega a medias (§5.7). No afirma nada sobre el contenido de esa copia. Una nueva descarga puede incluirla si el fallo fue transitorio; si se repite, el suscriptor debe comunicarlo a soporte.

El HTML no es evidencia. integrity-report.html es una vista de conveniencia generada desde el XML. Su aviso nombra el fichero XML correspondiente y el SHA-256 de ese XML tal como viaja en el ZIP: el receptor debe contrastar siempre el XML, no el HTML.

5.7 Copia del último informe sellado

El archivo registra comprobaciones de integridad del AIP y sella el informe de cada una (XAdES más token de sello de tiempo). Si el AIP tiene una, el DIP lleva una copia byte a byte de la última.

Regla de selección — mecánica, nunca por veredicto:

  1. Se toma la última comprobación terminal del AIP: la de mayor fecha de comprobación (desempate por su identificador) entre las que terminaron con PASS, FAIL, NOT_ANCHORABLE o ERROR. Las que siguen en curso no cuentan.
  2. Si esa comprobación tiene informe sellado completo (XAdES y token), se copian el XAdES, el token y la versión legible, sea cual sea su veredicto.
  3. Si la custodia muestra que está incompleta o no tiene informe, no se copia ninguno y no se salta a una comprobación anterior: el informe de emisión lo declara en limitations (LATEST_SEALED_REPORT_INCOMPLETE). Si la custodia no se pudo leer o comprobar en la emisión (no se sabe si hay informe), tampoco se copia ninguno y se declara LATEST_SEALED_REPORT_NOT_ATTACHED. Si la copia se leyó pero no se pudo generar su versión legible, no se entrega a medias y se declara LATEST_SEALED_REPORT_HTML_NOT_RENDERED. Si el AIP no tiene ninguna comprobación terminal, declara NO_SEALED_REPORT. Toda ausencia de copia sellada lleva exactamente uno de esos cuatro códigos; nunca se omite en silencio.

La selección no mira el veredicto y no rescata un informe anterior «mejor»: elegir evidencia por lo que dice sería presentarle al tercero una historia mejor que la real. El SHA-256 de cada entrada copiada coincide con el del blob custodiado. La comprobación de la que se copió consta como checkId en las tres entradas SEALED_REPORT_* de reports (§5.5).

Determinismo y reintento (decisión de la fase 06.7, 2026-11-03). La copia sellada es un complemento del informe de emisión: si la custodia no se pudo leer o comprobar, o la copia no se pudo presentar en su versión legible, en la emisión, el DIP se entrega igualmente, sin copia y declarándolo con LATEST_SEALED_REPORT_NOT_ATTACHED o con LATEST_SEALED_REPORT_HTML_NOT_RENDERED; un fallo del complemento no bloquea la entrega de los PDF. Por tanto dos descargas consecutivas del mismo AIP pueden llevar conjuntos de evidencia distintos, y solo cuando la primera lo declara: ningún DIP omite la copia sellada sin declararlo. Volver a descargar el paquete puede incluir la copia si el fallo fue transitorio; si el mismo código se repite en descargas sucesivas, el suscriptor debe comunicarlo a soporte.


6. Procedimiento de verificación offline / Offline verification procedure

Esta es la parte normativa para el receptor. Se ejecuta sin conexión con la plataforma, con herramientas estándar (unzip, sha256sum, jq, y un validador de firmas eIDAS).

Paso 1 — Hash del PDF

Calcular el SHA-256 del documento entregado y comprobar que coincide con el campo sha256 de su entrada en fileEntries.

unzip -o dip-{aipId}.zip -d dip/
sha256sum "dip/{aipId}/contrato.pdf"
jq -r '.fileEntries[] | select(.deliveredFilename=="contrato.pdf") | .sha256' \
   "dip/{aipId}/metadata/manifest.json"

Qué prueba: que el fichero que tienes es el que el manifiesto describe. Qué no prueba todavía: nada sobre el archivo — un manifiesto y unos bytes fabricados a la vez serían igual de auto-consistentes. Por eso hay un paso 2.

Paso 2 — Contraste contra el sidecar sellado

Comprobar que ese mismo SHA-256 aparece, asociado a la ruta sourcePath correspondiente, en la lista de hojas de {aipId}/metadata/aip-hash-seal.xml. El sidecar es una copia byte a byte del documento que el archivo selló; el manifiesto no puede influir en él.

Qué prueba: que el contenido entregado es exactamente el que el archivo selló, identificado por su ruta real dentro del AIP (no por el nombre de entrega).

Paso 3 — Validación de la firma del sello

Validar la firma electrónica del sidecar contra las trust lists de la UE (EUTL / LOTL), con un validador conforme a eIDAS —por ejemplo DSS de la Comisión Europea—, comprobando además que el sealedMerkleRoot que el sidecar declara es el que se ha firmado.

Qué prueba: la autenticidad de origen — que quien selló es el prestador cualificado que dice ser, y que el sello no se ha alterado desde entonces.

Paso 4 (opcional) — Leer los informes de integridad

Abrir metadata/integrity-report.xml (§5.6) para saber qué comprobó la plataforma al emitir, con qué evidencias y con qué limitaciones; y, si el DIP lleva sealed-integrity-report.xml (§5.7), validar su firma y su token de sello de tiempo con el mismo tipo de validador del paso 3. Contrastar con sha256sum cada entrada contra su referencia en el array reports del manifiesto.

# Las rutas de `reports` parten de la raíz del ZIP: se ejecuta desde la carpeta donde se descomprimió.
cd dip/ && jq -r '.reports[] | "\(.sha256)  \(.path)"' "{aipId}/metadata/manifest.json" | sha256sum -c -

Qué prueba: que los informes que tienes son los que el manifiesto referencia. Qué no prueba: el informe de emisión no está sellado y no es una garantía vigente; y los ficheros .html son una vista de conveniencia, no evidencia.

Precisión importante sobre el reparto de responsabilidades. La plataforma, al emitir el DIP, verifica la fixity de cada documento contra las hojas selladas y valida la firma del sidecar contra las anclas de confianza que tiene configuradas (§7.1), y no entrega el paquete si algo no cuadra. Lo que la plataforma no hace en el momento de la descarga es comprobar la revocación ni la cualificación de esa firma contra las trust lists de la UE: ese es el paso 3, y es del receptor (por eso consta como limitación REVOCATION_AND_QUALIFICATION_NOT_CHECKED). La independencia es deliberada — una verificación que dependiera de la plataforma no probaría nada ante un tercero.

6.1 La mitad que sí requiere a la plataforma

Hay una comprobación que solo la plataforma puede hacer, y por eso se documenta aquí: confirmar que un DIP presentado por un tercero fue realmente emitido por el archivo. Cada emisión registra en su audit log encadenado el SHA-256 de los bytes exactos del manifest.json entregado. Presentado un DIP, la plataforma recalcula ese hash y lo cruza contra su cadena de auditoría.

Como el manifiesto lleva generatedAt y las huellas del informe de emisión (§5.5), cada descarga produce un hash distinto: es correcto e intencionado — identifica esa emisión concreta, no «un DIP de ese AIP». Es también lo que ancla, de forma indirecta, los informes del DIP (§5.5).


7. Integridad en la emisión — lo que el archivo comprueba antes de entregar

7.1 Verificación incondicional

Hay dos condiciones de entrega, y las dos se comprueban en cada descarga:

  1. La firma del sidecar. Antes de interpretar el sidecar y de leer ningún PDF, la plataforma valida que la firma del sidecar es íntegra y encadena a un ancla de confianza configurada. Si no, no se emite el DIP (500 DIP_EVIDENCE_SIGNATURE_INVALID, §8.1), se audita DIP_SIDECAR_SIGNATURE_INVALID y se encola una verificación de integridad del AIP.
  2. La fixity de cada documento. Por cada documento, el SHA-256 se recomputa desde el contenido real mientras el byte se copia al ZIP, y se contrasta contra la hoja del sidecar sellado.

Ambas son condición de entrega, no un diagnóstico posterior: cada descarga de un DIP es una verificación de integridad incidental.

Evidencia y configuración no son lo mismo. Un motivo de evidencia (sin firma, firma no íntegra, cadena sin anclar, sidecar ilegible) acusa de verdad: es DIP_EVIDENCE_SIGNATURE_INVALID. Un fallo de configuración de la plataforma (anclas no configuradas o no disponibles, error del validador) no es una acusación de manipulación: responde DIP_ERROR, sin auditar como incidente ni despachar verificación, porque tratarlo como manipulación negaría el DIP de todo AIP legítimo.

7.2 Divergencia → el DIP no se entrega

Si el contenido no coincide con la evidencia sellada —o si el sidecar no declara esa ruta en absoluto—, la entrega se aborta, el hecho se registra en el audit log con ambos hashes y se encola una verificación de integridad del AIP.

El archivo no entrega contenido que contradice su propio sello. La alternativa —entregarlo declarando la alteración en el manifiesto— produciría un paquete redistribuible que lleva dentro la afirmación de que su contenido está alterado: evidencia envenenada.

El aborto tiene dos formas, y las dos son detectables por el receptor:

Momento Qué recibe el receptor
Antes del primer byte Error HTTP con errorCode (§8). No hay ZIP.
A mitad de la transferencia Un ZIP sin manifest.json y sin directorio central: inválido por definición (§7.4).

7.3 El manifiesto no se sella

El manifest.json es un índice de procedencia en claro. No lleva firma ni sello propios, por decisión explícita: sellarlo acoplaría cada descarga a la disponibilidad del prestador de servicios de confianza. La evidencia sigue siendo el AIP sellado, al que el manifiesto apunta, y el hash del manifiesto entregado queda anclado en la cadena de auditoría (§6.1).

Tampoco se sella el informe de emisión (integrity-report.xml): se genera en cada descarga y su hash queda anclado solo de forma indirecta, por el del manifiesto que lo referencia (§5.5). La copia del último informe sellado (§5.7), en cambio, ya viene sellada de origen (XAdES y token); el DIP la copia sin tocarla ni volver a sellarla.

7.4 Regla estructural — un DIP sin manifest.json es un DIP inválido

{aipId}/metadata/manifest.json se escribe siempre en último lugar, después de todos los informes. Su presencia es, por tanto, la señal de que la emisión se completó, informes incluidos.

Un receptor que abra un DIP y no encuentre metadata/manifest.json debe descartarlo por completo. No es un paquete «parcial» ni «sin índice»: es una emisión abortada. No se debe confiar en ninguno de sus ficheros, aunque abran correctamente.


8. Contrato de errores del endpoint / Error contract

GET /api/v1/aip/{aipId}/dip responde, ante cualquier condición de error, un cuerpo JSON con un campo errorCode estable —el valor contractual— y un message legible —que no lo es y puede cambiar sin previo aviso.

{ "errorCode": "AIP_HAS_NO_PDF", "message": "The AIP contains no PDF documents for aipId: …" }

8.1 Códigos

HTTP errorCode Significado
403 DIP_FORBIDDEN El actor está autenticado pero su rol no incluye la descarga de DIP. Se comprueba antes que nada: un actor sin permiso no puede ni siquiera sondear si el AIP existe.
404 AIP_NOT_FOUND No existe ningún AIP con ese identificador.
403 FORBIDDEN El AIP existe pero pertenece a otro tenant.
409 AIP_HAS_NO_PDF El AIP existe y es accesible, pero no contiene ningún PDF. No es un error del cliente ni un 404: es el resultado legítimo para toda una clase de paquetes (p. ej. facturación en XML).
409 DIP_EVIDENCE_UNAVAILABLE El AIP no tiene sidecar de sello. Sin él, el DIP no puede acreditar autenticidad de origen: no se emite un DIP degradado. No hay régimen de dos clases («DIP verificado» vs «DIP de confianza»).
409 DIP_INDEX_INCOMPLETE El AIP está sellado pero su índice de ficheros está ausente o incompleto. Se falla ruidosamente en vez de emitir un DIP calculado sobre un índice parcial.
500 DIP_EVIDENCE_SIGNATURE_INVALID La firma del sidecar sellado no es válida (sin firma, no íntegra, cadena sin anclar o ilegible), detectada antes de emitir el primer byte (§7.1). El cuerpo incluye además aipId. Es un hallazgo positivo del archivo, no un fallo de la petición, y es distinto de DIP_ERROR: un fallo de configuración de la comprobación no acusa de manipulación y responde DIP_ERROR.
500 DIP_INTEGRITY_DIVERGENCE El contenido del AIP diverge de su evidencia sellada (§7.2), detectado antes de emitir el primer byte. El cuerpo incluye además aipId. Es un hallazgo positivo del archivo, no un fallo de la petición.
500 DIP_ERROR Error genérico de emisión. Es el catch-all: un errorCode estable para todo lo que no encaja arriba, para que un cliente nunca reciba un 500 sin código.
403 TENANT_CONTEXT_REQUIRED La credencial no lleva contexto de tenant (p. ej. un principal de plataforma sin tenant asignado).

8.2 Orden de evaluación — y por qué es parte del contrato

contexto de tenant → rol → AIP inexistente (404) → AIP de otro tenant (403)
  → sin sidecar (409) → firma del sidecar inválida (500) → sin índice (409) → sin PDF (409)
  → fixity del sondeo (500) → emisión

8.3 Errores a mitad de transferencia

Si el fallo ocurre cuando la respuesta 200 ya ha empezado a viajar, el código de estado ya no se puede cambiar. El contrato en ese caso es el de §7.4: el ZIP llega sin manifest.json y el receptor debe descartarlo. Esto incluye el caso de que no se pueda armar el informe de la emisión (§5.6): un DIP 1.1 sin lo que declara no se entrega con manifiesto.


9. Reproducibilidad — qué se garantiza y qué no

Garantía auditable: mismo AIP → mismo ZIP, byte a byte, salvo el campo generatedAt del manifiesto y las entradas integrity-report.xml y integrity-report.html con sus referencias del manifiesto. Dos descargas del mismo AIP producen paquetes confrontables entrada a entrada. Se sostiene porque el AIP de origen es WORM: su contenido y el orden de sus entradas son fijos.

Matiz de la copia sellada. Qué copia sellada lleva el DIP depende de cuál sea la última comprobación terminal en el momento de la descarga (§5.7): si entre dos descargas se completa una comprobación nueva, las entradas sealed-integrity-report* y sus referencias del manifiesto cambian. No es una variación del formato, es el estado del archivo. Lo mismo ocurre si la copia no se pudo leer o presentar en una descarga y sí en la siguiente: la primera lo declara con LATEST_SEALED_REPORT_NOT_ATTACHED o con LATEST_SEALED_REPORT_HTML_NOT_RENDERED (§5.7, «Determinismo y reintento»).

Las tres afirmaciones siguientes son normativas y deben leerse juntas, porque cada una acota a las otras:

  1. Las entradas del ZIP se emiten en el orden estable del AIP de origen. NO se garantiza que estén ordenadas por sequence. El orden físico del AIP y el orden por sequence proceden de dos criterios distintos —uno sensible a mayúsculas y otro no— y divergen en cuanto dos nombres mezclan mayúsculas y minúsculas. Coinciden cuando todos comparten caja, que es el caso mayoritario, pero eso no es una garantía y no debe asumirse.
  2. Los nombres entregados SÍ derivan de sequence (§4.2), y por tanto son estables y reproducibles con independencia del orden de recorrido.
  3. El array fileEntries del manifiesto SÍ va ordenado por sequence ascendente. RFC 8785 canonicaliza las claves de los objetos pero preserva el orden de los arrays, de modo que este orden se impone explícitamente. El auditor conserva la vista ordenada por sequence en el manifiesto aunque las entradas físicas del ZIP vayan en el orden del AIP.

Además:

9.1 Compresión

Entradas Método Razón
Los PDF ({aipId}/*.pdf) STORED (sin comprimir) Un PDF ya viene comprimido: aplicarle DEFLATE gastaría CPU sobre streams de hasta varios GiB a cambio de ~0 % de ganancia.
{aipId}/metadata/* DEFLATE El manifiesto JSON, el sidecar XML y los informes comprimen bien y son pequeños.

Un receptor no necesita saber esto para abrir el ZIP —cualquier herramienta estándar lo maneja—, pero forma parte del contrato de reproducibilidad: el método de compresión es uno de los bytes que no varían entre dos emisiones del mismo AIP.


10. Dónde consultar los veredictos PDF/A

El manifiesto del DIP no declara el veredicto PDF/A de ningún documento, por decisión explícita. El veredicto se determinó en la ingesta y se persistió con una clave que es ambigua cuando varias representaciones comparten el nombre base de un fichero; incorporarlo al manifiesto podría atribuir a un PDF el veredicto de otro, es decir, una afirmación falsa dentro de un artefacto de procedencia. Un campo que además mezclara «conforme», «no validado» y «no atribuible por ambigüedad» bajo un mismo valor confundiría más de lo que informa.

La señal no se pierde: se consulta donde vive.

Dónde Qué es
metadata/preservation/premis.xml dentro del AIP Los eventos PREMIS de preservación, incluida la validación de formato de la ingesta. Es la fuente archivística, y está cubierta por el sello del AIP.
GET /api/v1/aip/{aipId}/premis-events La misma información, consultable por API para quien tenga acceso al tenant.

Un PDF con veredicto no conforme o indeterminado se entrega igual en el DIP (§4.1): el archivo entrega lo que custodia. El veredicto informa sobre la conformidad del documento con un estándar de formato; no sobre su integridad ni su autenticidad, que son las que este DIP acredita.


11. Historial de cambios / Change history

Versión Fecha Cambio
1.1 2026-11-02 Fase 06.7. Aditiva: mismo identificador …/dip-profile/v1. El DIP lleva siempre el informe de integridad de la emisión (metadata/integrity-report.xml y .html, no sellado, §5.6) y, si existe, una copia byte a byte del último informe sellado (§5.7); el manifiesto gana el array reports (§5.5, con checkId en las entradas selladas) y dipFormatVersion pasa a "1.1". La plataforma valida la firma del sidecar antes de entregar (§7.1) y gana el código DIP_EVIDENCE_SIGNATURE_INVALID (§8.1, §8.2). Se reescriben de forma explícita la fila «Estado de integridad» de §5.4 y la garantía de §9, y §3.1 enumera qué cambia de redacción respecto a la 1.0.
1.0 2026-09-21 Versión inicial — Fase 05.4 «Descarga DIP Solo-PDF». Publica el formato del DIP solo-PDF: estructura del ZIP, esquema del manifiesto (§5), procedimiento de verificación offline (§6), contrato de errores (§8), contrato de reproducibilidad (§9), limitación de nombres del corpus /file (§4.3) y ubicación de los veredictos PDF/A (§10). Cierra REQ-11-06 de CEN/TS 18170.