PROTOCOLO — Batuta Zero

Procedimiento ejecutable para el primer experimento de Batuta. Está escrito para que una persona pueda realizarlo de principio a fin sin tener que decidir nada sobre la marcha.

Tamaño de la primera tanda: 5 tareas × 4 modelos × 2 brazos = 40 rondas (aproximadamente una semana).

El punto de datos cero no es valioso por su resultado. Es valioso por ser un número sobre skills producido con orden aleatorio, sesión limpia, evaluación ciega y datos brutos publicados. Si el protocolo se desvía, el dato se convierte en basura; y publicar basura con apariencia de medición es peor que no publicar ningún dato.


0. Antes de empezar

0.1 Las cinco tareas

No se redacta una tarea nueva para Zero. Se utiliza la batería congelada, de modo que el primer punto ya sea comparable con todo lo que venga después.

código Zerotarea de la batería v1categoríaverificación
z-01cod-01codigoautomática
z-02cod-02codigoautomática
z-03cod-03codigoautomática
z-04cod-04codigoautomática
z-05esc-01escritamixta

Las cuatro tareas automáticas permiten obtener el número casi sin coste. La quinta existe para que el procedimiento de evaluación ciega se ejecute de verdad en esta tanda, en vez de estrenarse en producción.

0.2 Los cuatro modelos

Uno por franja. El nombre exacto se registra en manifesto.json (paso 1.3), no en este documento: el modelo cambia, la franja no.

idfranja
m1gama alta de pago
m2gama media
m3pequeño
m4gratuito / local

Un único canal para las 40 rondas: OpenRouter. Véase «el canal no multiplica» en bateria/v1/README.md.

0.3 Los dos brazos

idqué está activado
Asem-nada: ninguna skill instalada y enrutador desactivado
Bcom-skill: solo las skills_candidatas de la tarea y enrutador activado

El enunciado es idéntico, palabra por palabra, en ambos. La diferencia está en el entorno y en ningún otro lugar.


1. Pasos

Paso 1 — Fijar el terreno una vez, antes de cualquier ronda

1.1 Crear la estructura.

mkdir -p ~/batuta-zero/{tarefas,rodadas,cego,vereditos,publicacao}
cd ~/batuta-zero

1.2 Publicar la semilla antes que nada.

La semilla hace auditable el sorteo: cualquier persona puede repetirlo y debe llegar al mismo orden.

SEED="batuta-zero-v1-$(date +%Y-%m-%d)-$(head -c 8 /dev/urandom | xxd -p)"
printf 'SEED=%s\n' "$SEED" > SEED.txt
cat SEED.txt
git add SEED.txt && git commit -m "batuta zero: semente publicada antes da primeira rodada"
git push

El commit de la semilla precede a la primera ronda. Una semilla publicada después no vale: quien publica tarde puede escoger la que produzca el orden que desea.

1.3 Congelar el manifiesto de la tanda.

cat > manifesto.json <<'JSON'
{
  "leva": "batuta-zero-1",
  "bateria": "batuta.bateria.v1@1.0.0",
  "canal": "openrouter",
  "tarefas": ["cod-01", "cod-02", "cod-03", "cod-04", "esc-01"],
  "modelos": {
    "m1": {"faixa": "topo-pago",    "id_canal": "PREENCHER", "versao": "PREENCHER"},
    "m2": {"faixa": "media",        "id_canal": "PREENCHER", "versao": "PREENCHER"},
    "m3": {"faixa": "pequeno",      "id_canal": "PREENCHER", "versao": "PREENCHER"},
    "m4": {"faixa": "gratis-local", "id_canal": "PREENCHER", "versao": "PREENCHER"}
  },
  "bracos": {"A": "sem-nada", "B": "com-skill"},
  "temperatura": 0,
  "teto_turnos": "o teto_turnos de cada tarefa em tarefas.json",
  "holdout_causal": "desligado nesta leva (ver secao 5)"
}
JSON

