# Manual técnico de operaciones — IA Gobernanza

> Audiencia: especialistas en seguridad, DevSecOps, oficiales de cumplimiento con perfil técnico. Describe procedimientos operativos, contratos de API y semántica de cada control tal como está implementado. Donde un control es una hoja de ruta y no una capacidad actual, se indica explícitamente.
>
> Versión 1.0 · Base URL: `https://<su-dominio>/api` · Todas las rutas del plano de control exigen sesión de operador (cookie `gov_session`, httpOnly, SameSite=Lax, 8 h). Rutas de datos usan API key (`Authorization: Bearer gov_live_*` o `X-API-Key`).

---

## 1. Arquitectura de referencia

```
[Apps del cliente] ──Bearer gov_live_*──▶ /api/v1/gateway/chat/completions ──▶ Conector (Ollama/vLLM local · Fireworks · DeepSeek · …)
        │                                  │ pre-auditoría (<50 ms) · ZK anonimización · post-auditoría ISO 42001
        │                                  └─▶ connector_transactions (hash/métricas) · incidents · webhooks HMAC v2
[SDK aiguard / Muro Perimetral] ──X-API-Key──▶ /api/v1/public/evaluate-stream (fail-closed PII)
[Operadores] ──cookie + MFA TOTP──▶ /api/{models,policies,killswitch,connectors,threats,keys,webhooks,audit,...}
Persistencia: MongoDB (tenant-scoped por company_id) · Vault efímero ZK: Redis (REDIS_URL) o MongoDB TTL
```

Principios implementados:
- **Multi-tenancy por actor:** toda consulta filtra por `company_id` derivado de la sesión o de la API key; accesos por id a recursos ajenos devuelven 404.
- **Zero-Knowledge fail-closed:** `/v1/public/evaluate-stream` rechaza PII en claro (422 `PII_PLAINTEXT_REJECTED`) y solo persiste hashes. El Gateway anonimiza PII hacia destinos externos con mapa cifrado efímero (TTL ≤ 300 s).
- **Kill Switch por consenso (anti-FP):** Capa 1 regla dura · Capa 2 confianza (risk ≥ 55) · Capa 3 persistencia (≥ 3 eventos en 5 s). Las amenazas de usuario **no** disparan el KS por sí solas.
- **Auditoría tamper-evident:** `audit_events` encadenada por SHA-256 (`prev_hash` → `hash`), verificable en `GET /api/audit/verify-chain`.

---

## 2. Identidad, MFA y RBAC

| Ruta | Método | Rol | Notas |
|---|---|---|---|
| `/auth/login` | POST | — | `{email,password}`. bcrypt(12). Rate limit 5/min por IP+email. Si el usuario tiene MFA → `{mfa_required:true, mfa_token}` (JWT purpose=mfa, 5 min). |
| `/auth/mfa/verify` | POST | — | `{mfa_token, code}` o `{mfa_token, recovery_code}` → cookie de sesión. 5 intentos/min por usuario. |
| `/auth/mfa/setup` · `/enable` · `/disable` · `/recovery-codes` | POST | sesión | TOTP RFC 6238 (otplib, ventana ±30 s). Secreto cifrado AES-256-GCM con `MFA_ENC_KEY`; recovery codes solo como SHA-256. |
| `/auth/users` | GET/POST/PUT/DELETE | admin | Crear/rotar rol/deshabilitar/`mfa_reset:true`. Último admin activo no puede degradarse. |
| `/auth/change-password` | POST | sesión | Invalida sesiones previas (`session_version`). |

**Enforcement MFA (`MFA_REQUIRED_ROLES=admin,operator`):** un usuario de rol obligado sin MFA solo puede ejecutar `GET`; toda mutación devuelve `403 {code:'MFA_ENROLLMENT_REQUIRED'}`. En producción el propio usuario **no** puede desactivar su MFA; otro admin (con MFA) lo reinicia vía `PUT /auth/users/:id {mfa_reset:true}`.

