Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,52 @@ a320-bench score runs/ --json > scores.json # ScoreCards + aggregates for plots
a320-bench score runs/elec-apu-gen-fault/one.jsonl --json --detail
```

## Experiment runbook (needs provider API keys)

The baselines and ablations of #20 are a loop over `run` (records) and `score`
(measures) — no bespoke code. The protocol (models, N per cell, ablation axes,
statistical power) is in [`docs/fase5-metrica.md`](../docs/fase5-metrica.md);
here are the exact commands the matrix executes.

Keys live in the environment, never in a file or a trajectory (the adapter
records the model and sampling, never the credential):

```powershell
$env:ANTHROPIC_API_KEY = "..." # Claude via litellm
$env:GEMINI_API_KEY = "AQ..." # Gemini via Vertex express (AQ.* keys)
```

One cell — a model against every scenario, N runs each, into a run tree:

```powershell
$SCEN = Get-ChildItem scenarios -Recurse -Filter *.yaml |
Where-Object { $_.Directory.Name -ne "schema" }
foreach ($s in $SCEN) {
a320-bench run --scenario $s.FullName `
--model anthropic/claude-opus-4-8 --runs 10 --out runs/baseline
}
# Gemini needs its Vertex express api_base passed through --sampling:
foreach ($s in $SCEN) {
a320-bench run --scenario $s.FullName --model gemini/gemini-2.5-flash --runs 10 `
--out runs/baseline `
--sampling '{"api_base": "https://aiplatform.googleapis.com/v1beta1/publishers/google"}'
}
```

Score the whole tree — the table separates by `(scenario, model)`, the JSON
feeds the plots:

```powershell
a320-bench score runs/baseline # human table + aggregates
a320-bench score runs/baseline --json > baseline.json
```

An ablation is the same loop with one lever changed (a scenario variant with a
different `instructions_profile`, a `--sampling` temperature, a tool-surface
profile) into a separate `--out runs/ablation-<name>`, scored the same way.
`score` needs no binding and no network, so the whole measurement half runs on
a reviewer's machine with `pip install -e bench/` alone.

## Tests

```powershell
Expand Down
25 changes: 25 additions & 0 deletions docs/fase5-metrica.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,28 @@ Los procedimientos anormales del QRH/FCOM A320 son públicos y plausiblemente es
1. **Qué mide entonces el benchmark**: *ejecución en bucle cerrado bajo observación*, no recall — leer la ECAM real, secuenciar con un reloj que solo avanza vía `advance`, interpretar el reset fallido (la caution vuelve), y sortear trampas del entorno (la supresión de la caution bajo EXT PWR). **Evidencia empírica ya en mano**: en los smokes, dos modelos que claramente *conocían* el procedimiento (volaron el bloque de reset completo y en orden) **omitieron igualmente la acción de aislamiento** — conocer ≠ cumplir, que es precisamente el hueco que la métrica separa (coverage 0.75 con order 1.0). El recall no explica esa omisión; la ejecución bajo observación, sí.
2. **Canarios naturales**: las divergencias documentadas FBW-vs-real (los `source.notes` de cada escenario, la distinción `EcamSource` de D-014) hacen de detector — un agente que ejecute el QRH verbatim donde el modelo diverge delata recall sobre observación; se reporta cualitativamente.
3. **Mitigación futura** (no de esta etapa): el eje de ablación "QRH access vs not" ya previsto en #20, y el reporte por componentes en vez de por pass-rate (el vector ya lo impone).

## Protocolo experimental (bloqueado por claves de API)

Esta sección fija *cómo* se correrán los baselines y las ablations cuando haya claves de proveedor. **No hay código nuevo que escribir**: `a320-bench run` graba trayectorias y `a320-bench score` las puntúa; la matriz es un bucle sobre esos dos comandos (el runbook exacto está en `bench/README.md`). Nada de esto corre en CI ni toca la red hasta ese momento.

### Modelos (≥2 baselines)

El paper exige al menos dos modelos (CLAUDE.md, #20). Los dos ya validados end-to-end el 2026-07-24 son la base: **Claude** (`anthropic/claude-*` vía litellm, o la suscripción vía `a320-bench serve` + `claude -p` para desarrollo — no para el baseline formal, porque el system prompt de Claude Code es un confound) y **Gemini** (`gemini/gemini-2.5-flash` vía litellm contra el endpoint express de Vertex). Cada modelo se identifica en el `meta.adapter` de cada trayectoria, así que la agregación por `(scenario, model)` los separa sola.

### Runs por escenario (potencia estadística)

Los LLM no son deterministas, así que un solo run por celda no distingue modelos. Punto de partida: **N = 10 runs por (escenario × modelo × ablación)**, con la desviación reportada por `aggregate` (`score_std`, `pass_rate`). N=10 es el mínimo para una media estable con la varianza que se observa en tareas de agente; se sube a 20–30 en las celdas donde dos modelos queden dentro de una desviación. El escenario también aporta varianza (el azar del vendor, D-022), que las ventanas de tolerancia de los predicados absorben — la varianza dominante es el muestreo del modelo. Con 4 escenarios (`elec-apu-gen-fault`, `elec-eng1-gen-fault`, `hyd-eng2-pump-overheat`, `hyd-blue-epump-overheat`) × 2 modelos × N=10 = 80 runs por ablación; asequible.

### Ejes de ablación (palancas ya existentes, cero código)

Cada eje es un parámetro que ya expone el harness; se varía uno a la vez desde el baseline:

- **Instrucciones del sistema** (`instructions_profile` del escenario / `INSTRUCTIONS_PROFILES` del servidor, D-023/D-017): el prompt del agente es "prompt engineering, no documentación" y el eje de ablación que D-017 anunciaba. Variar la riqueza de las reglas de pulgar del avión mide cuánto del cumplimiento viene del prompt vs del modelo.
- **Sampling** (`--sampling` de `a320-bench run`, reenviado verbatim a `litellm.completion` y grabado en `meta`): temperatura 0 vs por defecto mide la contribución del muestreo a la varianza intra-modelo.
- **Superficie de tools** (perfil del servidor): el perfil `benchmark` ya retira `inject_failure`/`clear_failure`; una variante que exponga u oculte tools de descubrimiento (`snapshot`, `list_*`) mide cuánto depende el diagnóstico de la exploración libre.
- **QRH access** (mitigación de contaminación): dar vs no dar el texto del procedimiento en el prompt, para separar recall de ejecución bajo observación.

### Qué se reporta

Por el compromiso de forma (D-026), el paper reporta el **vector agregado**, no solo el escalar: media±desv del escalar, y de `coverage`/`order`/`end_state` por separado, más `pass_rate`, `dangerous_rate` y las tasas de infraestructura (`provider_error_rate`, `invalid_rate`). El escalar rankea; el vector explica *por qué* un modelo rankea donde rankea — y es donde vive el hallazgo de los smokes (dos modelos con `end_state` alto pero `coverage` 0.75). Un punto de referencia humano/experto, si es factible, da techo al escalar (un score sin techo es difícil de interpretar); queda como deseable, no como bloqueante.
Loading