Resultados Experimento 3 ‐ Facilidad de modificación mediante Puertos y Adaptadores - JuanHerreraP/Proyecto-MISO-Solventa-Grupo-11 GitHub Wiki

Experimento 3 — Facilidad de modificación mediante Puertos y Adaptadores (EC06)

Qué valida

Hipótesis de diseño: si la integración de KYC se implementa mediante el patrón Puertos y Adaptadores, manteniendo una interfaz interna estable (IdentityVerificationProvider) entre el servicio de Identidad y los proveedores externos, entonces es posible sustituir el proveedor KYC sin modificar el servicio de Identidad ni los demás componentes consumidores.

Punto de sensibilidad: el contrato del puerto IdentityVerificationProvider entre el servicio de Identidad y la implementación concreta del proveedor KYC.

Estructura

app/
  domain/
    models.py      # VerificationRequest / VerificationResult / VerificationStatus (modelo agnóstico de proveedor)
    ports.py        # IdentityVerificationProvider (el puerto)
  adapters/
    kyc_provider_a.py  # Adaptador + cliente simulado del Proveedor A (contrato REST plano, en inglés)
    kyc_provider_b.py  # Adaptador + cliente simulado del Proveedor B (contrato anidado, en español, confianza invertida)
  config.py          # Lee KYC_PROVIDER (env var) — único mecanismo de configuración
  main.py             # Servicio de Identidad (consumidor): endpoint /identidad/verificaciones
tests/
  test_contract_regression.py   # Suite de regresión: MISMAS pruebas corridas contra Proveedor A y Proveedor B
  test_adapter_provider_a.py    # Unitarias del adaptador A (traducción de contrato)
  test_adapter_provider_b.py    # Unitarias del adaptador B (traducción de contrato)

El servicio (app/main.py) es el "consumidor" bajo prueba: en ningún punto de ese archivo se referencia KYCProviderAAdapter ni KYCProviderBAdapter fuera de la función de ensamblaje get_identity_verification_provider. Esa función lee la variable de entorno KYC_PROVIDER y decide qué adaptador inyectar — es el único lugar del servicio que conoce que existen dos proveedores.

Los dos proveedores simulados tienen contratos deliberadamente distintos para que la sustitución sea una prueba real y no un caso trivial:

Proveedor A Proveedor B
Forma de la solicitud Campos planos, en inglés Objeto anidado (solicitante), en español
Formato de fecha YYYY-MM-DD DD/MM/YYYY
Vocabulario de estado APPROVED / REJECTED / PENDING OK / RECHAZADO / EN_REVISION
Escala del puntaje Entero 0-100 (a mayor score, mayor riesgo) Flotante 0.0-1.0 (a mayor score, menor riesgo — es confianza, no riesgo)

Cómo correrlo

Linux / macOS (bash):

cd experimentos/experimento-3-puertos-adaptadores-kyc
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# Suite completa (parametrizada internamente sobre A y B)
pytest -v

# Levantar el servicio con un proveedor u otro (para probar manualmente / grabar evidencia en video)
KYC_PROVIDER=A uvicorn app.main:app --port 8001
KYC_PROVIDER=B uvicorn app.main:app --port 8002

Windows (PowerShell):

cd experimentos\experimento-3-puertos-adaptadores-kyc
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements.txt

pytest -v

$env:KYC_PROVIDER = "A"
uvicorn app.main:app --port 8001

Evidencia de ejecución (2026-09-10)

Regresión automatizada — 3 corridas independientes, mismo resultado:

Entorno Resultado
Sandbox cloud (Linux, Python 3.11) 16/16 pasan con KYC_PROVIDER=A y 16/16 con KYC_PROVIDER=B
Puente al equipo del integrante (Linux VM, Python 3.10) 16/16 pasan con KYC_PROVIDER=A y 16/16 con KYC_PROVIDER=B
PowerShell del integrante (Windows, Python 3.14, venv real del proyecto) pytest -v corrido por el integrante — 16/16 pasan
======================== 16 passed, 1 warning in 0.07s =========================   (KYC_PROVIDER=A)
======================== 16 passed, 1 warning in 0.06s =========================   (KYC_PROVIDER=B)

Prueba manual del servicio real, en tres entornos distintos, mismo resultado byte a byte:

--- Proveedor A ---
POST /identidad/verificaciones -> {
    "verification_id": "A-1000000034-4489",
    "status": "REJECTED",
    "risk_score": 0.89,
    "checked_at": "2026-09-10T00:17:51.005768"
}
GET /salud -> {"status":"ok","proveedor_kyc_activo":"A"}