**RBAC (`requiredRoleFor`):** GET → viewer · killswitch/simulate/incidents/threats/webhooks test/connectors test → operator · resto → admin. Desactivar un Kill Switch exige admin + `reason` obligatorio + evento de auditoría + webhook firmado.

**Rotación JWT:** firma con `JWT_SECRET`; verificación acepta `JWT_SECRET_PREVIOUS` durante la ventana de rotación. Proveedor de secretos: `SECRETS_PROVIDER=env|aws` (AWS Secrets Manager soportado en código; **no configurado** en esta instalación).

---

## 3. Modelos gobernados y Kill Switch

- `POST /api/models {name, provider, type, risk_sector}` crea `ai_models_registered` + `killswitch_configs {mode:'alert', status:'inactive', trigger_threshold:80}`.
- `PUT /api/killswitch/:modelId {status:'active'|'inactive', mode:'alert'|'block', reason}`. `mode:'block'` marca el modelo `blocked` y toda evaluación/gateway devuelve bloqueo determinista. Desactivación: admin + reason.
- Disparo automático: `evaluateEvent` / `evaluateV1` / Gateway registran `risk_events` (TTL) y aplican `decideAction(layers, circuitMode)`:
  - `ACTION_KILLSWITCH_TRIGGER` (L1∧L3, L2∧L3 o L1 aislada en motor de políticas), `ACTION_REDACT_AND_SUBSTITUTE` (L2), `ACTION_LOG_AND_MONITOR`, `ACTION_ALLOW`, `HUMAN_ALERT_REQUIRED` (circuit breaker: 100 % de la flota fallando, ≥ 2 modelos, congelación 30 s).
- Cada decisión lleva `decision_hash` (SHA-256 sobre inputs exactos) para anti-repudio.
- Webhooks: `killswitch.activated`, `killswitch.deactivated`.

**Procedimiento de reactivación (runbook):**
1. Consultar `GET /api/incidents` y `GET /api/threats` para la causa (`last_trigger_cause`).
2. Verificar que la causa está contenida (p. ej. API key del atacante revocada, conector corregido).
3. `PUT /api/killswitch/:id {status:'inactive', mode:'alert', reason:'<ticket + justificación>'}` como admin con MFA.
4. Confirmar recepción del webhook en el SIEM y verificar la cadena: `GET /api/audit/verify-chain → chain_valid:true`.

---

## 4. Políticas (motor determinista)

`governance_policies {name, regulation, framework, applies_to[], policy_rules}`. Reglas soportadas: `max_bias`, `max_privacy_risk`, `max_risk_score`, `max_tokens_per_request`, `forbidden_categories[]`, `requires_killswitch`, `max_toxicity`, `max_semantic_drift`, `pii_forbidden`, `prompt_injection_forbidden` (+`injection_threshold`), `system_prompt_leak_forbidden`, `max_pii_tokens_out`, `applies_to_stage`. La política **AI Threat Shield** se crea automáticamente por tenant si no existe. Cache de políticas en Mongo con invalidación por versión (`policies_version`).

---

## 5. Conectores de IA (modelos propios) y Gateway

### 5.1 Modelo de datos
- `ai_connectors`: `{name, provider, base_url, network(public|private|loopback), egress{mode: direct|direct_private|proxy, proxy_id}, api_key_enc (AES-256-GCM, CONNECTOR_ENC_KEY), api_key_hint, default_model, model_id (→ ai_models_registered), sovereignty{kind, data_leaves_perimeter, processor_jurisdiction, model_origin, risk_level, regulatory_flags[]}, governance{...}, status, last_test}`.
- `connector_egress_proxies`: proxies inversos autorizados (`proxy_url https`, `allowed_cidrs[]`, `auth_token_enc`). Requeridos para destinos privados salvo `ALLOW_PRIVATE_EGRESS_DIRECT=true` (despliegue on-prem/demo).
- `connector_transactions` (TTL = `governance.retention_days`): `{transaction_id, kind, latency_ms, upstream_ms, audit_ms, tokens{prompt,completion,total}, compliance_status, geopolitical_risk, data_left_perimeter, zk{anonymized,restored,unresolved,by_type}, rule, violations[], kill_switch_action, request_hash, decision_hash}`. **Nunca** texto.

