Phase 6.4.25b: 13 corrective seeds for gate 5 diagnosis, rebuild training mix

Diagnosis (audited gate5 full-mode transcripts, PNGs, and holdout payloads):
the dominant failure mode was NOT rubro/content coverage but a tool-call
formatting bug -- after diagnosing an exception, the model often writes its
retry as literal <tool_call> XML text embedded in reasoning instead of a
structured call, so it's silently dropped (9/10 gate5 full-mode prompts hit
this on their final captured turn). Reasoning length before a tool call
correlates with the failure (malformed-turn mean 1895 chars vs 364 for
well-formed turns), while the training mix's own tool-calling turns never
exceed 1630 chars and export_shape turns never exceed 485.

Corrective seeds (group D, grupo 'D', short 1-3 sentence diagnosis +
immediate well-formed retry, to avoid reinforcing long-reasoning risk):
- 9 seeds across fresh rubros (lavanderia, zapateria, optica, jugueteria,
  papeleria, peluqueria, floreria, heladeria, cerrajeria) covering distinct
  real API errors: .color on Text, addFlexLayout on non-Board, findShapeById
  2-arg, createText() no-arg, textAlign, typography.setFont, createBoolean
  null, appendChild no-arg, uploadMediaUrl network rejection.
- 4 seeds reinforcing uploadMediaUrl over the exact penpot.importImage
  variant the model actually invents (distinct from the one existing seed,
  which only taught the penpotUtils.importImage variant) -- rubros:
  relojeria, guarderia infantil, agencia de viajes, kiosco.

Deliberately avoid ferreteria/gimnasio/veterinaria/panaderia: reserved for
the held-out generalization probe (separate from the frozen gate 5).

Added the newly-verified error strings (t.color, penpot.importImage,
addFlexLayout-on-non-Board) to penpot_errors.md -- all captured live from
this phase's own gate 5 full-mode run, not fabricated.

Rebuilt train_lora2.jsonl (901)/eval_lora2.jsonl (99)/calibration_v2.jsonl
from the 138-seed corpus (07_build_lora2_mix.py) and validated
(06_validate_dataset.py, 0 exceptions, 0 secrets, max 3271 tokens).
This commit is contained in:
2026-08-03 15:44:22 +00:00
parent 730e42494f
commit 18efe3fa5d
5 changed files with 682 additions and 647 deletions
+128 -128
View File
File diff suppressed because one or more lines are too long
+50 -50
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+23 -1
View File
@@ -31,9 +31,16 @@ la interfaz lanza, y la excepción **aborta todo el `execute_code`**, no solo es
| Disparador | Mensaje verbatim |
| --- | --- |
| `text.textAlign = 'center'` | `Cannot add property textAlign, object is not extensible` |
| `text.color = '#...'` | `Cannot add property color, object is not extensible` |
Forma del mensaje, generalizable: `Cannot add property <nombre>, object is not extensible`.
**`text.color` (capturado en vivo, puerta 5 modo full, paso 6.4.25, prompts `g5-06-landing-pizzeria` y
`g5-01-boton-primario`, 2026-08-03):** el modelo asume que `Text` tiene una propiedad `color` de nivel
superior (analogía con CSS) en vez de usar `fills`. Es el mismo mecanismo que `textAlign` —el objeto
`Text` no es extensible— pero para una propiedad distinta, y hoy no hay ningún seed que lo enseñe (el
lint ya lo detecta como patrón prohibido, cero ejemplos de recuperación en el corpus).
La propiedad correcta para alineación horizontal de texto es **`align`**
(`'left' \| 'center' \| 'right' \| 'justify'`). Ver `penpot_api_docs.md` Captura 4.
@@ -48,9 +55,17 @@ composición completa, no solo el título.
| Disparador | Mensaje verbatim |
| --- | --- |
| `penpotUtils.importImage(url)` | `penpotUtils.importImage is not a function` |
| `penpot.importImage(url)` | `penpot.importImage is not a function` |
| `typography.setFont(font)` sobre un `LibraryTypography` | `t.setFont is not a function` |
Dos casos distintos, y la diferencia importa pedagógicamente:
**`penpot.importImage` (capturado en vivo, puerta 5 modo full y holdout, paso 6.4.25, 2026-08-03):**
variante distinta de la ya documentada `penpotUtils.importImage` — el modelo la invoca directamente
sobre el objeto `penpot` (no sobre `penpotUtils`), en 1 de los 10 prompts de la puerta 5 modo full
(`g5-03-card-producto`) y en 4 de los 60 del holdout, siempre en prompts que piden "una foto real
traída de una URL". El único seed de recuperación existente (grupo D) enseña la variante
`penpotUtils.importImage`, no ésta — de ahí que el modelo no generalizara la lección.
Tres casos distintos, y la diferencia importa pedagógicamente:
- `penpotUtils.importImage` **nunca existió**: no está en la Captura 1 de `penpot_api_docs.md`, ni
`import_image` está entre las herramientas MCP de este deployment (ver `data/schemas/penpot.json`).
@@ -76,6 +91,13 @@ llamadas de creación y de búsqueda pueden devolver `null`; usar el resultado s
| `const s = penpotUtils.findShapeById(page, id); s.x = 10` | `Cannot read properties of null (reading 'x')` |
| `const s = penpotUtils.findShapeById(idInexistente); return s.fills` | `Cannot read properties of null (reading 'fills')` |
| `const b = penpot.createBoolean('union', []); b.name = 'x'` | `Cannot set properties of null (setting 'name')` |
| `const r = penpot.createRectangle(); const f = r.addFlexLayout(); f.dir = 'row'` | `Cannot set properties of null (setting 'dir')` |
**`addFlexLayout()` sobre un `Rectangle` (capturado en vivo, puerta 5 modo full, `g5-02-navbar-flex`,
2026-08-03):** `addFlexLayout()` solo existe en `Board`. Llamarlo sobre un `Rectangle` (o sobre un
`Board` que ya tiene un layout asignado) devuelve `null` en silencio en vez de lanzar; el error real
aparece recién en la línea siguiente al intentar setear una propiedad del layout inexistente. Hay que
chequear el retorno de `addFlexLayout()` antes de usarlo, igual que con `createText()`.
Forma del mensaje, generalizable:
`Cannot read properties of null (reading '<prop>')` y
+468 -468
View File
File diff suppressed because one or more lines are too long