Los campos PREENCHER se rellenan con el identificador y la versión servida de cada modelo, copiados del canal. El archivo se confirma antes de la primera ronda.

1.4 Extraer los cinco enunciados palabra por palabra.

python3 - <<'PY'
import json, pathlib
b = json.load(open('/caminho/para/batuta/bateria/v1/tarefas.json', encoding='utf-8'))
alvo = {'cod-01': 'z-01', 'cod-02': 'z-02', 'cod-03': 'z-03',
        'cod-04': 'z-04', 'esc-01': 'z-05'}
for t in b['tarefas']:
    if t['id'] in alvo:
        p = pathlib.Path('tarefas') / (alvo[t['id']] + '.md')
        p.write_text(t['enunciado'] + '\n', encoding='utf-8')
        print(p, len(t['enunciado']), 'caracteres')
PY
sha256sum tarefas/*.md > tarefas/CHECKSUMS.txt
git add tarefas && git commit -m "batuta zero: enunciados congelados" && git push

A partir de aquí, tarefas/*.md es ley. Antes de cada jornada se comprueban los checksums:

sha256sum -c tarefas/CHECKSUMS.txt

Si falla, la serie está contaminada: se detiene todo y se vuelve a empezar (sección 4).


Paso 2 — Sortear el orden de los brazos de forma determinista

Ejecutar siempre el brazo B primero mediría calentamiento, no el efecto de una skill. El orden de cada pareja —tarea × modelo— se sortea a partir de la semilla publicada, no por intuición.

2.1 Función de sorteo.

. ./SEED.txt

braco_primeiro () {   # $1 = tarefa, $2 = modelo
  h=$(printf '%s|%s|%s' "$SEED" "$1" "$2" | sha256sum | cut -c1-8)
  if [ $(( 0x$h % 2 )) -eq 0 ]; then echo "A B"; else echo "B A"; fi
}

2.2 Generar el plan para las 20 parejas, 40 rondas.

: > plano.tsv
for t in z-01 z-02 z-03 z-04 z-05; do
  for m in m1 m2 m3 m4; do
    printf '%s\t%s\t%s\n' "$t" "$m" "$(braco_primeiro "$t" "$m")" >> plano.tsv
  done
done
cat plano.tsv
sha256sum plano.tsv > plano.sha256
git add plano.tsv plano.sha256 && git commit -m "batuta zero: plano sorteado" && git push

El plan es reproducible: quien tenga SEED.txt ejecuta los mismos comandos y obtiene un plano.tsv idéntico byte por byte. Eso es lo que da significado a «aleatorio».

2.3 Orden de las rondas. Se sigue plano.tsv de arriba abajo. No se omite una línea porque «esta tardará mucho». Omitir en el momento equivale a escoger.


Paso 3 — Ejecutar una ronda, repetido 40 veces

Cada ronda tiene el identificador <tarefa>-<modelo>-<braco>, por ejemplo z-02-m3-B.

3.1 Directorio limpio.

R="z-02-m3-B"                      # trocar a cada rodada
rm -rf "rodadas/$R"
mkdir -p "rodadas/$R/trabalho"
cd "rodadas/$R/trabalho"

3.2 Generar los insumos. Se ejecuta, en orden, el gerador de cada tarea definido en tarefas.json, con trabalho/ como directorio actual. Después se comprueba:

ls -la
sha256sum * > ../INSUMOS.sha256

Los mismos insumos, byte por byte, se usan en ambos brazos. Si difieren los checksums de A y B, la pareja queda invalidada y se repite completa.

3.3 Sesión limpia, sin excepciones.

  • Ventana nueva, conversación nueva y cero historial.
  • Nada de «continúa desde allí» ni «igual que la vez anterior».
  • En el brazo A no hay skills instaladas y el enrutador está apagado: se comprueba.
  • En el brazo B están instaladas únicamente las skills_candidatas de la tarea.
  • Temperatura 0, o el mínimo que acepte el canal; se registra el valor usado.
  • Entre A y B de la misma pareja se cierra el cliente por completo.

Antes de pegar el enunciado se verifica:

ls ~/.claude/skills 2>/dev/null || echo "(nenhuma skill instalada)"

3.4 Pegar el enunciado. Se muestra con cat ../../../tarefas/z-02.md y se pega sin añadir nada antes ni después. No se agrega «por favor», «hazlo bien» ni «usa la skill X». Si el modelo pregunta, solo se responde con información que ya figure en el enunciado o en los insumos. Si no está, la respuesta es «sigue el enunciado» y la pregunta queda registrada en meta.json.

3.5 Dejar que trabaje hasta el teto_turnos de la tarea. Si supera el límite sin entregar, se registra reprovada_por_teto. No se descarta: es un resultado.

3.6 Guardar la salida bruta.

cd ..
mkdir -p saida
cp -a trabalho/. saida/            # todos os arquivos produzidos
# e a transcrição completa da conversa, exportada do cliente:
#   saida/transcricao.md

3.7 Ejecutar el verificador en las tareas automatica y mista:

cd trabalho
bash -e -c "$(python3 -c "
import json;b=json.load(open('/caminho/para/batuta/bateria/v1/tarefas.json',encoding='utf-8'))
print([t for t in b['tarefas'] if t['id']=='cod-02'][0]['verificador'])")"
echo "codigo de saida: $?"
cd ..

3.8 Cerrar el registro de la ronda en meta.json, con el schema de la sección 3.

3.9 Volver a la raíz y pasar a la siguiente línea del plan.


Paso 4 — Anonimizar para la evaluación ciega

La evaluación es ciega también para quien ejecuta. Quien sabe que una salida viene del brazo con skill encuentra calidad en ella, no por mala fe, sino por ser humano.

4.1 Buscar autorrevelaciones. Una salida puede delatarse con frases como «siguiendo la skill Y». Eso no se borra de los datos brutos: se sustituye solo en la copia ciega y se registra la sustitución.

grep -rniE 'skill|claude|gpt|gemini|llama|mistral|anthropic|openai' rodadas/*/saida/ \
  > cego/autodelacao.log || true
