Skip to content

English · Español

Lab 00 — Definir el esquema del conjunto de probes; cargar 60 ejemplos etiquetados

Objetivo: fijar el esquema de probes, construir el loader y validar un conjunto inicial de 60 probes curados a mano que cubren la rejilla de gramática verbal §A13.

Tiempo estimado: 90-120 minutos.

Prerrequisito: el corpus de la Fase 12 está commiteado; data/corpus_spec.md describe las convenciones de etiquetado.


Lo que produces

Un módulo nuevo:

  • src/eval/probes.py — validador de esquema + loader.
  • tests/eval/test_probes.py — tests de esquema + detección de fugas (leaks).

Un archivo de datos nuevo:

  • data/eval/probes.jsonl — 60 probes núcleo (Claude los aporta al abrir la fase como semilla; Borja los extiende si quiere).
  • data/eval/probe_prompt.txt — la plantilla de prompt fija.
  • data/corpus_spec.md — ampliado con una sección "Probe schema".

TODOs

Bloque A — extender data/corpus_spec.md

Añade una sección "Probe schema" que documente:

  • Campos requeridos y sus tipos.
  • Valores permitidos para language, verb, regularity, tense, person, label, category.
  • Reglas de validación (unicidad de id, prevención de fugas, expectedcandidates, consistencia regularidad↔verbo).
  • La matriz de cobertura de theory/03.

Bloque B — implementar src/eval/probes.py

from dataclasses import dataclass
from pathlib import Path
import hashlib, json

REGULAR_VERBS = {"work", "play", "walk", "talk", "listen",
                 "watch", "study", "finish", "start", "look",
                 "want", "like"}
IRREGULAR_VERBS = {"be", "have", "do", "go", "come",
                   "see", "eat", "write"}
TARGET_VERBS = REGULAR_VERBS | IRREGULAR_VERBS  # 20

TENSES = {"infinitive", "present_simple", "past_simple",
          "past_participle", "future"}
PERSONS = {"1sg", "2sg", "3sg"}
LANGUAGES = {"en", "es"}
LABELS = {"correct", "incorrect", "ambiguous"}
CATEGORIES = {"core", "adversarial"}

@dataclass(frozen=True)
class Probe:
    id: str
    language: str
    verb: str
    regularity: str       # "regular" | "irregular"
    tense: str
    person: str
    prompt: str
    candidates: tuple[str, ...]
    expected: str
    label: str
    category: str
    reason_code: str | None = None
    explanation: str | None = None
    source: str = "hand"

def load_probes(path: Path) -> list[Probe]: ...

def validate_probes(probes: list[Probe],
                    train_hashes: set[str],
                    val_hashes: set[str]) -> list[str]:
    """Returns list of error strings; [] = clean."""
    ...

def normalize_prompt(prompt: str, expected: str) -> str:
    """Whitespace+lowercase normalization; replaces non-verb content
    nouns with <NOUN> for stricter leak detection."""
    ...

def hash_prompt(prompt: str, expected: str) -> str:
    """SHA256 hex of the normalized form."""
    ...
  • load_probes parsea JSONL a dataclasses Probe (tupla para candidates).
  • validate_probes ejecuta cada chequeo de theory/03 §"Probe-set checks":
  • corrección del esquema (todos los campos requeridos presentes, tipos correctos)
  • unicidad de id
  • verb ∈ TARGET_VERBS, tense ∈ TENSES, person ∈ PERSONS, language ∈ LANGUAGES
  • label ∈ LABELS, category ∈ CATEGORIES
  • expected ∈ candidates
  • regularity coincide con la clase del verbo
  • leakage contra train_hashes y val_hashes
  • mínimos de la matriz de cobertura
  • normalize_prompt elimina comentarios, normaliza espacios en blanco, pasa a minúsculas, reemplaza nombres de contenido incidentales por <NOUN> (heurística aproximada — lista las limitaciones en el docstring).
  • hash_prompt devuelve SHA256 hex del par (prompt, expected) normalizado.

Bloque C — escribir la plantilla de prompt

data/eval/probe_prompt.txt (formato de opción múltiple):

// Task: pick the grammatically correct verb form for the blank.
// Allowed forms are listed; pick exactly one.
//
// Sentence: {prompt}
// Candidates: {candidates_joined}
// Answer:

Para probes en formato de clasificación (la frase ya tiene una forma; clasificar como CORRECT/INCORRECT/AMBIGUOUS), una plantilla paralela vive en data/eval/classify_prompt.txt:

