Saltar a contenido

ADR-047: La ficha provisional dura hasta la disposición final, el correo se autentica y ALTCHA pasa a v2

Estado: Aceptado Derogado en parte por ADR-065: D-3, purga de la ficha provisional. Siguen vigentes correo autenticado y ALTCHA. Fecha: 2026-10-22 Autores: Giampiero (mantenedor principal); lote D, bloque D-3 Relacionados: ADR-038 (enmienda su §6, el widget fijado en 2.3.0, y fija el destino de la ficha provisional), ADR-031 (Ley 1581), ADR-035, ADR-010


Contexto

Tres asuntos de la puerta pública: (1) la ficha provisional de quien radica sin autenticar quedaba para siempre aunque el radicado se eliminara por la TRD, conservando datos personales sin finalidad (Ley 1581 de 2012 [confirmar]); (2) el correo entrante se asociaba a una ficha por la sola dirección del remitente, que cualquiera puede falsificar; (3) ALTCHA v1 usaba un reto SHA-256 con maxnumber y la versión 2.3.0 del widget.

Decisión

  1. Purga de la ficha provisional con la disposición final: dentro de la transacción de cada radicado que la purga TRD elimina, purgar_provisional_huerfana elimina la ficha si ningún otro radicado la usa y la anonimiza (anonimizada_at, sin identidad) si es actor de alguno. Asientos document.tercero_provisional_eliminado|anonimizado. Migración tenant 054: origen_provisional (ventanilla|correo), CHECK chk_tercero_provisional_sin_identidad, trigger reject_tercero_conciliacion_rewrite que abre una transición de anonimización.
  2. Conciliación por lote: GET /terceros/por-conciliar/grupos agrupa por documento declarado o por correo; POST /terceros/conciliar-lote aplica UNA acción a 2..50 fichas del mismo grupo, todo o nada, con las reglas de la conciliación individual y un asiento por ficha con el mismo lote_id. Errores: 404 tercero_no_encontrado, 409 lote_no_homogeneo, lote_cambio, documento_ya_registrado, destino_invalido.
  3. Correo autenticado (E19): email_cuenta.authserv_id declara qué servidor receptor autentica la cuenta. core/autenticacion_correo.py (RFC 8601) confía solo en el primer Authentication-Results cuyo authserv-id es el declarado, exige SPF/DKIM/DMARC alineados con el dominio de From (alineación relajada con el punto: endswith("."+d)) y, sin authserv_id, falla cerrado. resolver_por_email(..., autenticado) no tiene valor por defecto: un correo no autenticado crea ficha provisional (origen_provisional='correo') y no se asocia a nadie. Se guarda email_mensaje.autenticacion y el asiento de radicación lo cita. PATCH /email/cuentas/{id}/authserv-id (USUA_PERM_ADMIN, asiento antes/después) es una ruta propia: es una decisión de confianza.
  4. Horario de atención: parámetro entidad_horario_atencion (tenant-service, migración tenant 017), servido con el contacto de la ventanilla.
  5. ALTCHA v2 (core/altcha.py): PBKDF2/SHA-256 con cost y prefijo calibrables (ALTCHA_COST, ALTCHA_PREFIJO_HEX), parameters firmados con HMAC-SHA256 sobre JSON canónico; la firma se verifica antes de derivar; anti-replay por signature. Widget altcha@3.3.0 fijado exacto (guardián de package.json).

Alternativas descartadas

  • Confiar en cualquier Authentication-Results: el remitente puede inyectar el suyo; solo vale el del servidor propio.
  • Conservar la ficha provisional siempre: datos personales sin finalidad tras la disposición.

Residuos declarados

  • Microsoft 365 no emite el authserv-id de forma conforme: queda NULL (todo correo sin autenticar) hasta confirmarlo [confirmar].
  • El vector de prueba de ALTCHA se generó con altcha-lib@2.4.0, no con el paquete del widget.
  • La calibración de ALTCHA_COST se afina en el navegador (Playwright) al cierre del lote.

Consecuencias

  • Una dirección falsificada ya no se vincula a la ficha de otra persona.
  • El widget y el servidor deben desplegarse juntos: el formato del reto cambió.