wc -l cego/autodelacao.log

4.2 Generar copias ciegas con códigos opacos.

: > mapa.tsv
for d in rodadas/*/; do
  R=$(basename "$d")
  COD=$(head -c 12 /dev/urandom | xxd -p)
  printf '%s\t%s\n' "$COD" "$R" >> mapa.tsv
  mkdir -p "cego/$COD"
  cp -a "$d/saida/." "cego/$COD/"
  # substituições da 4.1, aplicadas SÓ na cópia cega:
  grep -rlZ -iE 'skill|claude|gpt|gemini|llama|mistral|anthropic|openai' "cego/$COD" 2>/dev/null \
    | xargs -0 -r sed -i -E 's/(skill|claude|gpt|gemini|llama|mistral|anthropic|openai)/[REDIGIDO]/Ig'
done

4.3 Sellar el mapa antes de mirar cualquier salida.

sha256sum mapa.tsv > mapa.sha256
git add mapa.sha256 && git commit -m "batuta zero: mapa selado antes do julgamento" && git push
mv mapa.tsv ~/.batuta-zero-mapa-selado.tsv     # fora da pasta de trabalho
chmod 400 ~/.batuta-zero-mapa-selado.tsv

El hash entra en el repositorio antes de evaluar y el archivo sale del directorio de trabajo. Al final se publica el mapa y cualquiera puede comprobar que coincide con el sellado. Así se impide que aparezca después una versión conveniente del mapa.

4.4 Barajar el orden de evaluación usando también la semilla.

. ./SEED.txt
ls cego | grep -v autodelacao.log | LC_ALL=C sort \
  | shuf --random-source=<(openssl enc -aes-256-ctr -pass "pass:$SEED" -nosalt </dev/zero 2>/dev/null) \
  > ordem_julgamento.txt
head ordem_julgamento.txt

Se evalúa en ese orden, de arriba abajo, sin inspeccionar previamente toda la lista.


Paso 5 — Evaluar

5.1 Qué se evalúa. Para cada código de ordem_julgamento.txt, se abre cego/<codigo>/, se consulta la tarea correspondiente en tarefas/ y se responde sí o no a cada elemento de criterio_aceite. No se asigna una nota global antes de responder los elementos.

5.2 Registrar el veredicto en vereditos/<codigo>.json, con el schema de la sección 3.

5.3 No volver atrás. Un veredicto registrado no se reabre después de revelar el mapa. Una duda posterior se publica como observación, no como corrección.

5.4 Solo después de los 40 veredictos se revela el mapa, comprobando primero que es el mismo que se selló:

cp ~/.batuta-zero-mapa-selado.tsv mapa.tsv
sha256sum -c mapa.sha256        # tem que imprimir: mapa.tsv: OK

Si aparece FAILED, se descarta la tanda completa y se publica como descartada, con el motivo. Un descarte publicado vale más que un resultado rescatado.

Solo cuando la pantalla muestra OK se unen los veredictos con las rondas:

join -1 1 -2 1 -t $'\t' <(LC_ALL=C sort mapa.tsv) \
     <(for v in vereditos/*.json; do
         printf '%s\t%s\n' "$(basename "$v" .json)" \
           "$(python3 -c 'import json,sys;print(json.load(open(sys.argv[1]))["aprovada"])' "$v")"
       done | LC_ALL=C sort) > resultados.tsv
cat resultados.tsv

Paso 6 — Publicar los datos brutos

Lo que separa Batuta de una afirmación en un README es que cualquiera puede repetir la evaluación y discrepar.

mkdir -p publicacao
cp -a tarefas manifesto.json SEED.txt plano.tsv mapa.tsv mapa.sha256 \
      vereditos ordem_julgamento.txt publicacao/
for d in rodadas/*/; do
  R=$(basename "$d")
  mkdir -p "publicacao/rodadas/$R"
  cp -a "$d/saida" "$d/meta.json" "$d/INSUMOS.sha256" "publicacao/rodadas/$R/"
