ADR-057: Soporte y formato por tipo documental (Ac. AGN 001/2024, Anexo 6) y semillas de integración sin disparadores¶
Estado: Aceptado Fecha: 2026-10-29 Autores: Giampiero (mantenedor principal); épica «soporte y formato por tipo documental», cierra la deuda B9 del lote D Relacionados: ADR-054 (cuadro público y certificado RUSD), ADR-025 (versionado de la TRD), ADR-053 (MCP)
Contexto¶
El Acuerdo AGN 001/2024 obliga a registrar en las TRD los formatos electrónicos de los tipos documentales (art. 4.1.4) y el Anexo 6 pide, en el campo «Soporte o Formato», dos cosas frente a cada tipo documental: marcar si se produce en físico («Papel») y, si es electrónico, indicar la extensión en que se produce y se preservará. Es información «mínima y obligatoria» para evaluar y convalidar la TRD. El Anexo 7 repite el campo para la TVD, que no tiene columna de tipos: va por agrupación. OrpycaMCP guardaba el tipo documental (código, nombre, plantilla) pero no cómo se produce.
Por separado, el carril de integración de archive-service instalaba cuatro disparadores itest_rellena_* que completaban en
silencio procedimiento, certificado RUSD, tipos documentales y reserva motivada: los tests pasaban con filas que el producto
rechaza, y escondían justo lo que el lote D volvió obligatorio. Con la obligatoriedad del soporte habrían sido el quinto atajo.
Decisión¶
1. Qué es «soporte» y «formato»¶
Dos campos ortogonales que calcan las dos columnas del Anexo 6: soporte_fisico BOOLEAN y formatos_electronicos TEXT[]. Un
tipo producido en papel y en electrónico se expresa sin inventar un tercer valor. La API expone además soporte ∈
{fisico, electronico, fisico_y_electronico} | null como derivado de lectura (null = no declarado). Descartado: un enum con
hibrido (redundante con la lista y reintroduce el vocabulario que medio_conservacion retiró a propósito).
Relación con radicados.medio_conservacion (electronico|fisico): mismo vocabulario, distinto objeto. El segundo es el soporte
del original de un radicado; los campos nuevos son los soportes admitidos para la clase. No hay FK ni CHECK entre
servicios.
El formato es un catálogo cerrado de códigos (orpycamcp_common.formatos_documentales): pdfa, pdf, tif, png, jpg,
gif, odt, ods, docx, xlsx, pptx, doc, xls, ppt, csv, txt, eml y xml, cada uno con extensión, MIME, PUID de PRONOM y
una marca informativa apto_preservacion (art. 7.1.2 par.: formatos abiertos). Texto libre habría producido «pdf», «.PDF»,
«PDF/A» y «pdfa» como cuatro cosas. El catálogo vive en tres sitios (Python, la función SQL td_formatos_validos y lo que
storage admite) y shared/tests/test_formatos_documentales_gemelos.py los ata. Solo se añaden códigos (quitar uno rompe el
CHECK de las filas que lo usan) y un código nuevo exige que storage admita su MIME en alguna de sus dos listas:
allowed_mime_types (anexos que sube una persona) o allowed_system_mime_types (artefactos que produce el sistema: el XML
y el .eml del correo recibido, Ley 527/1999 art. 12) — de ahí que eml y xml entren. Fuera a propósito: zip y —Q2—
audio y video, que storage no admite en ninguna lista: limitación declarada (las audiencias y grabaciones no se
pueden registrar como formato de un tipo hasta que storage los admita; ver docs/es/normativa.md).
Enmienda (2026-10-30): Q2 saldada por ADR-060:
el catálogo pasa a 26 códigos (WAV/BWF, FLAC, MP3, Opus, MPEG-4, QuickTime, Matroska, WebM) con la migración 085; la 082 se
conserva intacta. El PUID de PDF/A es
None a propósito: PDF y PDF/A comparten MIME y el PUID de PRONOM de un PDF/A lo da el validador según el perfil
(trd_series.pdfa_profile, migración 035), no el catálogo.
2. Dónde vive¶
- TRD: en
tipos_documentales(migración archive 082). Aquí la fila del tipo es el tipo-en-la-serie (UNIQUE (trd_serie_id, code)), así que una tabla aparte sería una relación 1:1 sin ganancia. - TVD: en
trd_series(solotipo_instrumento = 'TVD', CHECKtrd_series_soporte_forma). - Instantánea:
trd_serie_tipos_convalidadosgana las dos columnas; el cuadro público lee de ella (el histórico?vigente_endice el soporte que regía, no el vivo). Las filas anteriores a la 082 quedanNULL= «soporte no registrado», sin inventar.
3. Obligatoriedad y congelación¶
- En
borradores opcional. Aprobar exige que cada tipo activo que la versión tendrá al convalidarse (los propios más los heredables de la vigente que el re-apuntado le moverá) declare papel, formato o ambos: 409tipo_documental_sin_soportecon la lista de códigos. Convalidar y ratificar unamigradalo comprueban de nuevo sobre los tipos ya re-apuntados, dentro de la transacción y antes de la instantánea. La TVD: 409tvd_sin_soporteal aprobar + CHECK de respaldo. - El tipo es contenido de la versión (Ac. AGN 001/2024 art. 5.1.4.1 nums. 7 y 9 y su parágrafo, que exige llevar el registro
documentado de los cambios): el disparador
trg_tipos_documentales_congeladorechaza alta y baja fuera deborrador(unamigradatampoco admite tipos nuevos: solo la captura única del soporte vacío, patrón deprocedimiento), rechaza mover el tipo de serie fuera deborrador(única excepción: el re-apuntado de la convalidación, derogada → convalidada del mismo código) y rechaza reactivar un tipo inactivo fuera deborrador—un tipo inactivo no cuenta en el gate de soporte; la BAJA, que no es contenido, sigue libre—. Lee la(s) serie(s)FOR SHARE, que choca con elUPDATEde estado deaprobar: no hay carrera entre «añado un tipo» y «el Comité aprueba». El servicio toma el mismo bloqueo dentro de la transacción del alta/baja y traduce el rechazo del motor, si llegara, al mismo 409. - Hueco cerrado de paso:
TipoDocumentalService.create/deleteno comprobaban el estado de la serie (soloupdate). Ahora 409trd_version_inmutable, con el disparador de respaldo. La UI ofrece «Redeclarar en el borrador»: es la forma de cambiar el soporte de un tipo vigente (el código propio tapa al heredado).
4. Formato y política de preservación: aviso, no bloqueo¶
Al aprobar se calcula avisos_formato: formato_en_riesgo_segun_plan (el MIME del formato está en la política resuelta COMO el
job de migración de storage: formatos_origen del plan vigente o, si no declara ninguno, FORMAT_MIGRATION_MIME_TYPES del
despliegue; lo que el plan lista como formatos_destino no es riesgo, y pdfa nunca lo está por MIME) y formato_no_apto_conservacion (disposición CT o S sin ningún formato apto: «apto» es abierto y sin pérdida). Enmienda ADR-060 (C1): un tercer aviso, formato_apto_condicional, cuando el único apto es WAV o MKV, cuyo códec no se identifica: «apto según contenedor, códec sin verificar». Viajan
en la respuesta y en el asiento archive.trd_version_aprobada; la UI los muestra en un aviso persistente, no en un toast.
Si no se pudo leer el plan, avisos_formato_evaluados = false: «no sé», nunca «sin avisos». Un bloqueo convertiría una
actualización del plan en un instrumento inaprobable (la TRD convalidada es inmutable).
5. La radicación no se bloquea (Q3)¶
No se valida en la radicación que el anexo cumpla el formato del tipo (el derivado de lectura se calcula contra la TRD vigente el día del radicado: instantánea de la versión convalidada que regía, o el tipo vivo de la migrada): el art. 4.1.4 obliga a planear la producción, una
Entrada viene de fuera y la ventanilla no puede rechazarla por su extensión, y doc_class es solo el code (no único entre
series). Solo un derivado de lectura en GET /documents/{id}: conformidad_tipo {soporte, anexos_fuera_de_formato}, null
para Entradas, sin tipo o con tipo ambiguo; pdfa cuenta conforme solo con pdfa_status = 'conformant'. Deuda declarada: un
gate (no un aviso) para Salidas/Internas producidas fuera de E23 cuyo anexo no case con el formato del tipo.
Saldada por ADR-058: las Salidas e Internas (también por lote, E23 y
al retipificar) se gatean; las Entradas siguen sin bloqueo.
6. Certificado RUSD de una versión migrada (Q1)¶
Una migrada no tiene acto (CHECK de la 037) y sin certificado no transfiere ni elimina lo que gobierna. Puede registrar su
certificado una sola vez (fill-once por trigger, con asiento), por code + version en vez de por acto, y declara su
procedencia: el acto y la fecha de convalidación que el certificado inscribe (rusd_acto_declarado,
rusd_convalidacion_declarada, columnas que permiten validar). El CHECK trd_series_rusd_certificado_forma exige
convalidación declarada ≤ fecha del certificado (y el servicio, ≤ hoy); como la migrada tiene fecha_convalidacion NULL,
la procedencia declarada es lo que mantiene válida la fila al derogarse o relevarse por la N+1 (primera versión de la 082
exigía fecha_convalidacion en derogada y dejaba la fila sin salida: 23514 permanente). Al ratificar se exige además
fecha_convalidacion ≤ fecha del certificado (422 fecha_convalidacion_posterior_al_certificado).
7. Semillas de integración sin disparadores¶
Retirados los cuatro itest_rellena_* y los SET itest.*. Las semillas viven en tests/integration/_semillas.py y recorren el
camino real: create → tipos → aprobar → convalidar → certificado, expediente reservado validado con la misma regla que la API
(validar_reserva_expediente) y escrito con las siete columnas a la vez. La única excepción honesta es migrada
(sembrar_serie_migrada/marcar_migrada): no se alcanza por ningún acto, solo por el backfill de la 037. El guardián
tests/test_semillas_sin_atajos.py prohíbe en el resto del carril los disparadores de relleno, SET itest.*,
DISABLE TRIGGER, y los UPDATE/INSERT de estado o nivel, salvo una lista blanca con motivo (el sujeto ES el camino crudo) que no
puede envejecer. Esto destapó y corrigió el rojo latente de las pruebas que transfieren con una serie migrada (decía 409
trd_sin_certificado_rusd con o sin disparadores).
Citas¶
ArchiveService._exigir_procedimiento y la descripción MCP del procedimiento citaban el Acuerdo AGN 004/2019, derogado; ahora
«Ac. AGN 001/2024, Anexo 6, campo Procedimiento». Las menciones al 060/2001 de document-service quedan fuera de esta épica.
Consecuencias¶
- Datos previos (entorno de prueba): los tipos anteriores a la 082 quedan sin soporte; una versión que los herede no se aprueba
hasta redeclararlos en el borrador. Una TVD convalidada antes de la 082 no tiene soporte y no se backfillea: el CHECK de
respaldo exime a
derogada, así que puede derogarse o relevarse por la N+1; mientras sigaconvalidadasin soporte, cualquier UPDATE de esa fila (p. ej. registrar su RUSD) lo rechaza el CHECK: se redeclara en una versión nueva o se recrea el entorno de prueba (tenant_demotiene una así). Sin backfill ni ramas de compatibilidad. - Cambio de contrato del portal: el CSV público lleva
[soporte]en la celda de cada tipo y una columna nueva al final,soporte_formato(llena solo en filas TVD). - MCP: tool nueva
listar_formatos_documentales;crear_tipo_documentaly las tools de TVD ganansoporte_fisicoyformatos_electronicos; los certificados RUSD admitencode+version(migrada).actualizar_tipo_documentalno lo gana: el soporte es contenido de la TRD y se edita sobre un borrador. - La ratificación de una TVD
migradacon soporte no se implementa: una TVD nace enborradory nunca llega amigrada.
Ronda de corrección (2026-10-29, dos auditorías)¶
- Derogatoria. El Acuerdo AGN 001/2024 (art. 10.1) deroga expresamente los Acuerdos 060 de 2001 y 004 de 2019; las citas
al 004/2019 que quedaban en archive (acta de eliminación, selección
M, cuadro público) pasan al equivalente vigente (arts. 4.5.3, 4.5.4 num. 6 y par. 1, 7.2.1 par. 1, 5.1.3.2). Respaldo de la congelación de tipos: art. 5.1.4.1 nums. 7 y 9 (transformar tipos físicos en electrónicos; nuevos tipos documentales) y su parágrafo (registro documentado de cambios). - Decidido distinto (M3). La auditoría pedía congelar
activo. Se congela la reactivación (false → true) fuera deborrador, que es la vía por la que un tipo sin soporte volvería al contenido sin pasar por el gate; la baja (true → false) sigue libre: no es contenido (la instantánea no cambia) y es la forma de retirar un tipo que ya no se usa sin crear una versión nueva. Un tipo dado de baja en una versión convalidada solo vuelve redeclarándolo en el borrador. - Respaldo del motor con rostro (L2). Alta y baja de tipos toman
FOR SHAREla serie dentro de su transacción y, si el disparador rechaza por una carrera, el servicio responde el mismo409 trd_version_inmutable;aprobarde la TVD traduce el CHECK de respaldo a409 tvd_sin_soporte. - Guardián de semillas (L1). Detecta también
session_replication_role,DROP TRIGGER,UPDATEcon alias ynivel_seguridaden cualquier posición delSET, con controles negativos.
Enmienda (2026-11-06, decisión del dueño): el ZIP entra como anexo¶
«Los zip van como anexos a los expedientes y a los documentos que se radican como tal; quien lleva la TRD es el expediente y el radicado, no el anexo». La frase «fuera a propósito: zip» queda superada. zip (application/zip, PUID x-fmt/263, apto_preservacion=False) entra al catálogo con solo_anexo=True:
- La TRD no lo gobierna. No está en
CODIGOSni entd_formatos_validos(sin migración): declararlo enformatos_electronicoses422 formato_solo_anexo. El selector de formatos deadmin/trdyadmin/tvdno lo ofrece. - El evaluador (único,
conformidad_tipo) no juzga un anexo subido de ese formato contra losformatosdel tipo, y un radicado o expediente cuyo único anexo es ZIP quedasolo_soporte: del formato no se afirmó nada. El soporte se sigue juzgando; el asiento marcaeximidoyexencion: solo_anexoen ese anexo. Es la única exención: un.docxen un tipo que solo admite PDF sigue fuera, y el MIME es el defiles(storage lo detecta por contenido: un.docxrotulado «zip» se registra como lo que es). - Nunca principal. Un ZIP marcado
es_principales422 zip_no_puede_ser_principal; sin principal no llega a firma, versión pública ni envío como pieza principal. - Limitación declarada. Orpyca no inspecciona el contenido del ZIP ni tiene antivirus; su contenido no se indexa ni se preserva por separado (se conserva el contenedor tal cual).