# ECHO-5.5-v3 — entrega local y calibración acotada

Fecha: 2026-10-17. Rama: `research/echo-5.5-arc3`. Sin push.

**Actualización tras R2:** ocho llamadas GPU completadas, **0 niveles,
16 acciones, 22.201 tokens**, score 0. El contexto ya cabe; no hay mejora de
resolución. [Diagnóstico R2](V3-R2-DIAGNOSIS-20261017.md).

## Resultado local verificado antes del primer intento

La segmentación interna conserva todos los componentes de los 4.096 píxeles.
La comparación de agencia usa índices por color y tamaño y rechaza asociaciones
ambiguas. La proyección de `objects()` limita la salida a 128 componentes,
priorizando las anclas que cambiaron. No se identifica automáticamente al jugador.
El color cero ya no se excluye de los análisis de agencia/contacto.

En BP35 oficial, dos acciones guionizadas (3 y 4, sin LLM) recuperaron los
candidatos 9 y 11. ACTION3 desplaza sus anclas de (37,21) a (37,15) y de
(38,22) a (38,14); ACTION4 las devuelve. Son desplazamientos de 6 y 8 píxeles,
no evidencia de física cardinal unitaria. Los 11 recibos y 11 eventos del diario
se verificaron; tres frames públicos íntegros; `destroyed=0`.

`echo.crop(r0,c0,r1,c1)` usa extremos finales exclusivos y valida límites.
`echo.ascii(frame=None)` devuelve caracteres 0–f. Estas operaciones son de lectura
y se registran junto con sus argumentos. El renderizador verifica primero las
firmas locales y hashes de frames, y genera PNG 4× nearest-neighbor y un GIF con
contador de acciones y niveles. Los tiempos del GIF son de presentación.

El contexto tiene un slot protegido para el resultado inmediato: stdout acotado,
diagnóstico y consecuencias. Solo los turnos ya reemplazados se desalojan por FIFO.
Los prints conservan hipótesis como afirmaciones no verificadas. Se compactó la
política y se retiraron hashes repetidos de su proyección; siguen en los recibos.
Si reglas, feedback inmediato y frame completo exceden 3.000 tokens medidos por
el proveedor, se interrumpe explícitamente en lugar de borrar esa evidencia.
El REPL conserva feedback entre programas; las variables Python del hijo **no**
persisten entre ejecuciones.

Validación: **67 tests ECHO-5.5 y 25 tests del núcleo pasan** en procesos separados.
La combinación de ambas suites en un único proceso dispara el guard existente de
identidad duplicada de `seed`; no se modificó ese guard ni el núcleo sellado.
También pasan el sondeo oficial de dos acciones, renderizado autenticado,
rechazo de metadata GPU incompatible y cierre de transportes ante fallo de inicio.
No se ejecutó inferencia CPU en esta entrega.

## Ensayo remoto predeclarado

Una única calibración de desarrollo BP35, semilla 73, primer nivel, con
Qwen2.5-Coder-32B-Instruct Q4_K_M (GGUF SHA256
`4d64b316b5e6319d9613e0d97935d9ebd631fc7e334da400d00085eca749d085`).
Se exige evidencia de 65/65 capas en dos Tesla T4 antes de llamar al modelo.

Máximos: 8 llamadas, 25.000 tokens totales, 3.000 de entrada/512 de salida por
llamada y 600 acciones físicas. Primer nivel completado termina el episodio.
El objetivo exploratorio es <50 acciones; la referencia anterior es 247.
La política y el límite de exploración por programa cambiaron respecto a v2:
esta calibración no constituye una ablación causal de cada modificación.

El supervisor local impone 1.530 segundos al proceso de calibración; el notebook
tiene un límite independiente de 1.800 segundos y el servicio local de 2.100.
Al finalizar solicita `/stop`, cierra sus procesos y exporta los artefactos.
Si falla la red, el límite del notebook sigue acotando el consumo; el cierre
remoto efectivo debe comprobarse en `shutdown.json` y en Kaggle.
No se inicia automáticamente la tríada ni el panel de ocho juegos.

## Resultado de la calibración GPU v3 (código `6cae0c9`)

**Cero niveles resueltos.** El modelo ejecutó correctamente el sondeo de dos
acciones y el segundo turno se rechazó por exceso de contexto. Kaggle COMPLETE
significa que terminó el proceso, no que ganó BP35. La condición para ampliar a
TU93/S5I5 no se cumple.

| Medida | Resultado |
|---|---:|
| Acciones físicas / resets | 2 / 0 |
| Niveles completados | 0 de 9 |
| Llamadas de generación | 1 |
| Tokens de entrada / salida | 2.326 / 29 |
| Tokens totales conocidos | 2.355 |
| Scorecard oficial local del SDK | 0 |
| Recibos de eventos / catálogo | 15 / 1 |
| Eventos del diario | 15 |
| Frames públicos únicos | 3 |
| CAM destruidas | 0 |
| Reservas huérfanas de inferencia / acciones | 0 / 0 |
| Duración del worker / preparación del modelo | 436,612 s / 372,005 s |