done
python3 -c "import pathlib,hashlib;[print(hashlib.sha256(p.read_bytes()).hexdigest(), p) for p in sorted(pathlib.Path('publicacao').rglob('*')) if p.is_file()]" > publicacao/MANIFEST.sha256
git add publicacao && git commit -m "batuta zero leva 1: cru completo" && git push

Cada pareja publica el enunciado, ambas salidas y el veredicto. También incluye el plan sorteado, la semilla, el mapa sellado y los checksums.

La publicación se enlaza con el hash de la anterior y la cabecera se sella con OpenTimestamps, de acuerdo con la sección 8 del dossier.


2. EL JUEZ

2.1 Las tres leyes

Ley 1 — Ciego. El juez no sabe si se activó una skill, qué brazo produjo la salida ni qué modelo la escribió. Si lo sabe, confirma lo que esperamos oír y el número deja de ser válido. Se aplica tanto al modelo juez como a la persona que ejecuta.

Ley 2 — No es el acusado. Un modelo nunca juzga su propia salida. La evaluación es cruzada, siempre. Parejas para la primera tanda:

salida dejuzgada por
m1 (gama alta de pago)m2
m2 (gama media)m1
m3 (pequeño)m1
m4 (gratuito/local)m2

Ningún modelo aparece en ambas columnas de la misma fila. El modelo juez pertenece a una franja alta porque evaluar cuesta menos que producir; su coste no es el cuello de botella.

Ley 3 — Versionado. Junto a cada veredicto se registran el identificador del modelo juez, la versión exacta servida por el canal, la instrucción completa del juez —no un resumen ni un enlace—, la temperatura y el hash de esa instrucción. Un juez que cambia sin changelog invalida retroactivamente toda la serie histórica.

Cada cambio de instrucción crea una versión nueva (juiz-v1 → juiz-v2), una entrada de changelog y mantiene las series anteriores marcadas con la versión antigua. El pasado no se sustituye con el juez nuevo: se recalcula y se publican ambas series, declarando cuál es cuál.

