Envelope estable
Errores HTTP
Sobre HTTP, el envelope de EVA es siempre el mismo. No hay 202. Validación de query/body es 422, no 400. Miss o permiso cruzado es 404 (no se filtra existencia a otros tenants). 304 en extract es revalidación correcta (If-None-Match), no un error.
{
"code": "INVALID_TOKEN",
"message": "Invalid token.",
"details": []
}
Éxito
| HTTP | Operación |
|---|---|
| 200 | Índice, extract GET, extract batch, pending, claim, heartbeat, result, CSV ingest |
| 304 | Extract: If-None-Match coincide. Cuerpo vacío. No es un error. |
| 201 | JSON ingest (hallazgo o aspecto); ensure si creó proyecto o enlazó escenario |
Autenticación y tenant
| HTTP | code | Cuándo |
|---|---|---|
| 401 | MISSING_BEARER_TOKEN | Falta Authorization: Bearer |
| 401 | INVALID_TOKEN | PAT inválido, caducado o revocado |
| 401 | TOKEN_TYPE_NOT_ALLOWED | JWT de sesión en rutas PAT, o PAT en CRUD de tokens |
| 403 | TENANT_MISMATCH | X-Tenant-Id ≠ tenant del PAT |
| 403 | INTEGRATION_SCOPE_DENIED | Falta extract, ingest, retest_read o retest_write |
| 403 | INTEGRATION_IP_DENIED | Extract/ingest: la IP no cae en allowed_cidrs del PAT. Retest no aplica esta lista. |
Recurso y conflicto
| HTTP | code | Cuándo |
|---|---|---|
| 404 | NOT_FOUND | Proyecto/escenario inexistente o sin permiso (extract/ingest) |
| 404 | JOB_NOT_FOUND | UUID de job desconocido en ese tenant |
| 409 | SCENARIO_AMBIGUOUS | Más de un escenario con ese scenario_key en el proyecto o en catálogo (ensure) |
| 409 | PROJECT_CODE_CONFLICT | Ensure: el código existe con otro nombre (no se renombra) |
| 409 | PROJECT_CLIENT_CONFLICT | Ensure: el código existe con otro client_code |
| 409 | JOB_ALREADY_CLAIMED | Lease vigente de otro runner_id |
| 409 | JOB_NOT_CLAIMED | Heartbeat/result sobre job pending |
| 409 | JOB_LEASE_EXPIRED | Lease vencido o job expired |
| 409 | JOB_ALREADY_FINISHED | Job succeeded / failed |
| 422 | validación | Query o body inválido (Pydantic). No use 400. CIDR inválido al crear el PAT. Índice: fechas invertidas/inválidas. Batch: más de 10 ítems, report_type ausente, pares duplicados. |
| 429 | INTEGRATION_RATE_LIMITED | Extract/ingest: cupo 60/min por token_id+superficie. Índice y GET extract = 1 hit; batch = N. Cabecera Retry-After. Retest no usa este cupo. |
Matriz de laboratorio
| Caso | Esperado |
|---|---|
Sin Authorization | 401 MISSING_BEARER_TOKEN |
| JWT de sesión en extract/ingest/retest | 401 TOKEN_TYPE_NOT_ALLOWED |
PAT sin scope ingest en ingest | 403 INTEGRATION_SCOPE_DENIED |
Extract/ingest desde IP fuera de allowed_cidrs | 403 INTEGRATION_IP_DENIED |
| N+1 extract del mismo PAT en un minuto | 429 INTEGRATION_RATE_LIMITED + Retry-After |
Retest pending con CIDR o cupo extract | No aplica. Solo PAT + scope retest_read. |
X-Tenant-Id de otro tenant | 403 TENANT_MISMATCH |
| UUID de otro tenant | 404 |
report_type inválido | 422 |
Índice con updated_since > updated_until | 422 |
Batch con 11 ítems o sin report_type | 422 |
| Batch con un UUID inexistente | 200 y ese ítem not_found (no 404 de lote) |
| PAT revocado, mismo curl | 401 INVALID_TOKEN |
Extract con If-None-Match del ETag actual | 304 (éxito; cuerpo vacío) |
El cupo de 60/min y allowed_cidrs aplican a extract e ingest. Índice y GET extract cuentan 1; un POST extract-batch cuenta N. Un CSV es 1 POST. Retest no usa este cupo. Envelope {code,message,details}.
Clases del runner (no son HTTP de EVA)
El contenedor clasifica fallos de operativa en logs y en /health last_class. No son el envelope {code,message,details} ni viajan en POST …/result salvo el set cerrado de error_code.
| Class local | Cuándo | Qué hace el agente |
|---|---|---|
auth_failed | 401 INVALID_TOKEN / MISSING_BEARER_TOKEN | /ready 503. Backoff ~60 s. No martilla pending cada 15 s. |
eva_unreachable | Timeout, DNS, connection refused o 5xx hacia Flask | /health 200, /ready 503. Backoff 5→60 s. No es error_code de result. |
claim_conflict | 409 JOB_ALREADY_CLAIMED | Siguiente tick. No es error de health. |
lease | 409 lease / finished en heartbeat o result | Log warning. 409 JOB_ALREADY_FINISHED en un retry de result cuenta como éxito. |
Detalle y JSON de /health: Runner.