Phase 6.4.25c: correct flex.appendChild -- live verification shows it works

Live probing against Penpot 2.16.2 (repeated, on a dedicated scratch page,
cleaned up afterwards) shows board.flex.appendChild(shape) is a real
function, distinct from board.appendChild, arity 1, throws nothing, and
preserves visual insertion order -- unlike board.appendChild, which still
inserts at the front as documented. The prior "broken" claim traces to the
MCP server's own high_level_overview() text (CRITICAL / BROKEN / NEVER use),
never verified with a live throw, and possibly confused with a real doc bug
that mislabels the grid 3-arg example as board.flex.

Removes flex.appendChild from the lint's FORBIDDEN patterns and from the
gate 5 forbidden-behavior veto, updates PENPOT_API_VERIFIED.md with the
verified facts, and drops the now-obsolete pattern from the replay filters
in 05_build_dataset.py and 07_build_lora2_mix.py.
This commit is contained in:
2026-08-04 17:40:16 +00:00
parent 3496051f72
commit 7a1577b9d7
5 changed files with 34 additions and 17 deletions
+34 -9
View File
@@ -236,19 +236,45 @@ fills = [{ fillOpacity: 1, fillColorGradient: {
| Situación | Forma correcta |
| --- | --- |
| Padre **sin** layout | `parent.insertChild(parent.children.length, shape)` |
| Board **con** flex | `board.appendChild(shape)`, llamado **en orden visual** |
| Board **con** flex | `board.flex.appendChild(shape)` (preferido, orden visual) o `board.appendChild(shape)` (orden invertido, ver abajo) |
| Board **con** grid | `board.grid.appendChild(shape, row, column)`**1-based** |
| Índice específico en flex | `board.insertChild(index, shape)`, recordando el orden invertido |
| Reparentar | `newParent.appendChild(shape)` / `insertChild(...)` — quita del padre viejo, preserva x/y absolutos |
| **PROHIBIDO** | `board.flex.appendChild(shape)`**está roto** |
**Orden invertido, verificado.** En `dir: 'column'` (y `'row'`), apendeando PRIMERO y luego SEGUNDO, el
array `children` queda `[SEGUNDO, PRIMERO, ...]`: `board.appendChild` inserta **al frente**. Por eso hay
que llamarlo en orden visual.
**ACTUALIZACIÓN (2026-08-04, hallazgo 54 de la Fase 6, ronda correctiva 6.4.25c): `board.flex.appendChild(shape)`
NO está roto — verificado en vivo, repetidas veces, contra Penpot 2.16.2.** Es una función real, de
aridad 1, distinta de `board.appendChild` (no es un alias: `board.flex.appendChild !== board.appendChild`,
`board.flex !== board`), que no lanza ninguna excepción y agrega el hijo correctamente, con `layoutChild`
funcionando bien después. La afirmación anterior de que estaba roto **nunca tuvo un error real capturado**
en `penpot_errors.md` (a diferencia de todos los demás comportamientos rotos documentados en este archivo,
que sí lo tienen). Su origen real: el `high_level_overview()` del servidor MCP (capturado verbatim en
`penpot_api_docs.md`, líneas 131-135) le dice al modelo, en mayúsculas y marcado `CRITICAL`, que
**`board.flex.appendChild` está BROKEN y que NUNCA lo use** — instrucción que la sesión original de
diagnóstico tomó como cierta sin verificarla empíricamente con un intento real de romperlo. Esa misma
sección de la doc mezcla además un bug real y distinto (el ejemplo de **grid** con 3 argumentos aparece
escrito como `board.flex.appendChild(shape, row, column)` en vez de `board.grid.appendChild(...)`, ver
`penpot_api_docs.md` línea 143), lo cual reforzó la confusión. **La documentación servida en vivo por el
MCP de Penpot está, en este punto, objetivamente equivocada** (verificado empíricamente, repetidas veces,
el 2026-08-04 contra Penpot 2.16.2) — o el comportamiento se arregló en Penpot después de escribirse esa
documentación, sin actualizarla. Cualquier seed nuevo que muestre al modelo leyendo `high_level_overview`
debería, idealmente, incluir el razonamiento de que esa afirmación puntual sobre `flex.appendChild` no es
confiable y de que hay que verificar con el runtime en vez de creerle a esa línea específica — el mismo
patrón de "la lista de tools es autoritativa, la prosa no" ya usado en el grupo C para `import_image`.
**Orden invertido, verificado — y por qué `board.flex.appendChild` es preferible.** En `dir: 'column'`
(y `'row'`), apendeando PRIMERO y luego SEGUNDO con `board.appendChild`, el array `children` queda
`[SEGUNDO, PRIMERO, ...]`: `board.appendChild` inserta **al frente**, así que hay que llamarlo en orden
inverso al visual para compensar. `board.flex.appendChild`, en cambio, preserva el **orden visual normal**
de las llamadas (PRIMERO, SEGUNDO, ...) — no necesita el truco de inversión. Para boards con flex, **usar
`board.flex.appendChild(shape)` en orden visual directo es la forma más simple y menos propensa a error.**
`board.appendChild` sigue siendo válido (y necesario para reparentar hacia boards sin layout, o cuando el
código ya maneja el truco de inversión de forma consistente), pero ya no es la única opción recomendada.
**La regla absoluta "nunca `appendChild`" que enseñan los seeds viejos es INCORRECTA.** El overview la
califica él mismo (`except in flex layout boards`) y la sección de Flex Layout **manda** usar
`board.appendChild`. La política correcta es condicional, y hay 5 seeds del grupo A3 dedicados a ella.
`board.appendChild`. La política correcta es condicional, y hay 5 seeds del grupo A3 dedicados a ella
esos seeds siguen siendo correctos sobre el comportamiento de `board.appendChild` (el orden invertido es
real), pero ya no reflejan que `board.flex.appendChild` sea una alternativa rota.
**Z-order:** el orden del array `children`. Métodos: `bringToFront()`, `sendToBack()`,
`bringForward()`, `sendBackward()`, `setParentIndex(index)` (0-based).
@@ -269,7 +295,7 @@ califica él mismo (`except in flex layout boards`) y la sección de Flex Layout
| `topPadding`/`rightPadding`/`bottomPadding`/`leftPadding`, `verticalPadding`/`horizontalPadding` | ✅ | |
| `horizontalSizing` / `verticalSizing` | ⚠️ | `'fill'` \| `'auto'` \| `'fit-content'`. **`'auto'` se lee de vuelta como `'auto'` pero el board NO crece** (penpot#8520). Hay que `board.resize()` a mano |
| `wrap` | ✅ | `'wrap'` \| `'nowrap'` |
| `flex.appendChild` | | **Roto.** Usar `board.appendChild` |
| `flex.appendChild` | | **Funciona** (verificado 2026-08-04, hallazgo 54). Aridad 1, preserva orden visual — preferible a `board.appendChild` para insertar en boards con flex |
### Grid
@@ -401,8 +427,7 @@ en prosa.
| --- | --- |
| `findShapeById(` con coma en los argumentos | Aridad 1; la forma de 2 devuelve `null` en silencio |
| `.layout` en una línea sin `shapeStructure` | La propiedad no existe |
| `.flex.appendChild(` | Roto |
| `appendChild(` sobre un receptor sin evidencia de flex | Solo es correcto en boards con flex |
| `appendChild(` sobre un receptor sin evidencia de flex | Solo es correcto en boards con flex (`board.flex.appendChild` o `board.appendChild`) |
| `fontSize`/`fontWeight`/`lineHeight`/`letterSpacing` `= <número>` | Son strings |
| `textAlign =` | Lanza y mata el `execute_code` |
| `importImage`, `import_image`, `createImage(`, `filePath` | No existen en este deployment |