### 5.2 Reglas de gobernanza por conector (`PUT /api/connectors/:id/governance`)
| Campo | Default | Efecto |
|---|---|---|
| `pii_filter_lfpdppp` | true | Escaneo PII (PAN, CURP, RFC, CLABE, CPF, RUT, EMAIL, PHONE). |
| `zk_anonymize_external` | true | Anonimización reversible hacia destinos externos (GovernanceZKEngine). |
| `prompt_injection_detection` | true | Threat Shield determinista + normalización anti-evasión (base64, leetspeak, zero-width, NFKC). |
| `kill_switch_threshold` | 80 | Sensibilidad: solo riesgos ≥ umbral alimentan el consenso (Bajo 90 · Medio 80 · Alto 65). |
| `block_on_geopolitical_risk` | `alto` | Bloquea egreso de PII sin anonimizar hacia procesadores con ese riesgo o superior. |
| `post_audit_enabled` · `post_audit_block_threshold` | true · 75 | PostAuditEvaluator; `riskScore > 75` o violación crítica → `BLOCK_KILL_SWITCH`. |
| `kill_switch_on_output_leak` | true | Violación crítica en la salida (fuga de secreto/system prompt, jailbreak exitoso) → KS inmediato del modelo vinculado. |
| `forbidden_keywords[]` · `confidential_terms[]` | [] | Lista del admin; los términos confidenciales se persisten **solo como SHA-256** (`confidential_terms_hashes`). |
| `max_tokens_per_request` · `retention_days` | 8192 · 90 | Límite (413) y retención de la bitácora de transacciones. |

### 5.3 Anti-SSRF (`analyzeBaseUrl`)
Solo `http(s)`; sin credenciales embebidas; resolución DNS en alta y **en cada llamada** (anti-rebinding); clases: `public`, `private` (RFC1918/fc00::/7), `loopback`, `blocked` (169.254/16 metadata, 0/8, 100.64/10 CGNAT, multicast, fe80::/10, fd00:ec2::). `blocked` nunca se permite. Público sin TLS → advertencia. Redirecciones no se siguen (`redirect:'manual'`).

### 5.4 Gateway OpenAI-compatible
`POST /api/v1/gateway/chat/completions` (alias `POST /api/v1/chat/completions`) · `GET /api/v1/gateway/models`.

Selección de conector: header `X-IAG-Connector: <id|nombre>`, o `model = "<nombre conector>"`, o `model = "<conector>/<modelo upstream>"`; con un único conector activo se usa por defecto y `model` pasa como upstream.

Secuencia:
1. Auth Bearer (scope `gateway:invoke` o `evaluate:stream`), rate limit por key (`X-RateLimit-*`).
2. Corto circuito: conector `disabled` → 403 `CONNECTOR_DISABLED`; KS `active+block` o modelo `blocked` → 403 `KILL_SWITCH_ACTIVE`.
3. Pre-auditoría síncrona (sin I/O): tokens (413 `MAX_TOKENS_EXCEEDED`), Threat Shield (score ≥ 0.6 → 403 `PROMPT_THREAT_BLOCKED` con `rule{id,name,framework,severity,matched_patterns}`, `kill_switch{triggered,consensus_action,layers}`), PII, geopolítico (403 `GEOPOLITICAL_PII_EGRESS`), anonimización ZK (mapa → `TokenCacheService.saveSessionMap(tx_gober_<uuid>)`, TTL 300 s).
4. Forward al upstream (`Authorization: Bearer <api_key descifrada>`), timeout de cabeceras 120 s. `stream_options.include_usage` se añade cuando el proveedor lo soporta.
5. Retención completa de JSON o SSE: límite de 2 MB y 120 s de lectura del cuerpo. No se entrega contenido mientras el proveedor genera la respuesta. SSE requiere `finish_reason` y `[DONE]`; cierre incompleto, JSON inválido, tamaño excesivo, timeout o canal no auditable → error, nunca `APPROVED`.
6. Post-auditoría de las elecciones completas, texto de razonamiento/rechazo y llamadas textuales a herramientas. Términos prohibidos, PII residual o tokens inventados bloquean la salida. Los detectores siguen siendo deterministas, no universales. Sólo después se restauran tokens conocidos; borrado del mapa al terminar, incluso en error o cancelación.
7. Entrega JSON o envoltura SSE posterior a auditoría, **sin streaming de texto en tiempo real**. Header `X-IAG-Delivery-Mode: buffered-audited`, metadata `iag_governance.delivery_mode`; un bloqueo devuelve HTTP 403 antes de entregar texto del proveedor. Un cliente SSE debe manejar errores JSON no-200.