La respuesta generada completa fue:

```python
echo.act(3)
echo.act(4)
print(echo.agency())
print(echo.targets()[:5])
```

El stdout incluye ambos candidatos móviles, colores 9 y 11. El modelo todavía
no recibió una oportunidad de formular una estrategia en un segundo turno.
No se puede concluir que haya mejorado la resolución ni que sea incapaz de
razonar sobre este juego. Las dos acciones no son una mejora sobre las 247 de
v2: aquel intento sí completó un nivel.

El GGUF, revisión, 65/65 capas y ambas T4 coinciden con lo predeclarado. El
worker confirma `relay_result.stopped=true`, sin errores; el supervisor registró
`COMPLETE` y detuvo los transportes. Se verificó el puerto 8798 cerrado antes
de preparar una repetición. El dato `gpu_after` del reporte se captura antes del
bloque de limpieza y no sirve por sí solo para demostrar apagado.

La cuota pasó de 9,6768 a 9,5532 horas entre las consultas disponibles, una
variación aproximada de 7 min 25 s; no se presenta como factura ni medida
independiente del tiempo exclusivo del modelo.

## Causa reproducida y corrección local para R2

Faltaba una prueba de integración del **segundo prompt real** con el tokenizador
32B. Las pruebas previas cubrían la conservación del feedback, pero sus mocks
no reproducían ese consumo. Proteger stdout era necesario, pero dejó un bloque
inmovible demasiado grande junto al frame y al resumen de herramientas.

Se reconstruyeron los dos prompts desde las observaciones públicas y el programa
registrado, sin inferencia ni acceso a estado privado del motor. Un tokenizador
local de Qwen2.5-Coder-32B-Instruct produjo **los mismos hashes completos** de
plantilla e IDs de tokens que el servidor GPU, para ambos turnos. El prompt que
no llegó a generación tenía **3.102 tokens**, 102 sobre el límite.

La corrección tiene dos partes de representación:

- El resumen de agencia/targets usa columnas y filas compactas y conserva una
  advertencia explícita de incertidumbre. Las coordenadas, colores, tamaños y
  momento de observación se preservan; los recibos completos no se modifican.
- El diccionario del frame usa filas de caracteres 0–f, un carácter por píxel,
  referenciadas por `frame_row_ids`. Es una codificación sin pérdida, incluido
  el HUD. `echo.observe()` sigue entregando la matriz original. El formato de
  la condición histórica `delegated_v2` se conserva.

| Prompt completo | v3 ejecutada | Corrección R2, replay sin inferencia |
|---|---:|---:|
| Turno 1 | 2.326 | 1.923 |
| Turno 2 | 3.102 (rechazado) | 2.526 |

El feedback inmediato es idéntico byte a byte en la reconstrucción; el frame se
decodifica a los mismos 4.096 píxeles. Quedan 474 tokens de margen en ese segundo
turno. Esto no garantiza que cualquier frame futuro quepa: permanece el rechazo
explícito si los bloques protegidos exceden 3.000 tokens.

**69 tests ECHO-5.5 pasan** tras la corrección (dos regresiones nuevas), además
del replay de dos turnos con conteo real. Los 25 tests del núcleo ya verificados
no se repitieron, porque ese código no cambió; se coteja la custodia del núcleo
sellado. No se ejecutó inferencia CPU: el tokenizador no carga pesos generativos.

## Evidencia y figuras

- [Auditoría independiente](v3-results-20261017/independent-audit.json).
- [Resultado completo y stdout](v3-results-20261017/result.json).
- [Scorecard oficial local](v3-results-20261017/official-scorecard.json).
- [Recibos, diario y frames públicos](v3-results-20261017/public-evidence.zip).
- [GIF real de las dos acciones de sondeo](v3-results-20261017/bp35-v3.gif).
- [Comparativa con v2](v3-results-20261017/calibration-overview.png).
- [Presupuesto de contexto](v3-results-20261017/context-budget.png).
- [PNG inicial 4×](v3-results-20261017/initial-4x.png) y
  [final 4×](v3-results-20261017/final-4x.png).

El GIF muestra izquierda y regreso al punto inicial; no representa un nivel
ganado. Los hashes publicados permiten revisar integridad; las claves de HMAC
permanecen locales. La validación de firmas se realizó antes de exportar; el ZIP
público no contiene autoridades, credenciales, configuración del relay ni notebook.
El scorecard del SDK no es una participación enviada al leaderboard.

Para reproducir el análisis de contexto: usar el entorno Linux de las pruebas,
`tokenizers==0.23.3`, `jinja2==3.1.6`, y los dos JSON de tokenización fijados en
[tokenizer-provenance.json](v3-results-20261017/tokenizer-provenance.json).
Ejecutar `reproduce_context.py --tokenizer-directory <directorio>` en ese
subdirectorio. El script coteja los hashes nativos, reproduce dos turnos con
proveedor simulado y verifica frame completo y feedback conservado. Las figuras
se regeneran con `plot_results.py` y Matplotlib, sin GPU.

