<?xml version="1.0" encoding="UTF-8"?>
<!--
  Schema XML del informe de integridad de EMISIÓN del DIP v1.
  Namespace: https://docs.docuten.com/earchiving/dip-integrity-report/v1
  Decisiones: D-03 (Phase 06.7) — el DIP lleva siempre un informe de integridad propio, no sellado;
  decisión 0b del plan 06.7-05 (nombre, namespace, campos y vocabularios de este esquema).

  QUÉ CERTIFICA ESTE DOCUMENTO

  Lo que el DIP comprobó AL EMITIRSE y nada más: que el SHA-256 de cada PDF entregado coincide con el
  del sidecar sellado del AIP y que la firma de ese sidecar es válida (D-01/D-02). El documento se
  genera en cada descarga: lleva el momento de la emisión, el paquete, el root sellado contra el que se
  contrastó, las evidencias por hash (el sidecar y, si existe, la copia del último informe de
  integridad sellado con su token) y las limitaciones del propio informe.

  QUÉ *NO* ES

  NO está sellado: no lleva firma QTSP ni token TSA, y su valor probatorio es el de las evidencias que
  referencia por hash, no el suyo. NO recomputa el Merkle root del AIP completo (el DIP entrega PDF
  solamente, no el AIP): por eso este esquema NO declara ningún elemento de root recomputado y no puede
  afirmar que «el AIP esté íntegro». NO valida revocación ni cualificación del certificado de firma.
  Todo eso consta como limitación declarada en «limitations».

  POR QUÉ integrityStatus ADMITE TRES VALORES SI UN DIP ENTREGADO SOLO PUEDE SER VALID

  Cualquier divergencia entre un PDF y el sidecar, o una firma del sidecar inválida, IMPIDE la entrega
  (D-01/D-02): un DIP que existe es, por construcción, VALID. El vocabulario conserva INVALID e
  INDETERMINATE porque es el mismo de los informes sellados (PASS/FAIL/ERROR) y porque cerrarlo a un
  solo valor obligaría a publicar un v2 el día que el DIP declare un resultado distinto.

  CONTRATO PUBLICADO

  Este documento viaja dentro de cada DIP entregado y los receptores lo procesan fuera de línea: el
  esquema NO se edita después de publicarse. Un cambio de formato es siempre una versión nueva (v2),
  nunca una modificación de esta. Los vocabularios cerrados (integrityStatus, scope, kind, originStatus
  y limitation) son parte del contrato.

  Los códigos LATEST_SEALED_REPORT_NOT_ATTACHED (WR-03, plan 06.7-14, decisión del usuario del
  2026-11-03) y LATEST_SEALED_REPORT_HTML_NOT_RENDERED (WR-01, quick 261103-lw6, decisión del usuario
  del 2026-11-03) se incorporaron a v1 antes de su primera publicación: este esquema no estaba ni en
  main ni en ningún DIP entregado (git log de main y de origin/main sobre este fichero vacíos), así que
  añadir un valor no rompe a ningún receptor. Corregirlos después del merge habría exigido
  dip-integrity-report-v2.xsd. Desde la publicación el vocabulario es inmutable.

  sealedRoot usa el MISMO nombre y significado que en integrity-report-v1.xsd / -v2.xsd: Merkle root
  SHA-256 hex del sidecar sellado de sello #2. Este esquema es autocontenido: no importa ni comparte
  ObjectFactory con ningún otro.

  reportId lo aporta el emisor y es un UUID aleatorio: el esquema solo fija su forma.

  Bindings JAXB: dip-integrity-report-v1.xjb
                 → paquete com.docuten.earchiving.attestation.internal.generated.dipintegrityreport