Estados de `compliance_status`: `APPROVED`, `BLOCKED_INJECTION`, `BLOCKED_OUTPUT`, `BLOCKED_GEOPOLITICAL`, `BLOCKED_KILL_SWITCH`, `BLOCKED_POLICY`, `UPSTREAM_ERROR`, `CLIENT_ABORTED`.

### 5.5 GovernanceZKEngine y TokenCacheService
- Tokens `[CURP_n]`, `[RFC_n]`, `[FINANCIAL_n]` (tarjeta con Luhn, CLABE), `[PHONE_n]`, `[EMAIL_n]`, `[NAME_n]` (honoríficos e introductores en español). Mismo valor → mismo token; índices ya presentes en el texto se reservan; cada valor cifrado AES-256-GCM con IV aleatorio y **AAD = token** (impide intercambiar entradas). Clave por tenant: `HKDF(CONNECTOR_ENC_KEY, company_id)`; nunca se persiste.
- Vault: `REDIS_URL` (driver oficial `redis` v4, reconexión con backoff, `SET NX EX ≤300`) con respaldo MongoDB TTL (`zk_token_maps`). Estado: `GET /api/public/status → hardening.zk_token_cache`.
- Métrica objetivo: anonimizar+desanonimizar < 15 ms; pre-auditoría < 50 ms. Observado en pruebas internas: `audit_ms` ≈ 1–5 ms.

### 5.6 Integración de una aplicación cliente
```bash
export OPENAI_BASE_URL=https://<dominio>/api/v1/gateway
export OPENAI_API_KEY=gov_live_********
# Cualquier SDK OpenAI-compatible funciona: model = nombre del conector
curl $OPENAI_BASE_URL/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H 'Content-Type: application/json' \
  -d '{"model":"DeepSeek R1 Local","stream":true,"messages":[{"role":"user","content":"..."}]}'
```
Recomendado: enviar `X-IAG-User-Ref: <id opaco del usuario final>` para análisis de comportamiento (burst/probing/extracción) sin exponer identidad.

### 5.7 MOCK de pruebas (solo `DEMO_MODE=true`)
`/api/mock-llm/v1/{models,chat/completions}` — OpenAI-compatible, soporta `stream`. El prompt `simula_fuga` produce una salida maliciosa (token inventado + jailbreak) para ejercitar la post-auditoría. **No existe en producción.**

### 5.8 Vista previa de repositorios de agentes — SIMULADA (MOCK)
Este panel **no tiene un escáner ni conexión a GitHub/GitLab**. No audita repositorios reales ni acredita cumplimiento.
- `GET /api/agents/status` (sesión): informa `integration_status:not_connected`, `real_audit_available:false`, `audited_repositories:0` y si el usuario puede cargar ejemplos.
- `GET /api/agents/repos` (sesión): array de muestras con `data_source:demo`, `is_demo:true`, `verification_status:simulated`; sin modo demo devuelve `[]`. Los registros históricos sin procedencia no se muestran; no se eliminan.
- `POST /api/agents/seed` (admin y controles MFA existentes, sólo `DEMO_MODE=true`): carga explícita de ejemplos idempotente, sin borrar registros. Fuera de demo está deshabilitado (404 tras superar autenticación/autorización).
- Abrir o actualizar el panel **no crea datos**. Sus porcentajes y conflictos se etiquetan como ejemplos, sin commits ni sincronizaciones reales. Sin muestras no se calcula un índice de cumplimiento.