El juez es una señal, no la verdad. Está al lado de proxies duros como reprompts, errores, reintentos y el código de salida del verificador. Cuando falla el verificador, no se consulta al juez: una salida que falló el objetivo no queda salvada por una conversación convincente.

2.2 Rúbrica por categoría

La rúbrica no sustituye criterio_aceite: se aplica después. Primero se responde sí o no a cada criterio; la rúbrica solo separa «cumplió» de «cumplió bien» entre las salidas que aprobaron todo. Cada eje vale 0, 1 o 2.

codigo — el verificador ya indica si pasa. La rúbrica observa lo demás:

  1. Supervivencia: maneja entrada vacía, límites y tipos incorrectos sin romperse.
  2. Legibilidad: una persona encuentra el defecto en menos de dos minutos.
  3. Contención: no reescribe lo que no se pidió ni añade una dependencia nueva.

escrita:

  1. Fidelidad factual: no añade, elimina ni cambia el valor de ningún hecho.
  2. Sirve al lector declarado: el destinatario entiende sin releer.
  3. Densidad: cada frase aporta información; ninguna existe solo para sonar bien.

dados:

  1. Número correcto: coincide con el valor recalculado a partir de la entrada.
  2. Método declarado: se puede repetir el cálculo leyendo lo que escribió.
  3. Casos límite: empates, ausencias, duplicados y valores imposibles reciben una decisión explícita.

documentos:

  1. Formato real: el archivo abre en el programa objetivo; no es otro formato con la extensión cambiada.
  2. Estructura solicitada: secciones, orden y cantidades coinciden con el enunciado.
  3. Trazabilidad: cada campo completado tiene un origen rastreable en la entrada.

pesquisa:

  1. Anclaje: cada afirmación indica de dónde procede.
  2. Declara el vacío: lo que las fuentes no responden queda sin responder, no se rellena con plausibilidad.
  3. Reconoce la tensión: si las fuentes discrepan, se nombra el desacuerdo.

automacao:

  1. Idempotencia: ejecutarla dos veces no rompe nada.
  2. Fallo visible: termina con código distinto de cero y un mensaje en el lugar correcto.
  3. Reanudación: el estado permite continuar desde el punto de detención sin repetir lo ya terminado.

Escala final por salida: aprovada si todos los criterios son sí, o reprovada si alguno es no, más el total de la rúbrica de 0 a 6. La aprobación es el número principal. La rúbrica sirve para desempatar y siempre se publica junto con la aprobación, nunca sola.

2.3 Qué se registra junto al veredicto

{
  "juiz": {
    "modelo": "PREENCHER",
    "versao_servida": "PREENCHER",
    "canal": "openrouter",
    "temperatura": 0,
    "prompt_versao": "juiz-v1",
    "prompt_sha256": "PREENCHER",
    "prompt_integral": "PREENCHER — o texto inteiro, sem corte"
  }
}

Un veredicto sin prompt_integral no entra en el dataset. No existe la excepción «la instrucción es demasiado larga».


3. Schemas de registro

3.1 rodadas/<id>/meta.json — uno por ronda

{
  "rodada_id": "z-02-m3-B",
  "leva": "batuta-zero-1",
  "bateria": "batuta.bateria.v1@1.0.0",
  "tarefa_bateria": "cod-02",
  "tarefa_zero": "z-02",
  "categoria": "codigo",
  "complexidade": "media",
  "modelo": "m3",
  "modelo_id_canal": "PREENCHER",
  "modelo_versao_servida": "PREENCHER",
  "canal": "openrouter",
  "temperatura": 0,
  "braco": "B",
  "braco_nome": "com-skill",
  "ordem_na_dupla": 1,
  "ordem_sorteada_por": "sha256(SEED|tarefa|modelo)",
  "skills_instaladas": [{"nome": "systematic-debugging", "versao": "PREENCHER"}],
  "skills_que_dispararam": ["systematic-debugging"],
  "roteador": {"ativo": true, "versao": "PREENCHER", "holdout_causal": false},
  "sessao_limpa": true,
  "insumos_sha256": "conteudo de INSUMOS.sha256",
  "enunciado_sha256": "PREENCHER",
  "turnos_usados": 3,
  "teto_turnos": 5,
  "reprompts": 1,
  "erros_de_ferramenta": 0,
  "tokens_entrada": 0,
  "tokens_saida": 0,
  "custo_usd": 0.0,
  "duracao_s": 0,
  "verificador_codigo_saida": 0,
  "desfecho": "aprovada | reprovada | reprovada_por_teto | erro_de_infra",
  "perguntas_do_modelo": [],
  "incidentes": []
}

