¿Qué hace agentic-evals?
Utilice esta habilidad cuando una prueba de humo única sea demasiado débil y la tarea requiera una evaluación repetible y respaldada por evidencia de una habilidad o flujo de trabajo de agente.
Alcance Actual
Este paquete inicial proporciona un ejecutor de fixtures determinista para casos basados en comandos. Ejecuta cada caso múltiples veces, registra stdout/stderr/estado de salida y duración, verifica expectativas explícitas y emite un resumen de preparación legible por máquina.
Esto solo prueba el comportamiento declarado del fixture. No prueba la corrección semántica, la integración real de servicios, la calidad de un juez LLM ni la preparación para el lanzamiento, a menos que los propios comandos del fixture ejerciten esas rutas en vivo.
Uso
./run.sh run fixtures/agentic_eval.json
./run.sh run fixtures/agentic_eval.json --output /tmp/agentic-evals-report.json
./run.sh audit-skills ../ --output /tmp/agentic-evals-baseline-gap-report.json
./run.sh scaffold-fixture ../some-skill --output ../some-skill/fixtures/agentic_eval.json
./run.sh apply-scaffolds ../ --write --output /tmp/agentic-evals-apply-scaffolds.json
# planificación de requisitos a trayectoria sobre descubrimiento en vivo (issue #1629)
./run.sh plan-journeys --fixture fixtures/agentic_eval.json \
--requirements requirements.json \
--interaction-inventory discovery/discovery-inventory.json \
--state-graph discovery/state-graph.json \
--output journey-plan.json [--scaffold-output fragment.json] [--report-only]
# reclamo / evidencia / regresión / cobertura (issues #1445-#1448)
./run.sh regressions audit ../ --output /tmp/agentic-evals-regressions.json
./run.sh regressions show . && ./run.sh regressions verify .
./run.sh coverage audit ../ --output /tmp/agentic-evals-coverage.json
./run.sh coverage show .
Preparación basada en reclamos (#1445)
Las pruebas deterministas prueban mecanismos; las E2E reales prueban capacidades. Un montón de casos deterministas que pasan nunca debe parecerse a la preparación para una capacidad en vivo que nunca fue ejercitada. Por lo tanto, la preparación se calcula por reclamo de capacidad declarado, luego se agrega, no a partir de un recuento de casos.
Declare capability_claims (mantenidos separados de la prosa de ámbito de prueba claims para que los fixtures v2 sigan siendo válidos). Cada caso que respalda un reclamo se etiqueta:
{
"capability_claims": [
{"id": "ask.roundtable.mixed_provider", "description": "...",
"criticality": "critical",
"evidence_required": {"deterministic": true, "live_e2e": true}}
],
"cases": [
{"name": "roundtable-live", "type": "positive", "evidence_class": "live_e2e",
"supports_claims": ["ask.roundtable.mixed_provider"],
"command": ["bash", "run.sh", "..."],
"expected": {"exit_code": 0, "artifacts": [{"path": "out/join.json", "json_pointer": "/settled", "equals": true}]}}
]
}
Clases de evidencia: deterministic, property_or_fuzz, fault_injected_deterministic, live_e2e, adversarial_live_e2e, human_evaluation. Veredictos por reclamo: PROVEN, PARTIALLY_PROVEN, BLOCKED_EXTERNAL, FAILED, NOT_ESTABLISHED. Una habilidad está READY solo cuando cada reclamo crítico requerido está PROVEN bajo sus propios requisitos de evidencia. Cuando se declaran reclamos, la compuerta de run es el peor de la preparación basada en casos y basada en reclamos, por lo que veinte casos deterministas verdes con una ranura live_e2e requerida insatisfecha no pueden alcanzar READY. Un caso en vivo que respalde más de un reclamo debe llevar artefactos independientes por reclamo, de lo contrario no cuenta para ninguno de ellos. report["capability_readiness"] contiene el desglose por reclamo.
Reclamos derivados de invariantes (nunca apuntar una respuesta) — operador 2026-09-11
La prueba de oai se perdió por una omisión: el requisito "ningún PII llega a la salida" se redujo silenciosamente a "ningún PII en forma de cadena llega a la salida". Cada evaluación, verificador y ejecución de calificación demostró el reclamo reducido como verde mientras que los números de teléfono de tipo entero pasaban sin ser tocados. El cliente leyó el invariante en el ámbito del dominio; nosotros lo probamos en el ámbito del mecanismo. REGLAS:
- Los reclamos se derivan del invariante del dominio, no de lo que el código ya hace. Antes de declarar
capability_claims, escriba el invariante en las palabras del cliente ("ninguna X llega a la salida en NINGUNA representación"), luego declare eso, textualmente, como el reclamo crítico. Un reclamo que describe el comportamiento actual es un apunte. - La matriz de representación es obligatoria para reclamos que llevan valor. Cualquier reclamo sobre valores de datos (PII, dinero, identificadores, secretos) debe enumerar las representaciones que admite el formato de entrada — cadena JSON/entero/flotante/notación científica, comillas CSV, tipos SQL — y llevar al menos un caso adversarial por representación, cada uno capaz de fallar. Un reclamo de valor sin una matriz de representación no puede ser PROVEN.
- Se requiere un seam de cobertura denominado
value-representation(criticality: critical) para cualquier pipeline que transforme, filtre o redacte valores de datos. La auditoría debe mostrar un guardia capaz en ese seam. - Los verificadores independientes no deben compartir el generador de datos del productor. Los fixtures del verificador deben incluir representaciones que los propios fixtures de la transformación no incluyen, o la independencia es nominal.
- Cuando una brecha de representación se envía a producción, regístrela en
fixtures/regressions.json(incidente → guardia retenido) y en el seamvalue-representation— el mismo tipo de error debe ser detectable para siempre.
El contrato anti-slop rechaza la plomería auto-servicial; estas reglas rechazan las suposiciones auto-serviciales — el conjunto que es honesto, adversarial, de múltiples ensayos y aún ciego porque cada fixture comparte una condición previa invisible sobre la forma de los datos.
Contrato de evidencia de extremo a extremo real (#1446)
evidence_class no se infiere de un comando que contenga run.sh o curl. Un caso que declara una clase en vivo (live_e2e/adversarial_live_e2e) es calificado estructuralmente y degradado (nunca aceptado silenciosamente) si:
- se alimenta a sí mismo con entradas de
fixtures//stub/mockedcomo la autoridad del límite; - no alcanza un punto de entrada de producción sustancial;
- no tiene un oráculo de lectura independiente (
expected.artifacts,readback: true, ostdout_excludes) — un código de salida más la prosa de éxito del propio comando no es prueba; o - reclama evidencia en vivo para los controladores
tau-dag/competedel navegador$asksin--executey lectura de artefactos de ejecución del navegador/proveedor comonode-receipt.json,response.md,response.meta.json,browser-tab-lifecycle.json,execution-status.json,roundtable-summary.md, ocompete-scorecard.json. Los casos$asksolo de compilación/pre-vuelo son evidencia de mecanismo determinista, nuncalive_e2e.
Un caso degradado se convierte en fault_injected_deterministic (falla en una ruta real) o deterministic, y el informe registra evidence_disqualifiers. Una ranura en vivo requerida cumplida solo por un caso BLOCKED_EXTERNAL deja el reclamo como no PROVEN.
Las exenciones son explícitas y con vencimiento. Un reclamo puede llevar exemptions nombrando evidence_class, reason_code, justification, owner y expires. Una exención válida se muestra en el informe (exempt_evidence) pero nunca hace que un reclamo sea PROVEN; una exención vencida o incompleta se ignora. No hay una eval_not_required general que satisfaga una capacidad operativa ejecutable.
Incidente → regresión retenida (#1447)
Una falla en vivo se convierte en evidencia permanente en fixtures/regressions.json (agentic_evals.regressions.v1). Cada registro vincula el incidente con los reclamos y los seams que amenazó, nombra el caso de guardia retenido (retained_case / retained_fixture) y lleva un fail_before_fix.proof_command.
regressions show <skill>/regressions audit <root>informan: regresiones no protegidas (caso retenido faltante/renombrado), regresiones nunca probadas (posiblemente vacuas), prueba en vivo obsoleta, regresiones retiradas e incidentes abiertos sin mapeo de regresión.regressions verify <skill>vuelve a ejecutar cada comando de prueba y confirma que el guardia realmente falla contra el comportamiento roto (sale con código distinto de cero) — una prueba de no vacuidad, no una bandera auto-reportada. Sale con código distinto de cero si algún guardia de regresión activa no puede demostrar falla-antes-de-la-corrección.
Arreglar un error editando la expectativa de la evaluación para que coincida con la salida rota es exactamente lo que detecta la prueba de no vacuidad. Retirar una regresión requiere una razón de retirement.
Suficiencia de cobertura basada en riesgos (#1448)
Contar casos es manipulable. coverage audit/coverage show preguntan, por seam declarado: ¿hay al menos un caso capaz de detectar una regresión en ese seam, en cada clase de evidencia que el riesgo del seam requiere? Declare seams con seam_id, seam_type, criticality y required_evidence; etiquete casos con seams. Un caso cubre un seam solo cuando enumera ese seam y lleva un oráculo que puede fallar — un exit 0 positivo simple es weak_only y no cuenta. La auditoría informa seams cubiertos/descubiertos, cobertura solo débil, cobertura en vivo vs determinista, regresiones de incidentes mapeadas y próximas evaluaciones priorizadas. La cobertura (se declara un guardia capaz) y la frescura (una prueba en vivo está actualizada) son dimensiones separadas; el ejecutor no ejecuta los casos del seam aquí.
Contrato de Fixture
{
"version": 2,
"skill": "example-skill",
"trials": 3,
"proof_scope": "fixture wiring smoke",
"claims": {
"proves": "the declared command exits with the expected status",
"does_not_prove": "semantic correctness, live service behavior, or full skill readiness"
},
"cases": [
{
"name": "happy-path",
"type": "positive",
"command": ["echo", "success"],
"expected": {
"exit_code": 0,
"stdout_contains": ["success"]
}
}
]
}
Cada caso debe declarar:
nametype:positive,negativeoadversarialcommand: una lista argv no vacíaexpected.exit_code
Expectativas opcionales:
expected.stdout_containsexpected.stderr_containsmust_exercise: lista de subcadenas de comando de contrato descendente que deben aparecer en el comando de nivel superior del caso. Utilícelo cuando un envoltorio podría falsificar el éxito; por ejemplo, una evaluación que reclama enrutabilidad$ticket/$project-watchdogdebe incluir"skills/ticket/run.sh feature", no solo un script auxiliar que imprimaOK.
Contrato Anti-Slop (fallo cerrado)
Un fixture de evaluación de habilidad es RECHAZADO en el momento de la carga (salida distinta de cero, sin ejecución) si es plomería determinista auto-servicial en lugar de una prueba del mundo real. Para pasar, un fixture de habilidad DEBE:
- establecer
trials>= 2 (un solo ensayo no es evidencia); - incluir al menos un caso
negativeoadversarial(un fixture completamente positivo es auto-servicial); - incluir al menos un caso del mundo real:
"real_world": truecuyo comando ejercite una ruta en vivo (elrun.shde la habilidad / un script / HTTP en vivo / un ejecutor de pruebas) y NO se alimente a sí mismo con entradas stub defixtures/; - no contener casos triviales de
echo/constantes que no demuestren nada.
El mensaje de rechazo nombra cada violación. Esto evita una evaluación que pase trivialmente mientras no prueba nada sobre si la habilidad realmente funciona.
Nivel de cumplimiento ("eval_tier": "compliance")
Un fixture que protege una etapa de pipeline de cumplimiento declara "eval_tier": "compliance" y el ejecutor entonces EXIGE el contrato fuerte además de la línea base (directiva del operador 2026-08-12, "esto es un pipeline de cumplimiento y debe estar robustamente endurecido"). Dicho fixture es RECHAZADO a menos que:
- una mayoría estricta de los casos sean
adversarial/negative(más de la mitad, no exactamente la mitad — los controles positivos son la minoría); - al menos un caso sea no determinista: su comando muestrea entradas frescas cada ejecución mediante
--samples,--seedo un$RANDOMde shell (un script de sonda con una clave fija no cuenta); - cada caso no determinista nombre
--samples>= 50, de modo que la cobertura de cada etapa sea de cientos a miles de aserciones por ejecución, apuntando a ~1000 por etapa en todos sus modos.
La declaración no puede ser relajada silenciosamente: los propios fixtures del pipeline de cumplimiento establecen el nivel, por lo que eliminarlo para evitar la compuerta es en sí mismo una regresión. tests/test_compliance_tier_gate.py fija cada regla contra su debilitamiento.
Dos exenciones declaradas honestamente evitan la compuerta — nunca válidas para una evaluación de habilidad real:
"eval_kind": "runner_selftest"— un fixture que prueba al propio ejecutor o es un ejemplo de documentación."eval_kind": "scaffold"— el fixture mecánico de primera postura emitido porscaffold-fixture/apply-scaffolds, que la auditoría aún marca como necesitando casos reales.
Mapeo de Preparación
La preparación se puntúa sobre los casos requeridos solamente ("required": false excluye un caso). Un caso BLOCKED requerido no puede alcanzar READY: una condición previa no cumplida es ausencia de evidencia, no evidencia de éxito.
READY: cada caso requerido pasó todos los ensayos.USABLE_WITH_GAPS: al menos un ensayo pasó y al menos uno no.NOT_READY: los ensayos se ejecutaron pero ningún caso requerido pasó completamente.NOT_ESTABLISHED: no se ejecutaron casos.
Salida de fallo cerrado
run sale con código distinto de cero a menos que la preparación sea READY. Un ejecutor que sale con 0 en USABLE_WITH_GAPS permite que un trabajo de CI externo se vuelva verde con casos fallidos, que es el fallo completo que esta compuerta existe para prevenir. Pase --report-only cuando desee el informe sin la compuerta.
Resultados de casos
Cada caso informa un outcome, porque estos significan cosas diferentes para una compuerta:
| Resultado | Significado |
|---|---|
PASS | cada ensayo cumplió cada expectativa |
FAIL | un defecto, o un tiempo de espera, o un ensayo que dejó un proceso hijo atrás |
BLOCKED | una condición previa no se cumplió; declare marcadores mediante blocked_when_stdout_contains |
NOT_TESTED | no se ejecutaron ensayos |
Aserciones de artefactos
La coincidencia de subcadenas de stdout no puede expresar "estos dos recibos nombran la misma sesión" o "la ejecución no dejó nada atrás". Declare expected.artifacts:
"expected": {
"exit_code": 0,
"artifacts": [
{"path": "out/session.json", "json_pointer": "/sessionId",
"equals_artifact": {"path": "out/detach.json", "json_pointer": "/sessionId"}},
{"path": "out/attach.json", "json_pointer": "/sessionId",
"exists": true},
{"path": "out/session.json", "json_pointer": "/sessionId",
"type": "string", "length_gte": 1},
{"path": "out/session.json", "json_pointer": "/participants/0/anonymous",
"equals": false},
{"path": "/tmp/skill-runner-*/", "glob": "**/*.tmp", "count_lte": 0}
]
}
Aserciones de artefactos soportadas:
| Aserción | Semántica |
|---|---|
exists: true/false | el archivo existe / no existe |
equals: <value> | el valor en la ruta JSON-pointer es exactamente <value> |
equals_artifact | dos archivos en punteros diferentes tienen el mismo valor |
matches: <re> | el valor coincide con la expresión regular |
type: <type> | string, number, boolean, null, array, object |
length_gte: N | la cadena o array tiene longitud >= N |
deep_match: <json> | coincidencia JSON profunda contra un objeto/array literal |
glob / count_gte / count_lte | coincidencia de patrón de archivo y recuento |
json_pointer: "" | la raíz completa del documento |
Una aserción equals_artifact entre dos archivos de salida prueba que un valor de sesión es compartido a través de los límites del proceso o del tiempo, sin requerir un fixture de entrada stub.
Diferencia de fixture v1 → v2
Todos los campos de fixture en la parte superior ahora son opcionales si se declara version: 2. skill, trials y proof_scope tienen valores predeterminados sensibles. El único campo estrictamente requerido en un fixture v2 es cases (no vacío).
Registro
Pase --log-level debug para ver por qué falló un fixture; --log-level trace para ver cada iteración de ensayo.
Salida de estado de prueba en vivo (--progress)
Con --progress el ejecutor imprime una línea [FAIL], [PASS], [BLOCK], [SKIP] por caso a stderr tan pronto como se conoce el resultado. Los resultados de casos lentos aparecen a medida que finalizan, no en un lote al final. Sin --progress el ejecutor permanece en silencio excepto en caso de error.
Formato de informe
El reporte JSON (--output) es la única salida garantizada estable entre versiones. La salida a stdout es para legibilidad humana y puede cambiar.
Dependencias
jq(manejo JSON en shell)python3(análisis de artefactos complejos JSON-pointer)- bash 4+
- coreutils (timeout, mktemp, etc.)