L Luna Labs · Soporte
Concepto fundamental

Cegado de pacientes

El cegado en Luna Labs no es una política de "por favor no veas el nombre". Es una propiedad del sistema, implementada en cinco capas independientes desde la base de datos hasta el código que se publica.

Equipo Luna Labs 10 min de lectura Conceptual

En resumen

Un analista de Luna Labs no puede ver el nombre del paciente al capturar resultados. No por una política — por una separación estructural: el rol de base de datos del analista carece de permisos sobre la tabla de identidades. Si el responsable necesita desbloquear, debe registrar una razón que queda en bitácora.

Qué significa "cegado"

En medicina clínica, un estudio cegado es aquel donde quien realiza la medición no conoce información que podría influir en su interpretación. En un laboratorio, esto significa que el analista que captura un resultado no sabe a qué paciente pertenece la muestra. Solo conoce el folio, la edad, el sexo y el tipo de muestra.

El término en inglés es patient blinding o blinded analysis. En la jerga regulatoria mexicana, se relaciona con las disposiciones de NOM-004-SSA3-2012 sobre confidencialidad del expediente clínico.

Por qué importa

Hay tres razones, en orden de importancia:

  1. Calidad clínica. Un analista que sabe que la muestra es de un familiar, de un colega o de un paciente con un diagnóstico esperado, puede — sin darse cuenta — repetir un control hasta que "salga lo que debería". El cegado elimina ese sesgo.
  2. Privacidad por mínimo necesario. El analista no necesita el nombre del paciente para hacer su trabajo. No dárselo es la aplicación del principio de mínimo privilegio (también llamado need-to-know) a un dato sensible: el nombre asociado a un resultado clínico.
  3. Cumplimiento normativo. NOM-004 exige confidencialidad estricta del expediente clínico. Limitar el acceso a la identidad a quien realmente la necesita es la implementación correcta de esa obligación. Ver Cumplimiento NOM-004.

Qué ve el analista

Cuando un analista abre una orden, ve:

CampoVisible para el analista
FolioSí (p. ej. 2026-0481)
Edad y sexo
Tipo de muestraSí (sangre, orina, suero, etc.)
Estudios solicitados
Prioridad (normal / urgente)
Notas clínicas del médicoSí, si el responsable las marcó como visibles
Nombre del pacienteNo
ApellidosNo
CURP, RFC, NSSNo
Dirección y teléfonoNo
Médico tratanteNo

La interfaz del analista nunca muestra estos campos. La API que sirve a esa interfaz tampoco los expone. Y la base de datos a la que esa API se conecta no tiene permisos para leerlos.

Las cinco capas del cegado

El cegado se implementa redundantemente en cinco capas. Que las cinco fallen al mismo tiempo es lo que se necesitaría para que un analista pudiera ver un nombre. Cada capa está descrita en el código fuente y verificable.

  1. 1

    REVOKE en PostgreSQL

    El rol de base de datos luna_labs_analyst no tiene SELECT sobre la tabla patient_identities. Una consulta directa devuelve permission denied. Esto se aplica con scripts/init-db-roles.sql al provisionar el sistema.

  2. 2

    Dos clientes Drizzle separados

    El backend usa dos conexiones distintas al ORM Drizzle: analystDb con el rol cegado, y managerDb con el rol completo. No hay un cliente "súper" compartido. Ver lib/db/src/index.ts y lib/db/src/manager.ts.

  3. 3

    Rutas de API separadas por rol

    El servidor expone routes/analyst/* y routes/manager/*. Las rutas del analista nunca importan el cliente del responsable. Esta separación física en el árbol de archivos hace evidente cualquier intento de cruzar la línea.

  4. 4

    Middleware vinculado a la sesión

    Un middleware (attachDbContext) inyecta el cliente correcto en cada request según el rol de la sesión autenticada. Las rutas no importan la base de datos directamente — la reciben del middleware. Si la sesión es de analista, recibe el cliente cegado. Punto.

  5. 5

    Linter de blindaje automatizado

    Antes de cada commit y en cada PR, el script lint-blinding.sh falla si una ruta de analista importa el cliente de responsable o referencia patientName/patientIdentitiesTable. Es un seguro mecánico que previene errores humanos.

Defensa en profundidad. Si la capa 5 fallara y alguien escribiera código incorrecto, la capa 4 ya le habría pasado el cliente cegado. Si la capa 4 fallara, la capa 3 separa físicamente los archivos. Si las tres aplicaciones fallaran, la capa 1 — PostgreSQL — devolvería un error de permisos.

Desbloqueo controlado

Hay situaciones legítimas donde el responsable necesita ver el nombre del paciente desde el sistema: confirmar identidad antes de entregar, contactar al paciente por un resultado crítico, responder a una solicitud del médico tratante.

El responsable puede desbloquear la identidad de una orden específica con esta secuencia:

  1. Abre la orden en la vista de responsable.
  2. Hace clic en "Desbloquear identidad".
  3. El sistema le pide una razón obligatoria (texto libre). No puede dejarse en blanco.
  4. La razón se registra en la bitácora junto con el usuario, fecha, hora e IP.
  5. El nombre se muestra. La acción queda registrada permanentemente.

Los analistas no tienen esta opción en su interfaz — y, aunque la tuvieran, fallaría porque el rol de base de datos del analista no puede leer la tabla de identidades.

Cómo verificamos el cegado

Tres mecanismos verifican continuamente que el cegado sigue intacto:

  • Linter de blindaje en cada PR. Si alguien intenta hacer un cambio que rompería el cegado, el CI rechaza el cambio antes de que pueda llegar a producción.
  • Pruebas automatizadas. Hay pruebas que ejecutan consultas como analista contra la tabla de identidades y esperan que fallen. Si dejaran de fallar, el deploy se cancela.
  • Auditoría de la bitácora. Cada desbloqueo queda registrado con razón. El responsable puede revisar cuántas veces y por qué se ha desbloqueado en cualquier período.

Preguntas frecuentes

¿El cegado es un filtro visual?

No. Es una separación a nivel del rol de PostgreSQL. Aunque alguien intentara hacer una consulta directa a la base de datos con las credenciales del analista, fallaría.

¿Y si el analista necesita identificar una muestra mal etiquetada?

El flujo es: el analista escribe una nota en la orden ("muestra sin etiqueta"), el responsable la ve, desbloquea la identidad si es necesario, y resuelve. La separación de roles no impide la operación — la canaliza por el responsable, que es quien tiene la autoridad clínica.

¿Puedo configurar a un analista para que sí vea nombres?

No. Si un usuario necesita ver nombres, debe tener rol de responsable. No hay una configuración intermedia. Esta rigidez es intencional: la ambigüedad de roles es lo que rompe los modelos de privacidad en la práctica.

¿Esto cumple HIPAA / GDPR si exporto a Estados Unidos o Europa?

El principio de minimum necessary access (HIPAA) y de data minimisation (GDPR) está implementado por arquitectura. Sin embargo, cumplir esas normativas requiere acuerdos contractuales (BAA, DPA), localización de datos y otros controles que no son automáticos. Si necesitas operar bajo esos marcos, escríbenos.

¿Y si tengo un analista que también es responsable?

Una persona física puede tener una cuenta de cada rol — pero son sesiones separadas. No hay "cambio de rol" dentro de la misma sesión. Esto preserva la trazabilidad: cada acción queda atribuida al rol activo en el momento.