3.2 vereditos/<codigo>.json — uno por salida ciega

{
  "codigo_cego": "PREENCHER",
  "tarefa_zero": "z-02",
  "julgado_em": "2026-09-03",
  "julgado_por": "humano-cego | modelo-cruzado",
  "criterio_aceite": [
    {"n": 1, "texto": "caixa.py continua expondo total(itens, cupom=None).", "resposta": "sim"},
    {"n": 2, "texto": "total([(5000, 2)]) devolve 9000.", "resposta": "sim"}
  ],
  "aprovada": true,
  "rubrica": {"eixo_1": 2, "eixo_2": 1, "eixo_3": 2, "total": 5},
  "observacao_livre": "",
  "juiz": {
    "modelo": "PREENCHER",
    "versao_servida": "PREENCHER",
    "prompt_versao": "juiz-v1",
    "prompt_sha256": "PREENCHER",
    "prompt_integral": "PREENCHER"
  }
}

3.3 Hoja de seguimiento, 40 filas

Una fila por ronda, con estas columnas y en este orden:

rodada_id | tarefa_zero | tarefa_bateria | categoria | complexidade | modelo |
faixa | canal | braco | ordem_na_dupla | sessao_limpa | skills_instaladas |
skills_que_dispararam | turnos_usados | teto_turnos | reprompts |
verificador_codigo_saida | desfecho | codigo_cego | aprovada | rubrica_total |
tokens_entrada | tokens_saida | custo_usd | duracao_s | incidentes

Se exporta como CSV. codigo_cego y aprovada solo se rellenan después del paso 5.4. Durante la evaluación ambas columnas permanecen vacías y el archivo no se abre.

El número que importa al final no es «cuántas aprobaron». Es, por franja de modelo, aprovadas(B) − aprovadas(A), además del coste por tarea completada en cada brazo. Una skill puede encarecer una llamada y abaratar la tarea al evitar reprompts. Esa es la métrica que falta en las comparaciones habituales.


4. Lo que NUNCA puede ocurrir

Cada elemento siguiente contamina la tanda. La regla es la misma: detenerse, registrar el incidente y repetir lo necesario; nunca continuar para mencionarlo al final.

Contaminación

  1. Reutilizar sesión, pestaña, contexto o historial entre rondas.
  2. Ejecutar B después de A en la misma ventana sin cerrar el cliente.
  3. Pegar el enunciado con una palabra añadida o ausente.
  4. Responder una pregunta con información que no esté en el enunciado o los insumos.
  5. Ayudar durante la ronda: corregir, señalar un error o sugerir una vía.
  6. Dejar una skill instalada en A o una ajena a skills_candidatas en B.
  7. Usar insumos diferentes entre A y B; se verifica INSUMOS.sha256.
  8. Ejecutar una pareja en días con versiones distintas del mismo modelo sin registrarlo.

Etiqueta visible

  1. Evaluar sabiendo qué brazo, modelo u orden produjo la salida.
  2. Nombrar carpeta, archivo o pestaña con brazo, modelo o «con/sin».
  3. Abrir mapa.tsv o la hoja de seguimiento antes del último veredicto.
  4. Dejar que la salida se delate en la copia ciega sin pasar por el escaneo 4.1.
  5. Evaluar seguidas las dos salidas de una pareja; el barajado existe para evitarlo.