## Repetición acotada R2

Conserva los mismos topes de llamadas, tokens, acciones, semilla y modelo. Usa
`ECHO-5.5/artifacts/v3-20261017/remote-r2/` y el notebook privado
`rogeernavarro/echo55-v3-bp35-r2-20261017`. Se inicia una sola calibración de BP35,
con el mismo supervisor y corte remoto de 30 minutos. Terminó y se auditó el
17 de octubre. La tríada y el panel siguen pendientes porque no se ha superado
la puerta de mejora BP35.

## Resultado R2 auditado — fuente `9b490e5`

| Métrica | v2 | v3 R1 | v3 R2 |
|---|---:|---:|---:|
| Niveles completados | 1 | 0 | 0 |
| Acciones físicas | 247 | 2 | 16 |
| Llamadas LLM | 4 | 1 | 8 |
| Tokens totales | 10.318 | 2.355 | 22.201 |
| Motivo de parada | Primer nivel | Preflight del turno 2 | Límite de 8 llamadas |

R2 consume 21.781 tokens de entrada y 420 de salida, todos contabilizados.
Ejecuta A3 una vez, A4 dos veces y 13 clics; cero resets. El scorecard del SDK
oficial offline devuelve 0, con juego sin terminar. Es una calibración por
condición, no una estimación estadística de resolución.

La duración registrada del worker fue **582,748 segundos**, de los que
410,118 corresponden a preparación. Es tiempo del worker, no facturación exacta
ni tiempo puro de inferencia. La API confirmó COMPLETE y saldo **9,3889858 h**
a las 01:38:57 de Madrid del 17/10. Ese saldo es una lectura puntual.

La revisión independiente autentica 90 recibos de eventos y dos de catálogo,
90 entradas del diario y 17 frames; vincula programas, uso, acciones y resultado
con esos recibos. No hay reservas huérfanas ni uso desconocido; `destroyed=0`;
ocho sandboxes vacíos. Modelo y offload 65/65 en dos T4 coinciden con el plan.
Worker detenido, procesos locales apagados y puerto 8798 cerrado.

Los ocho prompts se reconstruyeron desde las observaciones públicas y stdout
registrados. Sus hashes de plantilla y tokens coinciden con el relay; el máximo
es **2.973 <3.000**. El feedback inmediato se conserva. El texto del movimiento
del primer turno desaparece del contexto desde el cuarto tras desalojar historia.
`agency()` vuelve vacío desde el segundo turno porque resume el último efecto,
un clic sin desplazamiento identificable, y sobrescribe la proyección anterior.

No hubo llamadas a A*, exploración ni zoom. El modelo no imprimió hipótesis
contrastables; los programas de los turnos 6, 7 y 8 son idénticos. Doce de los
13 clics cambian únicamente el borde de la imagen; uno cambia además 25 píxeles
interiores. Esto no permite afirmar ausencia de efectos ocultos ni identificar
el objetivo del juego. Los 16 pasos fallidos no mejoran los 247 de una solución.

### Artefactos R2

- [GIF de las 16 acciones, con contadores](v3-results-20261017/r2/bp35-v3.gif).
- [Comparación v2 / R1 / R2](v3-results-20261017/r2/calibration-comparison.png).
- [Contexto y cambios por acción](v3-results-20261017/r2/context-and-actions.png).
- [Scorecard oficial local](v3-results-20261017/r2/official-scorecard.json).
- [Auditoría independiente](v3-results-20261017/r2/independent-audit.json) y
  [programas/stdout por turno](v3-results-20261017/r2/turn-analysis.json).
- [Evidencia pública sin claves](v3-results-20261017/r2/public-evidence.zip).
- [Estado remoto/cuota consultados](v3-results-20261017/r2/status-review.json).

El GIF muestra movimiento inicial y luego clics con muy poco cambio visual;
no es un replay ganador. La temporización es de presentación. El ZIP permite
comprobar digests y consistencia; para revalidar HMAC se necesita la autoridad
local, que no se distribuye. R1 y sus figuras se conservan íntegros.

Reproducción del análisis R2, con el tokenizer fijado y la autoridad local:

```bash
python ECHO-5.5/docs/v3-results-20261017/audit_r2.py \
  --run ECHO-5.5/artifacts/v3-20261017/remote-r2 \
  --output /tmp/echo55-r2-audit \
  --tokenizer-directory /ruta/a/tokenizer-v3/data
python ECHO-5.5/docs/v3-results-20261017/plot_r2.py
```

Las figuras solo requieren JSON públicos y Matplotlib. El análisis requiere
`tokenizers==0.23.3` y `jinja2==3.1.6`; no ejecuta inferencia ni el juego.
Siguiente paso: el replay CPU y los cambios propuestos en el
[diagnóstico](V3-R2-DIAGNOSIS-20261017.md), antes de una posible R3.