---

## 6. Gobernanza agéntica: propuestas y autoridad

- `GET /api/agent-policies` devuelve la configuración **efectiva** y, separadamente, `pending_change`, `pending_action`, `pending_id` y `revision`. Una edición pendiente no retira la regla vigente del evaluador.
- Con Cuatro Ojos, crear/editar/pausar/reactivar/eliminar requiere validar por otro `gov_admin`. `POST /api/agent-policies/:id/validate` y `/reject-change` reciben `pending_id` y credencial de reautenticación; el cliente debe enviar `revision` conocida para evitar una vista obsoleta. No se sustituye una propuesta pendiente por otra.
- Desactivar Cuatro Ojos mediante `PUT /api/governance/settings` genera propuesta y conserva `dual_control_enabled:true`. Se resuelve con `POST /api/governance/settings/validate` o `/reject-change`, `pending_id` y reautenticación; validación requiere otro administrador.
- Aprobar/rechazar `/api/agent-approvals/:id/{approve,reject}` exige el rol snapshot de la regla. `gov_admin` puede resolver ambas categorías; `gov_approver` no puede resolver una reservada a admin. El cargo humano descriptivo no se usa como permiso.
- La resolución usa comparación atómica `status:PENDING` y expiración: un único ganador, perdedor `409 DECISION_CONFLICT`. Actualizar la bandeja, no repetir una acción ciegamente. Poll: `GET /api/v1/agent/decision/:id` (singular), estados en mayúsculas y `execution_token` sólo al aprobar.
- No existe endpoint de consumo/verificación de uso único del execution_token; la integración ejecutora debe respetar la autorización.
- Kill-switch: un disparo no autoriza cambiar `mode`, `auto_trigger` o `trigger_threshold`. Para operator, omitir esos campos incluso si desea conservar su valor; su presencia devuelve 403. Sólo admin configura. `alert` no detiene tráfico y `block` sólo protege el camino integrado.
- Evidencia pública: `GET /api/public/capabilities` y `/trust#evidencia`; registros documentales curados, no telemetría en vivo. Los campos sin prueba registrada mantienen `last_verification:null`.

## 6b. AI Threat Shield
Detectores deterministas (Capa 1) con pesos: `ignore_instructions`, `reveal_system_prompt`, `role_override`, `dan_jailbreak`, `delimiter_injection`, `exfil_instruction`, `dump_data`, `encoded_payload`, `tool_abuse`; análisis de comportamiento por `user_ref` (burst ≥ 30/min, tasa de violaciones, plantillas repetidas → `MODEL_EXTRACTION_SUSPECTED`, tokens PII en salida → `DATA_EXFILTRATION_ATTEMPT`); huella de system prompt por shingles hasheados (`PUT /api/models/:id/system-prompt-fingerprint`). Mapeo OWASP LLM Top 10 / MITRE ATLAS. Incidentes `THREAT_DETECTED` con dedup 10 min; webhook `threat.detected` con pistas OCSF (class_uid 2004).

Operación: `GET /api/threats`, `PUT /api/threats/:id/ack`, `PUT /api/threats/:id/resolve {resolution, note}`, `POST /api/threats/simulate` (operator, DEMO).

---