Mover la regla a mitad del proceso

  1. Editar enunciado, insumo, criterio o verificador después de la primera ronda.
  2. Cambiar semilla, plan u orden después de publicarlos.
  3. Añadir o retirar una tarea durante la tanda.
  4. Cambiar la instrucción del juez durante los 40 veredictos.
  5. Reabrir un veredicto después de revelar el mapa.

Publicación

  1. Publicar un número sin los datos brutos que lo sostienen.
  2. Ocultar una ronda descartada: también se publica, con el motivo.
  3. Publicar sin canal, versión de batería y versión del juez.

5. Holdout causal

Una skill que aparece junto a un buen resultado demuestra correlación. Para medir causalidad, alguien debe no recibirla sin que eso dependa de quién sea el usuario. Ese es el grupo de control.

Funcionamiento. En el 5% de los turnos, elegido al azar en el momento del turno, el enrutador permanece en silencio deliberadamente: no propone ninguna skill aunque exista una coincidencia clara. El evento lleva holdout: true y entra en el dataset como control.

Condiciones obligatorias:

  1. Declarado ante la persona usuaria. Una frase en la primera ejecución, no escondida en documentación: «En el 5% de los turnos Batuta permanece en silencio a propósito para medir si la skill realmente ayuda. Esto hace honesto el número. Puedes cambiar el porcentaje o desactivarlo en ~/.batuta/config.json».
  2. Configurable. holdout_pct acepta valores de 0 a 100.
  3. Desactivable. holdout_pct = 0 lo desactiva sin degradar nada más.
  4. Marcado en los datos. Cada turno de holdout se sube identificado; sin marca, el dato está corrupto.
  5. Nunca oculto. Un experimento escondido destruye el proyecto. Si la declaración no cabe en la interfaz, el holdout no se ejecuta.

Configuración:

{
  "holdout_pct": 5,
  "holdout_semente": "por-instalacao, gerada localmente",
  "holdout_declarado_em": "primeira execucao"
}

En Batuta Zero el holdout está desactivado mediante holdout_causal en manifesto.json. Zero ya es un experimento controlado: sus dos brazos son el control. El holdout existe para la flota, donde no se puede pedir a cada persona que ejecute dos veces la tarea.

Cómo leer el número. Dentro de la misma instalación, perfil de uso y ventana temporal, se compara el resultado de los turnos holdout: true con los turnos donde el enrutador habló. La diferencia es atribuible al enrutamiento y no al tipo de usuario, algo que una comparación entre usuarios no puede demostrar.


6. Checklist de bolsillo

Antes de cada ronda:

  • [ ] sha256sum -c tarefas/CHECKSUMS.txt pasó.
  • [ ] Se usa la siguiente línea de plano.tsv, sin saltos.
  • [ ] El directorio de la ronda se recreó desde cero.
  • [ ] Los insumos tienen checksum idéntico al otro brazo.
  • [ ] El cliente se cerró y reabrió; la sesión es nueva.
  • [ ] Las skills se comprobaron con ls, no se dieron por supuestas.
  • [ ] El enunciado se pegó sin una palabra adicional.

Antes de evaluar:

  • [ ] Las 40 rondas están cerradas y cada meta.json está completo.
  • [ ] El escaneo de autorrevelación se ejecutó y registró.
  • [ ] mapa.sha256 está confirmado y el mapa fuera del directorio de trabajo.
  • [ ] ordem_julgamento.txt se generó desde la semilla.
  • [ ] La hoja de seguimiento está cerrada.

Antes de publicar:

  • [ ] sha256sum -c mapa.sha256 pasa.
  • [ ] Datos brutos completos: enunciado, dos salidas y veredicto para las 20 parejas.
  • [ ] Los descartes se publican con su motivo.
  • [ ] La instrucción íntegra del juez acompaña cada veredicto.
  • [ ] Canal, versión de batería y versión del juez figuran en cada fila.
  • [ ] La publicación se enlazó a la anterior y tiene prueba de OpenTimestamps.