// Task: classify the grammaticality of the verb form in the sentence below.
// Categories: CORRECT | INCORRECT | AMBIGUOUS
//   CORRECT: the verb agrees with the subject's person and the sentence's tense.
//   INCORRECT: the verb form is wrong for the subject or the tense.
//   AMBIGUOUS: the sentence is grammatical in more than one reading (e.g., "You work").
//
// Sentence: {sentence}
// Classification:

Ambos archivos están congelados por ejecución de eval. Cambios invalidan comparaciones entre ejecuciones.

Bloque D — semilla data/eval/probes.jsonl (60 ejemplos)

Claude aporta los 60 probes iniciales al abrir la fase. El trabajo de Borja en este lab es:

  1. Ejecutar validate_probes(load_probes('data/eval/probes.jsonl'), train_hashes, val_hashes).
  2. Corregir cualquier error de validación. Si un probe filtra contra train, reemplazarlo.
  3. Añadir al menos 5 probes propios — escoge combinaciones de verbo/tiempo/persona/idioma que sospechas que el modelo va a tener difícil según los informes de las Fases 18-19.

Bloque E — tests en tests/eval/test_probes.py

  1. test_load_known_probes — parsea el archivo semilla sin error; count = 60.
  2. test_validate_clean_set — dado el archivo semilla y train_hashes vacío, devuelve [].
  3. test_detects_id_dup — dado un probe-set con dos probes que comparten id, devuelve un error de duplicación.
  4. test_detects_leak — dado un probe cuyo hash prompt-expected coincide con un train hash, devuelve un error de leakage.
  5. test_detects_regularity_mismatch — un probe con verb="go" y regularity="regular" es rechazado.
  6. test_detects_expected_not_in_candidates — un probe con expected="ate" pero candidates=["eat","eats","eaten"] es rechazado.
  7. test_coverage_matrix_minima — dado un probe-set que carece de la lengua es por completo, devuelve un error de cobertura.
  8. test_normalize_idempotentnormalize_prompt(normalize_prompt(p, e), e) == normalize_prompt(p, e).

Restricciones

  • Python puro + biblioteca estándar. Sin validadores de esquema externos (Pydantic, etc.); un dataclass con algunos chequeos basta.
  • La detección de fugas es obligatoria. Sin excepciones.
  • Los probes están en JSONL, no en YAML / array JSON. Una línea por probe, conceptualmente append-only.
  • EN y ES conviven en el mismo archivo — se distingue por el campo language, no por ruta de archivo. (Algunos equipos separan por idioma; nosotros no, porque la lógica de slicing se simplifica.)

Condiciones de parada

Hecho cuando:

  1. pytest tests/eval/test_probes.py -v pasa todos los tests.
  2. data/eval/probes.jsonl tiene ≥ 60 probes que pasan validate_probes contra train+val de la Fase 12.
  3. Se cumplen los mínimos de cobertura (≥ 30 EN, ≥ 30 ES, ≥ 30 regulares, ≥ 30 irregulares, ≥ 10 por tiempo, ≥ 15 por persona).
  4. data/corpus_spec.md está ampliado con el Probe schema.

Trampas

  • Normalizar sin preservar la forma verbal. Si normalize_prompt elimina la forma verbal junto con los sustantivos del entorno, no puede detectar fugas correctamente. Preserva la forma verbal; reemplaza solo los sustantivos de contenido incidentales.
  • Olvidar que ambiguous es una clase real. Algunas frases en 2sg son genuinamente ambiguas entre 2sg y plural en inglés; márcalas ambiguous, no correct.
  • Probes del lado español que en realidad son spanglish. Mantén coherencia dentro de un probe: language: es significa que el prompt entero está en español, incluidos los marcadores temporales.
  • Colisiones de id entre archivos. probes.jsonl y adversarial.jsonl comparten el namespace de id. Usa convenciones de prefijo tipo probe-... y adv-....
  • Confusión con la lista de verbos irregulares. be / have / do / go / come / see / eat / write — escríbela una vez, refiérete a esa lista. Evita confiar en la memoria a mitad de redactar probes.

Cuándo consultar solutions/

Después de que pasen los ocho tests. La solución en solutions/00-probe-schema-ref.md (escrita al abrir la fase) recorre la función de normalización y el chequeo de la matriz de cobertura.


Siguiente lab: lab/01-harness-perplexity-accuracy.md.