## 7. API pública, SDK y Muro Perimetral
- `POST /api/v1/public/sessions` (scope `sessions:create`) → `session_token` por modelo/usuario.
- `POST /api/v1/public/evaluate-stream {session_token, text_payload, stage: INPUT|OUTPUT}` (scope `evaluate:stream`). Tokens `[TOKEN_<TIPO>_<HASH>]` del SDK se aceptan como PII anonimizada; PII en claro → 422 fail-closed (`ZK_FAIL_CLOSED=true`).
- `GET /api/v1/public/healthcheck` → heartbeat (Dead Man’s Switch: ausencia > 60 s → `stale`, incidente DMS con dedup 15 min).
- SDK Python `aiguard` (`/sdk`): `GovernanceClient`, `RedactionEngine`, `RedisTokenVault`, mTLS opcional, `threats.py`. Muro Perimetral (`/deploy/perimeter-wall`): proxy K8s con redacción local y vault Redis. **No publicado en PyPI**; se entrega como código.

---

## 8. API keys y Webhooks
- `POST /api/keys {name, scopes[], expires_in_days, rate_limit_per_min}` → la key en claro se muestra **una sola vez**; se persiste `key_hash` SHA-256 (en DEMO además `plain`, exclusivamente para evaluación). `DELETE /api/keys/:id` revoca de inmediato. Scopes: `sessions:create, evaluate:stream, metrics:write, metrics:read, policies:read, policies:write, killswitch:read, killswitch:override, logs:read, keys:manage, gateway:invoke`.
- Webhooks HMAC v2: cabeceras `X-IAG-Timestamp`, `X-IAG-Nonce`, `X-IAG-Signature: v2=HMAC-SHA256(timestamp.nonce.body)`; ventana ±5 min, anti-replay por nonce, reintentos 2/4/8/16/32 s. Eventos: `killswitch.activated|deactivated`, `policy.violation`, `threat.detected`. Verificación de ejemplo en `/docs/WEBHOOKS.md`.

---

## 9. Auditoría y evidencia
- `GET /api/audit?limit=` (admin) — eventos con `seq`, `prev_hash`, `hash`, actor, IP, `details` saneados (claves sensibles redactadas).
- `GET /api/audit/verify-chain` — recalcula la cadena; `chain_valid:false` implica alteración o pérdida.
- Logs de evaluación: `monitoring_logs` (hash de entrada, scores, decisión, políticas violadas, latencia). Transacciones del Gateway: `connector_transactions`.

---

## 9b. Plataforma: gate de visitantes y Super Admin
- **Gate (middleware.js):** toda ruta pública (landing, /trust, /status, /manual, /docs) exige una cookie válida: `visitor_pin` (PIN), `gov_session` (operador) o `super_session`. Excluidos `/api/*`, `/gate`, `/superadmin`, `/legal/*`, `/?view=dashboard` (sólo formulario de login). `VISITOR_GATE_ENABLED=false` lo desactiva. Es un control de exposición de información comercial, **no** una frontera de seguridad del plano de control (que sigue protegido por sesión + RBAC + MFA).
- **PINs:** `visitor_pins` guarda SHA-256(pin | JWT_SECRET); vigencia y usos máximos; rate limit 10 verificaciones/min por IP; cada intento queda en `gate_events` (TTL 90 d).
- **Super Admin (`/superadmin`, `/api/superadmin/*`):** cuenta de plataforma (`platform_admins`, bcrypt, seed desde `SUPERADMIN_PHONE`/`SUPERADMIN_PASSWORD`; se recomienda cambiarla desde la UI: ≥ 12 caracteres). Funciones: alta de empresas (+ admin inicial), edición de plan/contrato/contactos, **activar/suspender servicio** (motivo obligatorio; cierra sesiones del tenant vía `session_version`), inactivación automática al vencer `contract_end` (`auto_suspend_on_expiry`), métricas por tenant, generador y revocación de PINs, bitácora de accesos. Efecto de suspensión: login → `403 SERVICE_SUSPENDED`, API keys → 403, Gateway → 403, rutas del plano de control → 403.

## 10. Runbooks de anomalías