-->
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:dir="https://docs.docuten.com/earchiving/dip-integrity-report/v1"
    targetNamespace="https://docs.docuten.com/earchiving/dip-integrity-report/v1"
    elementFormDefault="qualified"
    version="1.0">

  <!-- Elemento raíz: dir:dipIntegrityReport -->
  <xs:element name="dipIntegrityReport" type="dir:DipIntegrityReportType"/>

  <xs:complexType name="DipIntegrityReportType">
    <xs:sequence>
      <!-- Identificador del informe: UUID aleatorio aportado por el emisor, único por descarga -->
      <xs:element name="reportId" type="dir:UuidType"/>
      <!-- Instante UTC en que se emitió el DIP (y con él este informe) -->
      <xs:element name="retrievalMoment" type="xs:dateTime"/>
      <!-- Paquete (AIP) del que se emitió el DIP -->
      <xs:element name="packageId" type="xs:string"/>
      <!-- Resultado de lo que el DIP comprobó (vocabulario cerrado) -->
      <xs:element name="integrityStatus" type="dir:IntegrityStatusType"/>
      <!-- Alcance de la comprobación: qué ficheros se contrastaron -->
      <xs:element name="scope" type="dir:ScopeType"/>
      <!--
        Merkle root SHA-256 hex del sidecar sellado de sello #2: la referencia con fuerza probatoria
        contra la que se contrastaron los PDF entregados. Mismo nombre y significado que en los
        informes sellados.
      -->
      <xs:element name="sealedRoot" type="dir:Sha256AnyCaseType"/>
      <!--
        Evidencias referenciadas por hash. Siempre la del sidecar; además, si el DIP lleva copia del
        último informe de integridad sellado, la del XAdES y la de su token de sello de tiempo.
      -->
      <xs:element name="evidence" type="dir:EvidenceType" maxOccurs="unbounded"/>
      <!-- Origen: lo que se comprobó sobre la firma del sidecar (vocabulario cerrado) -->
      <xs:element name="originStatus" type="dir:OriginStatusType"/>
      <!-- Limitaciones declaradas de este informe: 0..n códigos cerrados -->
      <xs:element name="limitations" type="dir:LimitationsType"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="EvidenceType">
    <xs:sequence>
      <!-- Qué es la evidencia -->
      <xs:element name="kind" type="dir:EvidenceKindType"/>
      <!-- Ruta de la entrada dentro del DIP -->
      <xs:element name="path" type="xs:string"/>
      <!-- SHA-256 hex en minúsculas de EXACTAMENTE los bytes de la entrada (SHA-256 o nada) -->
      <xs:element name="sha256" type="dir:Sha256Type"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="LimitationsType">
    <xs:sequence>
      <xs:element name="limitation" type="dir:LimitationType" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <!-- UUID en forma canónica (el emisor usa un UUID aleatorio) -->
  <xs:simpleType name="UuidType">
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- SHA-256 hex en minúsculas: 64 dígitos. Ninguna otra longitud (SHA-1, SHA-384, MD5) es admisible. -->
  <xs:simpleType name="Sha256Type">
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9a-f]{64}"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- SHA-256 hex tal como lo declara el sidecar sellado (puede venir en cualquier caja) -->
  <xs:simpleType name="Sha256AnyCaseType">
    <xs:restriction base="xs:string">
      <xs:pattern value="[0-9a-fA-F]{64}"/>
    </xs:restriction>
  </xs:simpleType>

  <!--
    dir:IntegrityStatusType: resultado de lo que el DIP comprobó.
    - VALID:         los PDF entregados coinciden con el sidecar sellado y la firma del sidecar es válida
    - INVALID:       alguno no coincide o la firma no es válida
    - INDETERMINATE: la comprobación no pudo completarse (no afirma nada sobre el paquete)
    Un DIP entregado solo puede ser VALID (D-01/D-02); ver la cabecera.
  -->
  <xs:simpleType name="IntegrityStatusType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="VALID"/>
      <xs:enumeration value="INVALID"/>
      <xs:enumeration value="INDETERMINATE"/>
    </xs:restriction>
  </xs:simpleType>

  <!--
    dir:ScopeType: qué ficheros se contrastaron.
    - PDF_FILES_DELIVERED: solo los PDF que lleva el DIP, contra el sidecar sellado
  -->
  <xs:simpleType name="ScopeType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="PDF_FILES_DELIVERED"/>
    </xs:restriction>
  </xs:simpleType>

  <!--
    dir:EvidenceKindType: tipo de evidencia referenciada por hash.
    - SEALED_SIDECAR:          sidecar sellado de sello #2 (aip-hash-attestation)
    - SEALED_REPORT_XML:       informe de integridad sellado (XAdES) copiado al DIP
    - SEALED_REPORT_TIMESTAMP: token de sello de tiempo RFC 3161 de ese informe
  -->
  <xs:simpleType name="EvidenceKindType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="SEALED_SIDECAR"/>
      <xs:enumeration value="SEALED_REPORT_XML"/>
      <xs:enumeration value="SEALED_REPORT_TIMESTAMP"/>
    </xs:restriction>
  </xs:simpleType>

  <!--
    dir:OriginStatusType: lo que se comprobó sobre el origen.
    - SIDECAR_SIGNATURE_VALID: la firma del sidecar sellado es válida. No acredita revocación ni
                               cualificación del certificado (véase la limitación correspondiente).
  -->
  <xs:simpleType name="OriginStatusType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="SIDECAR_SIGNATURE_VALID"/>
    </xs:restriction>
  </xs:simpleType>

  <!--
    dir:LimitationType: lo que este informe NO afirma o por qué falta algo (vocabulario cerrado).
    - NON_PDF_FILES_NOT_REVERIFIED:            los ficheros que no son PDF no se volvieron a verificar
    - NO_SEALED_REPORT:                        el paquete no tiene ningún informe de integridad sellado
    - LATEST_SEALED_REPORT_INCOMPLETE:         el último informe sellado está incompleto (la custodia
                                               muestra que falta el XAdES o el token, o no hay blobs) y
                                               por eso no se adjunta
    - LATEST_SEALED_REPORT_NOT_ATTACHED:       el último informe sellado no se pudo adjuntar porque falló
                                               la lectura o la comprobación de la custodia en la emisión;
                                               el código NO afirma la causa del fallo, ni si existe
                                               informe, ni cuál es su contenido
    - LATEST_SEALED_REPORT_HTML_NOT_RENDERED:  la copia sellada se leyó de la custodia pero no se pudo
                                               generar su versión legible (HTML) en la emisión, y no se
                                               adjunta una copia sin ella; el código NO afirma nada sobre
                                               el contenido de esa copia
    - REVOCATION_AND_QUALIFICATION_NOT_CHECKED: no se comprobó la revocación ni la cualificación del
                                               certificado de firma
  -->
  <xs:simpleType name="LimitationType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="NON_PDF_FILES_NOT_REVERIFIED"/>
      <xs:enumeration value="NO_SEALED_REPORT"/>
      <xs:enumeration value="LATEST_SEALED_REPORT_INCOMPLETE"/>
      <xs:enumeration value="LATEST_SEALED_REPORT_NOT_ATTACHED"/>
      <xs:enumeration value="LATEST_SEALED_REPORT_HTML_NOT_RENDERED"/>
      <xs:enumeration value="REVOCATION_AND_QUALIFICATION_NOT_CHECKED"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>