--- Proveedor B ---
POST /identidad/verificaciones -> {
    "verification_id": "B-1000000034-4489",
    "status": "REJECTED",
    "risk_score": 0.81,
    "checked_at": "2026-09-10T00:17:52.684556"
}
GET /salud -> {"status":"ok","proveedor_kyc_activo":"B"}

El integrante repitió esta misma llamada de forma independiente en su propia máquina Windows con Invoke-RestMethod (puertos 8001 y 8002) y obtuvo exactamente los mismos valores: A-1000000034-4489 / REJECTED / 0.89 para el Proveedor A, y B-1000000034-4489 / REJECTED / 0.81 para el Proveedor B. Esto confirma que el experimento es determinístico y reproducible independientemente del sistema operativo o de quién lo ejecute — no es un resultado que solo se dio una vez en un ambiente controlado.

El contrato de respuesta hacia el consumidor (forma del JSON, nombres de campos, vocabulario de estado, escala 0.0-1.0 del riesgo) es idéntico sin importar el proveedor activo. La diferencia de risk_score (0.89 vs. 0.81) es esperable y correcta: cada proveedor simulado calcula el riesgo con su propia lógica interna; lo que el experimento valida no es que ambos den el mismo número, sino que ninguna de esas diferencias se filtra fuera del adaptador.

CI — regresión automática

.github/workflows/experimento-3-kyc-regression.yml ejecuta esta misma suite en GitHub Actions dos veces en paralelo (matriz KYC_PROVIDER: [A, B]), en cada push/PR que toque esta carpeta, y publica el resultado de cada corrida como artefacto (resultados-A.xml / resultados-B.xml) — esta es la evidencia a enlazar en el video de la Entrega 6.

Interpretación de resultados

Tabla de interpretación definida desde el diseño del experimento en Semana 4 (ver claude/SEmana 4 / claude/Semana 5 en el proyecto), con el resultado real obtenido resaltado:

Resultado posible Interpretación ¿Ocurrió en esta ejecución?
El proveedor se sustituye modificando únicamente el adaptador y existen cero cambios en los consumidores La evidencia obtenida soporta la hipótesis de diseño y el criterio evaluado de EC06. ✅ Sí — este es el resultado obtenido.
Es necesario modificar el servicio de Identidad u otro consumidor La hipótesis queda refutada porque el cambio del proveedor se propagó fuera del adaptador. No. app/main.py no se tocó entre la corrida con Proveedor A y con Proveedor B.
Es necesario modificar el puerto IdentityVerificationProvider El contrato interno presenta acoplamiento con las particularidades del proveedor y debe revisarse antes de considerar validada la hipótesis. No. app/domain/ports.py no cambió; el puerto siguió siendo verify(request) -> result en ambos casos.
El cambio queda aislado en el adaptador, pero aparecen fallos en la regresión La localización estructural del cambio funciona, pero la sustitución no mantiene completamente el comportamiento esperado. Se requiere analizar los contratos y transformaciones involucrados. No. Las 16 pruebas de la suite de regresión (contrato + validación de entrada + salud) pasaron igual con ambos proveedores, en tres entornos distintos.

Conclusión

La evidencia recolectada — 16/16 pruebas automatizadas pasando igual con ambos proveedores en tres entornos independientes (sandbox cloud, puente remoto, y la máquina Windows del integrante), más la verificación manual del servicio real con resultados idénticos y reproducibles — soporta la hipótesis de diseño. El patrón Puertos y Adaptadores, implementado mediante el puerto IdentityVerificationProvider y adaptadores concretos por proveedor, permite sustituir el proveedor KYC sin propagar el cambio al servicio de Identidad ni a los demás componentes consumidores. Esto valida el criterio de calidad EC06 — Facilidad de modificación para el punto de sensibilidad evaluado (cambio de proveedor KYC).

No se presentaron indicios de acoplamiento entre el puerto y las particularidades de ningún proveedor, ni fue necesario ajustar la interfaz IdentityVerificationProvider durante la implementación de ninguno de los dos adaptadores — un indicador adicional (no parte de la tabla original, pero relevante) de que el diseño de la interfaz fue lo suficientemente pequeño y orientado al negocio como para no filtrar detalles de un proveedor específico.

Decisiones de diseño confirmadas por esta evidencia:

  • Mantener IdentityVerificationProvider como la única vía de acceso del servicio de Identidad a la verificación KYC (sin llamadas directas a proveedores desde otros puntos del código).
  • Mantener la traducción de contrato (nombres de campo, formato de fecha, vocabulario de estado, normalización de score) encapsulada dentro de cada adaptador, y no en el servicio consumidor.

Decisiones que no fue necesario corregir o revisar: ninguna — no se identificó ningún punto donde el diseño actual del puerto o del servicio de Identidad necesitara ajustarse a partir de este experimento.