| Señal | Diagnóstico | Acción |
|---|---|---|
| `KILL_SWITCH_ACTIVE` masivo en gateway | Consenso disparado o activación manual | Revisar `last_trigger_cause`, `GET /api/threats`, transacciones del conector; reactivar con `reason`. |
| `POST_AUDIT_BLOCK` recurrente en un conector | Modelo manipulado/comprometido o lista de prohibidos demasiado amplia | Revisar `violations`; si `RESIDUAL_LEAK_*` o `SYSTEM_PROMPT_*` tratar como compromiso del modelo: rotar system prompt, revisar fine-tuning/proveedor. |
| `GEOPOLITICAL_PII_EGRESS` | Política de transferencia bloqueó PII | Confirmar `zk_anonymize_external:true` o mover carga a conector local; documentar decisión legal. |
| `UPSTREAM_ERROR` sostenido | Endpoint caído, TLS, API key caducada, proxy de egreso | `POST /api/connectors/:id/test`; revisar `last_test.error`; rotar `api_key` vía `PUT`. |
| `PII_PLAINTEXT_REJECTED` | Cliente envía PII sin redactar | Desplegar SDK/Muro; revisar `X-ZK-Redacted` (si venía true → bypass de redacción: ajustar patrones). |
| `HUMAN_ALERT_REQUIRED` | Circuit breaker: toda la flota falla a la vez | Posible falso positivo global o incidente mayor; decisión humana; el modo vuelve a `AUTO` tras 30 s. |
| Heartbeat `stale` / incidente DMS | Cliente sin latido > 60 s | Verificar disponibilidad del cliente y conectividad saliente hacia `/api/v1/public/healthcheck`. |
| Webhook `failing` | Receptor 4xx/5xx o firma rechazada | Validar secreto compartido y reloj (ventana ±5 min); revisar nonce store del receptor. |
| `chain_valid:false` | Alteración/pérdida en `audit_events` | Incidente de seguridad: preservar la colección, comparar con respaldo, investigar accesos a la BD. |
| `SERVICE_SUSPENDED` / `contract_expired` | Super Admin suspendió el tenant o venció `contract_end` | Regularizar contrato; Super Admin → Activar o extender `contract_end`. |
| `MFA_ENROLLMENT_REQUIRED` en automatizaciones | Cuenta de servicio con rol admin/operator sin MFA | Usar API keys para integraciones (no sesiones); las sesiones humanas requieren MFA. |

---

## 11. Configuración y despliegue (variables relevantes)
`MONGO_URL`, `DB_NAME`, `JWT_SECRET` (+`JWT_SECRET_PREVIOUS`), `MFA_ENC_KEY`, `MFA_REQUIRED_ROLES`, `CONNECTOR_ENC_KEY`, `ALLOW_PRIVATE_EGRESS_DIRECT`, `REDIS_URL`, `ZK_MAP_TTL_SEC`, `ZK_FAIL_CLOSED`, `SECRETS_PROVIDER`/`AWS_SECRETS_ID`, `DEMO_MODE` (**false en producción**: desactiva cuentas demo, `/seed`, `/demo-credentials`, mock LLM y la auto-desactivación de MFA).

Checklist de salida a producción: `DEMO_MODE=false` · claves hex-64 dedicadas · `ALLOW_PRIVATE_EGRESS_DIRECT=false` salvo on-prem · Redis con TLS para el vault ZK · respaldos de MongoDB verificados · receptor de webhooks validado · revisión legal de Términos/Privacidad · pentest externo (pendiente en la hoja de ruta).

---

## 12. Límites conocidos (transparencia)
- Detección PII/amenazas es determinista (regex + heurísticas); no hay clasificador ML en producción (hoja de ruta).
- La evaluación de riesgo geopolítico es orientativa; no constituye asesoría legal.
- No existen certificaciones SOC 2 / ISO 27001 / ISO 42001 de la plataforma; el diseño está alineado a esos marcos.
- Redis y AWS Secrets Manager están soportados en código pero no aprovisionados en esta instalación.
