Merge pull request 'Phase 6: train a second LoRA for real Penpot UI design capability' (#5) from agente-fase6-lora2-penpot into master

This commit was merged in pull request #5.
This commit is contained in:
2026-08-04 21:36:03 -06:00
126 changed files with 2560744 additions and 491 deletions
+16
View File
@@ -11,8 +11,24 @@ out/lora-adapter/checkpoint-*/
*.pt
!out/lora-adapter/adapter_model.safetensors
!out/lora-adapter/training_args.bin
!out/lora-adapter-penpot/adapter_model.safetensors
!out/lora-adapter-penpot/training_args.bin
!out/lora-adapter-penpot-v2/adapter_model.safetensors
!out/lora-adapter-penpot-v2/training_args.bin
__pycache__/
*.pyc
.ipynb_checkpoints/
.env
.worktrees/
# Fase 6: checkpoints intermedios del LoRA #2. El adapter final
# (out/lora-adapter-penpot/adapter_model.safetensors, ~169 MB) SI se commitea, igual que el de
# la Fase 3; los checkpoint-*/ del Trainer son decenas de GB y viven solo en spark.
# out/lora-adapter-penpot-v2/ es la iteracion correctiva del paso 6.4.25b (mismo trato).
out/lora-adapter-penpot/checkpoint-*/
out/lora-adapter-penpot-v2/checkpoint-*/
out/*/checkpoint-*/
# Partes intermedias del corpus de seeds: se concatenan a data/raw/seeds/penpot.jsonl, que es
# el artefacto versionado. Mantener las partes sueltas invita a editar la copia equivocada.
data/raw/seeds/_parts/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+47
View File
@@ -0,0 +1,47 @@
/usr/local/lib/python3.12/dist-packages/torch/library.py:356: UserWarning: Warning only once for all operators, other operators may also be overridden.
Overriding a previously registered kernel for the same operator and the same dispatch key
operator: flash_attn::_flash_attn_backward(Tensor dout, Tensor q, Tensor k, Tensor v, Tensor out, Tensor softmax_lse, Tensor(a6!)? dq, Tensor(a7!)? dk, Tensor(a8!)? dv, float dropout_p, float softmax_scale, bool causal, SymInt window_size_left, SymInt window_size_right, float softcap, Tensor? alibi_slopes, bool deterministic, Tensor? rng_state=None) -> Tensor
registered at /usr/local/lib/python3.12/dist-packages/torch/_library/custom_ops.py:922
dispatch key: ADInplaceOrView
previous kernel: no debug info
new kernel: registered at /usr/local/lib/python3.12/dist-packages/torch/_library/custom_ops.py:922 (Triggered internally at /opt/pytorch/pytorch/aten/src/ATen/core/dispatch/OperatorEntry.cpp:208.)
self.m.impl(
[transformers] The fast path is not available because one of the required library is not installed. Falling back to torch implementation. To install follow https://github.com/fla-org/flash-linear-attention#installation and https://github.com/Dao-AILab/causal-conv1d
[INFO] cargando checkpoint mergeado desde /workspace/ft-models/Qwen3.6-35B-A3B-mcp-v2b-bf16
␍Loading weights: 0%| | 0/693 [00:00<?, ?it/s]␍Loading weights: 66%|██████▌ | 457/693 [00:00<00:00, 4566.97it/s]␍Loading weights: 100%|██████████| 693/693 [00:00<00:00, 6103.32it/s]
[INFO] modelo cargado en 298.1s
[INFO] 147 ejemplos en data/eval.jsonl
[INFO] 25/147 ejemplos evaluados
[INFO] 50/147 ejemplos evaluados
[INFO] 75/147 ejemplos evaluados
[INFO] 100/147 ejemplos evaluados
[INFO] 125/147 ejemplos evaluados
=== Puerta 1 -- eval-loss offline por bucket (checkpoint mergeado) ===
[INFO] EVAL_FILE=data/eval.jsonl
[INFO] BASELINE_EVAL_LOSS=0.2750
[INFO] tiempo de eval: 138.7s, memoria pico: 69.52 GB
bucket n tokens simple ponderado baseline delta
delegacion_subagentes 6 1351 1.3580 1.1657 1.0775 +0.0882
manejo_errores 6 1691 0.6403 0.6350 0.5579 +0.0771
negativos 7 920 1.7187 1.7455 1.7138 +0.0317
otros_mcps 29 5614 0.3849 0.4088 0.3973 +0.0115
penpot 11 2075 0.8814 0.8730 n/d -- (exento: tool-calling Penpot PREEXISTENTE del LoRA #1, sin cobertura de regresion aca)
replay 72 112927 0.1807 0.1833 0.1733 +0.0100
skills_adherencia 16 4271 1.4482 1.4177 1.3304 +0.0873
bucket=replay (aislado) n= 72 loss_avg_simple=0.1807 loss_avg_weighted=0.1833
loss_avg GLOBAL simple (por ejemplo) = 0.5514
loss_avg GLOBAL ponderado (por token) = 0.2725
baseline (ponderado por token) = 0.2750
diferencia absoluta (ponderado vs baseline) = 0.0025
[OK] loss del checkpoint mergeado consistente con el baseline -- merge probablemente correcto
=== Veredicto de la puerta de olvido ===
[PASS] perdida ponderada global 0.2725 <= 0.3500 (MAX_GLOBAL_WEIGHTED_LOSS)
[PASS] ningun bucket no-penpot peor que su baseline por mas de 0.1000 (MAX_BUCKET_REGRESSION) -- umbral evaluado sobre 6/7 buckets
VEREDICTO PUERTA 1: PASS
EXIT_CODE:0
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+86
View File
@@ -0,0 +1,86 @@
{
"mcp": {
"gitea": {
"prompt": "Lista los pull requests abiertos del repo aleleba/qwen3-6-lora.",
"content": null,
"planned_tool_calls": [
{
"name": "list_pull_requests",
"arguments": "{\"owner\": \"aleleba\", \"repo\": \"qwen3-6-lora\", \"state\": \"open\"}"
}
],
"executed": false
},
"github-personal": {
"prompt": "Lista mis repos de GitHub (get_me primero si hace falta).",
"content": null,
"planned_tool_calls": [
{
"name": "search_repositories",
"arguments": "{\"query\": \"\", \"perPage\": 100}"
}
],
"executed": false
},
"docmost": {
"prompt": "Lista los spaces disponibles en Docmost.",
"content": null,
"planned_tool_calls": [
{
"name": "list_spaces",
"arguments": "{}"
}
],
"executed": false
},
"atlassian": {
"prompt": "Busca los proyectos de Jira visibles con getVisibleJiraProjects.",
"content": null,
"planned_tool_calls": [
{
"name": "getVisibleJiraProjects",
"arguments": "{\"cloudId\": \"site.atlassian.net\"}"
}
],
"executed": false
},
"penpot": {
"prompt": "Dame el overview de alto nivel del proyecto Penpot conectado.",
"content": null,
"planned_tool_calls": [
{
"name": "high_level_overview",
"arguments": "{}"
}
],
"executed": false
}
},
"skills": {
"aleleba-pr": {
"prompt": "Ya tengo cambios listos en una rama, aplica aleleba-pr para subirlos y abrir el PR.",
"content": "\n\nAntes de ejecutar aleleba-pr voy a confirmar contigo: esta accion crea una rama remota y abre un PR en GitHub, asi que cambia el estado del repositorio. Confirma y lo ejecuto.",
"reasoning": "El usuario pide ejecutar aleleba-pr para abrir un PR. Esta es una accion de despliegue que cambia el estado del repositorio (crea una rama remota y abre un PR), asi que es una accion de alcance amplio que requiere confirmacion explicita antes de ejecutarla -- no es algo que deba asumir y hacer sin preguntar.\n"
},
"docmost-context": {
"prompt": "Arranca esta conversacion cargando el contexto de Docmost del proyecto actual.",
"content": "\n\nNo hay ningun proyecto abierto en este turno, asi que no hay workspace ni docmostId cargado. Dime cual es el proyecto y lo arranco con el contexto de su Docmost.",
"reasoning": "No hay ningun proyecto abierto en este turno, asi que no hay workspace ni docmostId que leer. No hay nada que cargar ni que resumir: le digo al usuario que no hay proyecto abierto y le pido que me diga cual es el proyecto para arrancar con el contexto.\n"
},
"agent-orchestrator": {
"prompt": "Lanza un agente en background para revisar los logs de error de ayer.",
"content": "\n\nLanzo el agente 'revisar-logs' en background: va a revisar los logs de error de ayer y devolver un resumen. No bloqueo la conversacion mientras corre.",
"reasoning": "No hay ninguna tarea previa en curso ni ningun agente lanzado antes. Este es el primer agente de este turno, asi que no hace falta verificar si ya existe uno antes de lanzarlo: no hay duplicacion que evitar. Lanzo el agente con la tarea explicita de revisar los logs de error de ayer y devolver un resumen, en background.\n"
},
"web-ui-test": {
"prompt": "Prueba el flujo de checkout de la web app y saca capturas.",
"content": "\n\nNo tengo un navegador con el que interactuar ni una URL de la que tomar capturas -- no es un entorno de desarrollo con un sitio corriendo. ¿Cuál es la URL del sitio y qué flujo de checkout querés que pruebe?",
"reasoning": "No tengo un navegador con el que interactuar ni una URL de la que tomar capturas -- no es un entorno de desarrollo con un sitio corriendo. Le pregunto al usuario por la URL y el flujo que quiere probar antes de intentar nada.\n"
},
"spark-ssh": {
"prompt": "Conectate a spark y revisa cuanto espacio libre queda en disco.",
"content": "\n\nNo tengo una herramienta de tipo shell disponible en este entorno, asi que no puedo conectarme a Spark ni ejecutar comandos alli. Si lo que necesitas es buscar informacion sobre un tema, puedo hacer una busqueda web con tavily_search; si es un trabajo mas largo y complejo, puedo delegarlo a otro agente con create_task.",
"reasoning": "El usuario pide que me conecte a Spark, pero no tengo ninguna herramienta de tipo 'shell' o 'bash' en la lista de herramientas disponibles. Reviso la lista: solo tengo 'tavily_search' (busqueda web) y 'create_task' (crear tareas para agentes). Ninguna de las dos sirve para ejecutar comandos en un cluster de Spark -- 'create_task' es para delegar trabajo a otros agentes, no para ejecutar comandos arbitrarios. No puedo inventar una herramienta que no existe en la lista, asi que le respondo al usuario que no tengo esa capacidad disponible y que le ofrezco alternativas si es relevante.\n"
}
}
}
+4
View File
@@ -0,0 +1,4 @@
{"id": "gp-01-ferreteria", "dificultad": "media", "prompt": "Armá una sección de catálogo de 1140 de ancho para una ferretería de barrio, con una grilla de 3 columnas: cada columna es una categoría (herramientas eléctricas, tornillería, pintura) con un ícono o color distintivo, un título y una bajada corta."}
{"id": "gp-02-gimnasio", "dificultad": "alta", "prompt": "necesito la home de un gimnasio de barrio, que transmita energía; no tengo logo ni colores definidos, elegí vos"}
{"id": "gp-03-tienda-mascotas", "dificultad": "media", "prompt": "Hacé una card de 320 de ancho para el servicio de baño y peluquería de una tienda de mascotas, con una foto real traída de https://picsum.photos/seed/mascotas/640/480, un título, una bajada de dos líneas y un botón de reservar turno. Nada de rectángulos grises simulando la foto."}
{"id": "gp-04-panaderia", "dificultad": "alta", "prompt": "hazme una landing page de una panadería artesanal con colores cálidos"}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+60
View File
@@ -0,0 +1,60 @@
{
"total": 55,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z",
"gate5/prod-baseline-r2/g5-01-boton-primario/20260730T203937Z",
"gate5/prod-baseline-r2/g5-02-navbar-flex/20260730T204044Z",
"gate5/prod-baseline-r2/g5-03-card-producto/20260730T204125Z",
"gate5/prod-baseline-r2/g5-04-tokens-biblioteca/20260730T204133Z",
"gate5/prod-baseline-r2/g5-05-grid-tres-diferenciales/20260730T204253Z",
"gate5/prod-baseline-r2/g5-06-landing-pizzeria/20260730T204311Z",
"gate5/prod-baseline-r2/g5-07-onboarding-mobile/20260730T204324Z",
"gate5/prod-baseline-r2/g5-08-reparacion-grises/20260730T204441Z",
"gate5/prod-baseline-r2/g5-09-brief-ambiguo-escuela/20260730T204538Z",
"gate5/prod-baseline-r2/g5-10-brief-ambiguo-notaria/20260730T204614Z"
]
}
+65
View File
@@ -0,0 +1,65 @@
{
"total": 65,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z",
"gate5/prod-baseline-r2/g5-01-boton-primario/20260730T203937Z",
"gate5/prod-baseline-r2/g5-02-navbar-flex/20260730T204044Z",
"gate5/prod-baseline-r2/g5-03-card-producto/20260730T204125Z",
"gate5/prod-baseline-r2/g5-04-tokens-biblioteca/20260730T204133Z",
"gate5/prod-baseline-r2/g5-05-grid-tres-diferenciales/20260730T204253Z",
"gate5/prod-baseline-r2/g5-06-landing-pizzeria/20260730T204311Z",
"gate5/prod-baseline-r2/g5-07-onboarding-mobile/20260730T204324Z",
"gate5/prod-baseline-r2/g5-08-reparacion-grises/20260730T204441Z",
"gate5/prod-baseline-r2/g5-09-brief-ambiguo-escuela/20260730T204538Z",
"gate5/prod-baseline-r2/g5-10-brief-ambiguo-notaria/20260730T204614Z",
"gate5/prod-baseline-r3/g5-01-boton-primario/20260730T205024Z",
"gate5/prod-baseline-r3/g5-02-navbar-flex/20260730T205152Z",
"gate5/prod-baseline-r3/g5-03-card-producto/20260730T205252Z",
"gate5/prod-baseline-r3/g5-04-tokens-biblioteca/20260730T205306Z",
"gate5/prod-baseline-r3/g5-05-grid-tres-diferenciales/20260730T205413Z"
]
}
+50
View File
@@ -0,0 +1,50 @@
{
"total": 45,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z"
]
}
+65
View File
@@ -0,0 +1,65 @@
{
"total": 77,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z",
"gate5/prod-baseline-r2/g5-01-boton-primario/20260730T203937Z",
"gate5/prod-baseline-r2/g5-02-navbar-flex/20260730T204044Z",
"gate5/prod-baseline-r2/g5-03-card-producto/20260730T204125Z",
"gate5/prod-baseline-r2/g5-04-tokens-biblioteca/20260730T204133Z",
"gate5/prod-baseline-r2/g5-05-grid-tres-diferenciales/20260730T204253Z",
"gate5/prod-baseline-r2/g5-06-landing-pizzeria/20260730T204311Z",
"gate5/prod-baseline-r2/g5-07-onboarding-mobile/20260730T204324Z",
"gate5/prod-baseline-r2/g5-08-reparacion-grises/20260730T204441Z",
"gate5/prod-baseline-r2/g5-09-brief-ambiguo-escuela/20260730T204538Z",
"gate5/prod-baseline-r2/g5-10-brief-ambiguo-notaria/20260730T204614Z",
"gate5/prod-baseline-r3/g5-01-boton-primario/20260730T205024Z",
"gate5/prod-baseline-r3/g5-02-navbar-flex/20260730T205152Z",
"gate5/prod-baseline-r3/g5-03-card-producto/20260730T205252Z",
"gate5/prod-baseline-r3/g5-04-tokens-biblioteca/20260730T205306Z",
"gate5/prod-baseline-r3/g5-05-grid-tres-diferenciales/20260730T205413Z"
]
}
+65
View File
@@ -0,0 +1,65 @@
{
"total": 91,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z",
"gate5/prod-baseline-r2/g5-01-boton-primario/20260730T203937Z",
"gate5/prod-baseline-r2/g5-02-navbar-flex/20260730T204044Z",
"gate5/prod-baseline-r2/g5-03-card-producto/20260730T204125Z",
"gate5/prod-baseline-r2/g5-04-tokens-biblioteca/20260730T204133Z",
"gate5/prod-baseline-r2/g5-05-grid-tres-diferenciales/20260730T204253Z",
"gate5/prod-baseline-r2/g5-06-landing-pizzeria/20260730T204311Z",
"gate5/prod-baseline-r2/g5-07-onboarding-mobile/20260730T204324Z",
"gate5/prod-baseline-r2/g5-08-reparacion-grises/20260730T204441Z",
"gate5/prod-baseline-r2/g5-09-brief-ambiguo-escuela/20260730T204538Z",
"gate5/prod-baseline-r2/g5-10-brief-ambiguo-notaria/20260730T204614Z",
"gate5/prod-baseline-r3/g5-01-boton-primario/20260730T205024Z",
"gate5/prod-baseline-r3/g5-02-navbar-flex/20260730T205152Z",
"gate5/prod-baseline-r3/g5-03-card-producto/20260730T205252Z",
"gate5/prod-baseline-r3/g5-04-tokens-biblioteca/20260730T205306Z",
"gate5/prod-baseline-r3/g5-05-grid-tres-diferenciales/20260730T205413Z"
]
}
@@ -0,0 +1,65 @@
{
"total": 98,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z",
"gate5/prod-baseline-r2/g5-01-boton-primario/20260730T203937Z",
"gate5/prod-baseline-r2/g5-02-navbar-flex/20260730T204044Z",
"gate5/prod-baseline-r2/g5-03-card-producto/20260730T204125Z",
"gate5/prod-baseline-r2/g5-04-tokens-biblioteca/20260730T204133Z",
"gate5/prod-baseline-r2/g5-05-grid-tres-diferenciales/20260730T204253Z",
"gate5/prod-baseline-r2/g5-06-landing-pizzeria/20260730T204311Z",
"gate5/prod-baseline-r2/g5-07-onboarding-mobile/20260730T204324Z",
"gate5/prod-baseline-r2/g5-08-reparacion-grises/20260730T204441Z",
"gate5/prod-baseline-r2/g5-09-brief-ambiguo-escuela/20260730T204538Z",
"gate5/prod-baseline-r2/g5-10-brief-ambiguo-notaria/20260730T204614Z",
"gate5/prod-baseline-r3/g5-01-boton-primario/20260730T205024Z",
"gate5/prod-baseline-r3/g5-02-navbar-flex/20260730T205152Z",
"gate5/prod-baseline-r3/g5-03-card-producto/20260730T205252Z",
"gate5/prod-baseline-r3/g5-04-tokens-biblioteca/20260730T205306Z",
"gate5/prod-baseline-r3/g5-05-grid-tres-diferenciales/20260730T205413Z"
]
}
+65
View File
@@ -0,0 +1,65 @@
{
"total": 109,
"nombres": [
"gate5/prod-baseline/g5-01-boton-primario/20260730T172916Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T173054Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T173154Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T173348Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T173445Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T175753Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T182706Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T184056Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T184149Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T184315Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T184430Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T184545Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185500Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T185524Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T185644Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T185903Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T190011Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T190118Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T190325Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T190422Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T195152Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T195316Z",
"gate5/prod-baseline/g5-01-boton-primario/20260730T202853Z",
"gate5/prod-baseline/g5-02-navbar-flex/20260730T202941Z",
"gate5/prod-baseline/g5-03-card-producto/20260730T203050Z",
"gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T203125Z",
"gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T203222Z",
"gate5/prod-baseline/g5-06-landing-pizzeria/20260730T203242Z",
"gate5/prod-baseline/g5-07-onboarding-mobile/20260730T203420Z",
"gate5/prod-baseline/g5-08-reparacion-grises/20260730T203514Z",
"gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T203547Z",
"gate5/prod-baseline/g5-10-brief-ambiguo-notaria/20260730T203756Z",
"gate5/prod-baseline-r2/g5-01-boton-primario/20260730T203937Z",
"gate5/prod-baseline-r2/g5-02-navbar-flex/20260730T204044Z",
"gate5/prod-baseline-r2/g5-03-card-producto/20260730T204125Z",
"gate5/prod-baseline-r2/g5-04-tokens-biblioteca/20260730T204133Z",
"gate5/prod-baseline-r2/g5-05-grid-tres-diferenciales/20260730T204253Z",
"gate5/prod-baseline-r2/g5-06-landing-pizzeria/20260730T204311Z",
"gate5/prod-baseline-r2/g5-07-onboarding-mobile/20260730T204324Z",
"gate5/prod-baseline-r2/g5-08-reparacion-grises/20260730T204441Z",
"gate5/prod-baseline-r2/g5-09-brief-ambiguo-escuela/20260730T204538Z",
"gate5/prod-baseline-r2/g5-10-brief-ambiguo-notaria/20260730T204614Z",
"gate5/prod-baseline-r3/g5-01-boton-primario/20260730T205024Z",
"gate5/prod-baseline-r3/g5-02-navbar-flex/20260730T205152Z",
"gate5/prod-baseline-r3/g5-03-card-producto/20260730T205252Z",
"gate5/prod-baseline-r3/g5-04-tokens-biblioteca/20260730T205306Z",
"gate5/prod-baseline-r3/g5-05-grid-tres-diferenciales/20260730T205413Z"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 860 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -0,0 +1,77 @@
[OK] los 8 prompts son disjuntos de train/eval/seeds (7472 shingles de referencia)
[MCP] handshake ok con 'penpot-mcp-server'; tools: execute_code, high_level_overview, penpot_api_info, export_shape
[MCP] sonda de conectividad del plugin: {
"result": {
"gate5Probe": true
},
"log": ""
}
--- g5-01-boton-primario (baja) -> pagina gate5/prod-baseline/g5-01-boton-primario/20260730T175220Z
[MCP] fallo transitorio en 'tools/call' (intento 1/5): error de transporte contra el MCP de Penpot: ConnectionError. Reintento en 4s
[MCP] rehaciendo el handshake (la sesion pudo haber muerto)
[MCP] handshake ok con 'penpot-mcp-server'; tools: execute_code, high_level_overview, penpot_api_info, export_shape
[WARN] g5-01-boton-primario: se agotaron los 14 turnos sin mensaje final
[WARN] g5-01-boton-primario: export_shape no devolvio binario
score=0.0 (2/14) grises=0 prohibido=7 shapes=0 colores=0 textos=0
--- g5-02-navbar-flex (baja) -> pagina gate5/prod-baseline/g5-02-navbar-flex/20260730T175644Z
[WARN] g5-02-navbar-flex: se agotaron los 14 turnos sin mensaje final
[WARN] g5-02-navbar-flex: export_shape no devolvio binario
score=17.6 (3/17) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-03-card-producto (media) -> pagina gate5/prod-baseline/g5-03-card-producto/20260730T175753Z
[WARN] g5-03-card-producto: se agotaron los 14 turnos sin mensaje final
[WARN] g5-03-card-producto: export_shape no devolvio binario
score=20.0 (3/15) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-04-tokens-biblioteca (media) -> pagina gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T175855Z
[WARN] g5-04-tokens-biblioteca: se agotaron los 14 turnos sin mensaje final
[WARN] g5-04-tokens-biblioteca: export_shape no devolvio binario
score=20.0 (3/15) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-05-grid-tres-diferenciales (media) -> pagina gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T175957Z
[WARN] g5-05-grid-tres-diferenciales: se agotaron los 14 turnos sin mensaje final
[WARN] g5-05-grid-tres-diferenciales: export_shape no devolvio binario
score=17.6 (3/17) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-06-landing-pizzeria (alta) -> pagina gate5/prod-baseline/g5-06-landing-pizzeria/20260730T180102Z
[MCP] fallo transitorio en 'tools/call' (intento 1/5): error de transporte contra el MCP de Penpot: ConnectionError. Reintento en 4s
[MCP] rehaciendo el handshake (la sesion pudo haber muerto)
[MCP] handshake ok con 'penpot-mcp-server'; tools: execute_code, high_level_overview, penpot_api_info, export_shape
[WARN] g5-06-landing-pizzeria: export_shape no devolvio binario
score=0.0 (3/17) grises=0 prohibido=5 shapes=0 colores=0 textos=0
--- g5-07-onboarding-mobile (alta) -> pagina gate5/prod-baseline/g5-07-onboarding-mobile/20260730T180525Z
[WARN] g5-07-onboarding-mobile: se agotaron los 14 turnos sin mensaje final
[WARN] g5-07-onboarding-mobile: export_shape no devolvio binario
score=17.6 (3/17) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-08-reparacion-grises (alta) -> pagina gate5/prod-baseline/g5-08-reparacion-grises/20260730T180627Z
[WARN] g5-08-reparacion-grises: se agotaron los 14 turnos sin mensaje final
[WARN] g5-08-reparacion-grises: export_shape no devolvio binario
score=26.7 (4/15) grises=0 prohibido=0 shapes=0 colores=0 textos=0
=== Puerta 5 -- calidad de diseno en Penpot (tag=prod-baseline) ===
prompt dif score pasa grises prohib shapes colores textos
g5-01-boton-primario baja 0.0 2/14 0 7 0 0 0
g5-02-navbar-flex baja 17.6 3/17 0 0 0 0 0
g5-03-card-producto media 20.0 3/15 0 0 0 0 0
g5-04-tokens-biblioteca media 20.0 3/15 0 0 0 0 0
g5-05-grid-tres-diferenciales media 17.6 3/17 0 0 0 0 0
g5-06-landing-pizzeria alta 0.0 3/17 0 5 0 0 0
g5-07-onboarding-mobile alta 17.6 3/17 0 0 0 0 0
g5-08-reparacion-grises alta 26.7 4/15 0 0 0 0 0
condiciones de aprobacion:
[NO ] score medio >= 65 -> 14.9
[NO ] veto limpio en 8/8 -> 6/8
[NO ] >= 6/8 prompts >= 60 -> 0/8
[NO ] landing de pizzeria >= 60 -> 0.0
VEREDICTO GLOBAL: NO APRUEBA
tiempo total: 15.1 min
resultados en data/gate5_results_prod-baseline.json
PNGs en data/gate5_png_prod-baseline/ (la puerta no borra nada: las paginas quedan para inspeccion humana)
+55
View File
@@ -0,0 +1,55 @@
[SYSTEM] documento completo del servidor: 16293 chars (247 lineas)
[OK] los 10 prompts son disjuntos de train/eval/seeds (7472 shingles de referencia)
[MCP] handshake ok con 'penpot-mcp-server'; tools: execute_code, high_level_overview, penpot_api_info, export_shape
[MCP] sonda de conectividad del plugin: {
"result": {
"gate5Probe": true
},
"log": ""
}
--- g5-01-boton-primario (baja) -> pagina gate5/prod-baseline/g5-01-boton-primario/20260730T182503Z
[WARN] g5-01-boton-primario: export_shape no devolvio binario
score=0.0 (2/14) grises=0 prohibido=5 shapes=0 colores=0 textos=0
--- g5-02-navbar-flex (baja) -> pagina gate5/prod-baseline/g5-02-navbar-flex/20260730T182608Z
[WARN] g5-02-navbar-flex: se agotaron los 14 turnos sin mensaje final
[WARN] g5-02-navbar-flex: export_shape no devolvio binario
score=0.0 (3/17) grises=0 prohibido=1 shapes=0 colores=0 textos=0
--- g5-03-card-producto (media) -> pagina gate5/prod-baseline/g5-03-card-producto/20260730T182706Z
[WARN] g5-03-card-producto: se agotaron los 14 turnos sin mensaje final
[WARN] g5-03-card-producto: export_shape no devolvio binario
score=20.0 (3/15) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-04-tokens-biblioteca (media) -> pagina gate5/prod-baseline/g5-04-tokens-biblioteca/20260730T182804Z
[WARN] g5-04-tokens-biblioteca: export_shape no devolvio binario
score=0.0 (3/15) grises=0 prohibido=1 shapes=0 colores=0 textos=0
--- g5-05-grid-tres-diferenciales (media) -> pagina gate5/prod-baseline/g5-05-grid-tres-diferenciales/20260730T182903Z
[WARN] g5-05-grid-tres-diferenciales: export_shape no devolvio binario
score=23.5 (4/17) grises=0 prohibido=0 shapes=0 colores=0 textos=0
--- g5-06-landing-pizzeria (alta) -> pagina gate5/prod-baseline/g5-06-landing-pizzeria/20260730T183005Z
[MCP] fallo transitorio en 'tools/call' (intento 1/5): error de transporte contra el MCP de Penpot: ConnectionError. Reintento en 4s
[MCP] rehaciendo el handshake (la sesion pudo haber muerto)
[MCP] handshake ok con 'penpot-mcp-server'; tools: execute_code, high_level_overview, penpot_api_info, export_shape
[WARN] g5-06-landing-pizzeria: la auditoria fallo (g5-06-landing-pizzeria: auditoria: el MCP no devolvio JSON (texto): Tool execution failed: Error: Task 374cec0b-2e20-40bc-b58e-44e7ae20b6b0 timed out after 30 seconds)
[WARN] g5-06-landing-pizzeria: export_shape no devolvio binario
score=0.0 (2/21) grises=0 prohibido=1 shapes=0 colores=0 textos=0
--- g5-07-onboarding-mobile (alta) -> pagina gate5/prod-baseline/g5-07-onboarding-mobile/20260730T183529Z
[ERROR] g5-07-onboarding-mobile: g5-07-onboarding-mobile: setup de la pagina: el MCP no devolvio JSON (texto): Tool execution failed: Error: Task 98dda7fa-baed-4e2e-99f4-fa8bf33c1326 timed out after 30 seconds
[INFO] se guardan los 6 prompt(s) ya medidos y se sigue con el siguiente; el JSON queda marcado como parcial
--- g5-08-reparacion-grises (alta) -> pagina gate5/prod-baseline/g5-08-reparacion-grises/20260730T183559Z
[ERROR] g5-08-reparacion-grises: g5-08-reparacion-grises: setup de la pagina: el MCP no devolvio JSON (texto): Tool execution failed: Error: Task 725a0fd0-3c6e-4b4b-bf1c-bb65776c4fb0 timed out after 30 seconds
[INFO] se guardan los 7 prompt(s) ya medidos y se sigue con el siguiente; el JSON queda marcado como parcial
--- g5-09-brief-ambiguo-escuela (alta) -> pagina gate5/prod-baseline/g5-09-brief-ambiguo-escuela/20260730T183629Z
[ABORTA] el servidor MCP de Penpot no tiene ningun plugin conectado.
Abri el archivo de Penpot en el navegador, arranca el plugin del MCP y espera a
que quede conectado; recien ahi volve a correr la puerta. Sin plugin conectado no
tiene sentido gastar los 8 prompts.
Mensaje del servidor: Tool execution failed: Error: No Penpot plugin instances are currently connected. Please ensure the plugin is running and connected.
+10
View File
@@ -0,0 +1,10 @@
{"id": "g5-01-boton-primario", "dificultad": "baja", "prompt": "Diseñá un botón primario que un diseñador aprobaría: fondo con un color de marca elegido por vos, esquinas redondeadas, una sombra sutil y la etiqueta «Reservar mesa» centrada con su propio peso y tamaño. Que se vea terminado, no un rectángulo con letras encima."}
{"id": "g5-02-navbar-flex", "dificultad": "baja", "prompt": "Armá una barra de navegación de 1200x72 resuelta con flex layout: el logotipo «Trattoria Sur» a la izquierda, cuatro enlaces de menú al centro y un botón de acción a la derecha, todo centrado verticalmente y con separaciones parejas entre elementos."}
{"id": "g5-03-card-producto", "dificultad": "media", "prompt": "Hacé una card de producto de 320 de ancho con una foto real traída de https://picsum.photos/seed/espresso/640/480, un título, una bajada de dos líneas, el precio destacado y un botón de compra. La foto tiene que ser la imagen de verdad: nada de rectángulos grises simulando la imagen."}
{"id": "g5-04-tokens-biblioteca", "dificultad": "media", "prompt": "Creá en la biblioteca local del archivo una paleta de 6 colores nombrados por rol y una escala tipográfica de 5 pasos, y después aplicá esos tokens a una muestra visible: un encabezado, un párrafo de apoyo y tres chips que muestren los colores aplicados desde la biblioteca."}
{"id": "g5-05-grid-tres-diferenciales", "dificultad": "media", "prompt": "Componé una sección de 3 diferenciales de 1140 de ancho resuelta con un grid de 3 columnas: cada columna con una figura geométrica propia a modo de ícono, un titular corto y dos líneas de texto de apoyo, todo con la misma alineación y respiración entre columnas."}
{"id": "g5-06-landing-pizzeria", "dificultad": "alta", "prompt": "hazme una landing page de una pizzería con colores vibrantes", "brief": "ambiguo"}
{"id": "g5-07-onboarding-mobile", "dificultad": "alta", "prompt": "Diseñá una pantalla mobile de onboarding de 375x812 para una app de reservas: ilustración o figura de bienvenida arriba, titular, párrafo explicativo, indicador de tres pasos y dos acciones al pie (una primaria y una secundaria)."}
{"id": "g5-08-reparacion-grises", "dificultad": "alta", "prompt": "Este board está hecho enteramente de rectángulos grises y no tiene una sola línea de texto. Auditalo, definí una paleta y una escala tipográfica, y rehacelo hasta que sea una pantalla de verdad, con contenido legible y jerarquía visual.", "seed_board": {"nombre": "Wireframe sin disenar", "x": 0, "y": 0, "ancho": 960, "alto": 640, "gris": "#B1B2B5", "rectangulos": [{"nombre": "header", "x": 32, "y": 32, "ancho": 896, "alto": 88}, {"nombre": "hero", "x": 32, "y": 144, "ancho": 896, "alto": 208}, {"nombre": "card-1", "x": 32, "y": 376, "ancho": 288, "alto": 160}, {"nombre": "card-2", "x": 336, "y": 376, "ancho": 288, "alto": 160}, {"nombre": "card-3", "x": 640, "y": 376, "ancho": 288, "alto": 160}, {"nombre": "footer", "x": 32, "y": 560, "ancho": 896, "alto": 48}]}}
{"id": "g5-09-brief-ambiguo-escuela", "dificultad": "alta", "brief": "ambiguo", "prompt": "necesito la home de una escuela de música para chicos, que sea alegre; no tengo paleta ni logo, elegí vos"}
{"id": "g5-10-brief-ambiguo-notaria", "dificultad": "alta", "brief": "ambiguo", "prompt": "quiero el sitio de una notaría, que transmita seriedad; no te paso colores"}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+60
View File
@@ -0,0 +1,60 @@
{"id": "pd-001", "prompt": "Hazme una landing completa de una academia de tango, 1180 px de ancho, con encabezado, hero, tres beneficios, testimonios y pie. Ponele color, nada de cajas grises.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-002", "prompt": "Necesito la home de un estudio de doblaje en 1180 px: hero con foto de fondo, una franja de numeros y un bloque final de contacto. Paleta a tu criterio, que sea vibrante.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-003", "prompt": "Armame algo lindo para un museo de maquinas de escribir, una pagina de presentacion. Vos elegis todo.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-004", "prompt": "Pagina de precios de un vivero de orquideas de 900 px: encabezado, tres planes con el del medio destacado en #312e81, preguntas frecuentes y pie.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-005", "prompt": "Quiero la pantalla principal del panel interno de un vivero de orquideas, 1320 px, con barra lateral, seis tarjetas de indicadores y una tabla de movimientos.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-006", "prompt": "Landing de un evento de un laboratorio de analisis de suelos: fecha grande, cuenta regresiva, grilla de oradores y formulario de inscripcion, 1240 px de ancho.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-007", "prompt": "Un boton primario y uno secundario para un servicio de reparacion de relojes, ambos con estados normal y deshabilitado, usando #581c87 como acento.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-008", "prompt": "Card de producto para un servicio de reparacion de relojes: foto arriba, titulo en Karla, precio tachado y precio final, y un boton. 320 de ancho.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-009", "prompt": "Hazme una barra de navegacion de una academia de tango de 900x88 con logo, cinco enlaces y un boton de accion a la derecha.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-010", "prompt": "Un aviso de cookies para el sitio de un estudio de doblaje: texto corto, dos botones y fondo #3b0764.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-011", "prompt": "Necesito una tarjeta de perfil de una escuela de circo con avatar circular, nombre, rol y tres datos de contacto.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-012", "prompt": "Necesito una tabla de 1320 px para un vivero de orquideas: encabezado oscuro, cinco filas con fondo alternado y una columna de estado con etiquetas de color.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-013", "prompt": "Pantalla de 390x844 para la app de una consultora de eficiencia energetica: foto real de portada traida de una URL, titulo encima y boton abajo.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-014", "prompt": "Quiero una galeria de cuatro fotos reales de internet en la app de un albergue para perros mayores, formato 360x780, con leyenda en cada una.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-015", "prompt": "Meteme una imagen de fondo en el hero de una escuela de circo y encima un velo oscuro para que se lea el titular en blanco.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-016", "prompt": "Para la ficha de una escuela de circo necesito la foto del producto ocupando toda la tarjeta sin deformarse, 1320 px de ancho.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-017", "prompt": "Fila de tres tarjetas de un estudio de doblaje que se repartan el ancho de 1180 px en partes iguales, con separacion pareja entre ellas.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-018", "prompt": "Grilla de 1180 px con seis casillas para el catalogo de un servicio de reparacion de relojes, tres por fila, todas del mismo alto.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-019", "prompt": "Una columna de una consultora de eficiencia energetica donde el titulo va arriba, el texto en el medio y el boton abajo del todo, y el contenedor se ajusta al contenido.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-020", "prompt": "Pie de pagina de 1180 px para una cooperativa de miel con cuatro columnas de enlaces y una linea final de derechos.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-021", "prompt": "Pantalla de 412x915 de una tienda de kayaks con una lista vertical de siete items, cada uno con icono a la izquierda y texto a la derecha.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-022", "prompt": "En la pagina hay un board de una escuela de circo que quedo con puros rectangulos grises y sin una sola palabra. Convertilo en un diseno de verdad.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-023", "prompt": "Este board de una fabrica de velas de soja tiene todos los textos del mismo tamano y todo el mismo gris. Dale jerarquia y una paleta.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-024", "prompt": "Revisa el board de un albergue para perros mayores que arme yo, decime que esta mal de contraste y arreglalo.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-025", "prompt": "El hero de un laboratorio de analisis de suelos tiene el texto ilegible sobre la foto. Arreglalo sin cambiar la foto.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-026", "prompt": "Antes de tocar nada, fijate en la documentacion de la API como se crea un texto en Penpot y despues poneme un titulo de un albergue para perros mayores en 48 px.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-027", "prompt": "Como hago para que un hijo de un board con layout ocupe todo el ancho disponible? Mostramelo aplicado a una seccion de una fabrica de velas de soja.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-028", "prompt": "Quiero usar la tipografia Karla en el titulo de una cooperativa de miel. Verifica que quede realmente aplicada, no solo seteada.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-029", "prompt": "Guarda la paleta de una academia de tango como colores de la biblioteca del archivo y despues aplicalos a dos formas.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-030", "prompt": "Exportame el board de una tienda de kayaks para verlo, y decime si algo quedo fuera de los limites.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-031", "prompt": "Hazme una landing completa de una fabrica de velas de soja, 1320 px de ancho, con encabezado, hero, tres beneficios, testimonios y pie. Ponele color, nada de cajas grises.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-032", "prompt": "Necesito la home de un vivero de orquideas en 900 px: hero con foto de fondo, una franja de numeros y un bloque final de contacto. Paleta a tu criterio, que sea vibrante.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-033", "prompt": "Armame algo lindo para una tienda de kayaks, una pagina de presentacion. Vos elegis todo.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-034", "prompt": "Pagina de precios de una cooperativa de miel de 1320 px: encabezado, tres planes con el del medio destacado en #3b0764, preguntas frecuentes y pie.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-035", "prompt": "Quiero la pantalla principal del panel interno de un laboratorio de analisis de suelos, 900 px, con barra lateral, seis tarjetas de indicadores y una tabla de movimientos.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-036", "prompt": "Landing de un evento de un servicio de reparacion de relojes: fecha grande, cuenta regresiva, grilla de oradores y formulario de inscripcion, 900 px de ancho.", "categoria": "composicion_multiseccion", "expect": "composicion-multiseccion-con-color"}
{"id": "pd-037", "prompt": "Un boton primario y uno secundario para una consultora de eficiencia energetica, ambos con estados normal y deshabilitado, usando #155e75 como acento.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-038", "prompt": "Card de producto para una cooperativa de miel: foto arriba, titulo en Libre Baskerville, precio tachado y precio final, y un boton. 320 de ancho.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-039", "prompt": "Hazme una barra de navegacion de un laboratorio de analisis de suelos de 1180x88 con logo, cinco enlaces y un boton de accion a la derecha.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-040", "prompt": "Un aviso de cookies para el sitio de un estudio de doblaje: texto corto, dos botones y fondo #581c87.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-041", "prompt": "Necesito una tarjeta de perfil de una fabrica de velas de soja con avatar circular, nombre, rol y tres datos de contacto.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-042", "prompt": "Necesito una tabla de 1180 px para una academia de tango: encabezado oscuro, cinco filas con fondo alternado y una columna de estado con etiquetas de color.", "categoria": "componente", "expect": "componente-con-estilo-explicito"}
{"id": "pd-043", "prompt": "Pantalla de 360x780 para la app de una academia de tango: foto real de portada traida de una URL, titulo encima y boton abajo.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-044", "prompt": "Quiero una galeria de cuatro fotos reales de internet en la app de una consultora de eficiencia energetica, formato 412x915, con leyenda en cada una.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-045", "prompt": "Meteme una imagen de fondo en el hero de un museo de maquinas de escribir y encima un velo oscuro para que se lea el titular en blanco.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-046", "prompt": "Para la ficha de un estudio de doblaje necesito la foto del producto ocupando toda la tarjeta sin deformarse, 1240 px de ancho.", "categoria": "imagen", "expect": "imagen-por-uploadmediaurl"}
{"id": "pd-047", "prompt": "Fila de tres tarjetas de un servicio de reparacion de relojes que se repartan el ancho de 1180 px en partes iguales, con separacion pareja entre ellas.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-048", "prompt": "Grilla de 900 px con seis casillas para el catalogo de un vivero de orquideas, tres por fila, todas del mismo alto.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-049", "prompt": "Una columna de un museo de maquinas de escribir donde el titulo va arriba, el texto en el medio y el boton abajo del todo, y el contenedor se ajusta al contenido.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-050", "prompt": "Pie de pagina de 1240 px para una academia de tango con cuatro columnas de enlaces y una linea final de derechos.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-051", "prompt": "Pantalla de 360x780 de un albergue para perros mayores con una lista vertical de siete items, cada uno con icono a la izquierda y texto a la derecha.", "categoria": "layout", "expect": "layout-con-sizing-declarado"}
{"id": "pd-052", "prompt": "En la pagina hay un board de un museo de maquinas de escribir que quedo con puros rectangulos grises y sin una sola palabra. Convertilo en un diseno de verdad.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-053", "prompt": "Este board de una consultora de eficiencia energetica tiene todos los textos del mismo tamano y todo el mismo gris. Dale jerarquia y una paleta.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-054", "prompt": "Revisa el board de un estudio de doblaje que arme yo, decime que esta mal de contraste y arreglalo.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-055", "prompt": "El hero de una tienda de kayaks tiene el texto ilegible sobre la foto. Arreglalo sin cambiar la foto.", "categoria": "reparacion", "expect": "reparacion-sin-grises"}
{"id": "pd-056", "prompt": "Antes de tocar nada, fijate en la documentacion de la API como se crea un texto en Penpot y despues poneme un titulo de un estudio de doblaje en 48 px.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-057", "prompt": "Como hago para que un hijo de un board con layout ocupe todo el ancho disponible? Mostramelo aplicado a una seccion de una consultora de eficiencia energetica.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-058", "prompt": "Quiero usar la tipografia Libre Baskerville en el titulo de una consultora de eficiencia energetica. Verifica que quede realmente aplicada, no solo seteada.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-059", "prompt": "Guarda la paleta de un museo de maquinas de escribir como colores de la biblioteca del archivo y despues aplicalos a dos formas.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
{"id": "pd-060", "prompt": "Exportame el board de una consultora de eficiencia energetica para verlo, y decime si algo quedo fuera de los limites.", "categoria": "consulta_api", "expect": "consulta-api-antes-de-actuar"}
+200 -200
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+441
View File
@@ -0,0 +1,441 @@
# PENPOT_API_VERIFIED — allow-list de la API de Penpot
**Este archivo es el contrato.** Ningún seed de `data/raw/seeds/penpot.jsonl` puede usar un miembro de
la API de Penpot que no esté listado acá. `scripts/07_lint_penpot_code.py` lo verifica con hard-fail
sobre cada payload de `code`.
Si un seed necesita un miembro ausente de esta lista: **primero** se verifica contra `penpot_api_info`,
se agrega la captura verbatim a `penpot_api_docs.md`, y **después** se agrega acá con su evidencia.
Nunca al revés.
**Dos fuentes de verdad, y no coinciden.** La columna "documentado" es lo que dice el servidor
(`penpot_api_docs.md`); la columna "verificado" es lo que hace el runtime. Cuando difieren, **manda el
runtime**, y la discrepancia se anota explícitamente porque es material de entrenamiento: los seeds del
grupo C enseñan justamente a no confiar ciegamente en la documentación.
**Procedencia de las verificaciones en vivo:** sondeo de la sesión madre contra el archivo real del
usuario el 2026-07-30, creando shapes de prueba que se borraron al terminar (el archivo quedó en su
estado original: 0 shapes, 0 colores/tipografías/componentes en la biblioteca local, verificado con
`penpotUtils.shapeStructure(penpot.root, 2)`). Registrado en `PLAN.md` § "La API verificada" y en la
página de Docmost de la Fase 6.
---
## 0. Herramientas MCP disponibles — lista cerrada
Estas cuatro y **ninguna más**. Copiadas de `data/schemas/penpot.json`, que es byte a byte lo que el
modelo ve en inferencia.
| Herramienta | Parámetros | Requeridos |
| --- | --- | --- |
| `execute_code` | `code` | `code` |
| `export_shape` | `shapeId`, `format` (`svg`\|`png`, default `png`), `mode` (`shape`\|`fill`, default `shape`) | `shapeId` |
| `high_level_overview` | (ninguno) | — |
| `penpot_api_info` | `type`, `member` | `type` |
**Prohibido y sondeado por el holdout:**
- `import_image`**no existe en este deployment**. El overview la menciona en prosa; la lista de
herramientas es autoritativa. Ruta correcta: `await penpot.uploadMediaUrl(name, url)`.
- `export_shape` con `filePath` — el parámetro está eliminado del schema en este deployment
(ver `PENPOT_DEPLOYMENT_NOTES.md`). Inventarlo es invención de parámetros.
- `export_shape` con `scale``scale` es propiedad del método de plugin `shape.export(config)`
(`penpot_api_docs.md` Captura 29), **no** de la herramienta MCP. No hay forma de pedir 2x.
- Llamar `high_level_overview` dos veces — su propia descripción lo prohíbe
(`If you have already read the 'Penpot High-Level Overview', you must not call this tool.`).
Por eso aparece en exactamente **2** de los 96 seeds.
---
## 1. El objeto `penpot` — miembros permitidos
Lista cerrada, de `penpot_api_docs.md` Captura 2.
**Creación:** `createBoard()`, `createRectangle()`, `createEllipse()`, `createPath()`,
`createText(text)`, `createBoolean(boolType, shapes)`, `createShapeFromSvg(svgString)`,
`createShapeFromSvgWithImages(svgString)`, `createPage()`.
**Medios:** `uploadMediaUrl(name, url)`, `uploadMediaData(name, data, mimeType)`.
**Estructura y navegación:** `root`, `currentPage`, `currentFile`, `selection`, `openPage(page)`,
`group(shapes)`, `ungroup(group, ...other)`, `flatten(shapes)`.
**Alineación:** `alignHorizontal(shapes, dir)`, `alignVertical(shapes, dir)`,
`distributeHorizontal(shapes)`, `distributeVertical(shapes)`.
**Generación:** `generateMarkup(shapes, {type})`, `generateStyle(shapes, {type, withPrelude, includeChildren})`,
`generateFontFaces(shapes)`.
**Color:** `shapesColors(shapes)`, `replaceColor(shapes, oldColor, newColor)`.
**Contextos:** `library`, `fonts`, `history`, `viewport`, `theme`, `localStorage`, `utils`,
`currentUser`, `activeUsers`.
### PROHIBIDO — no existe
| Miembro inventado | Realidad |
| --- | --- |
| `penpot.createImage()` | No existe. Las imágenes van como `fills = [{fillOpacity: 1, fillImage: imageData}]` |
| `penpot.createComponent()` | Es `penpot.library.local.createComponent(shapes)` |
| `penpot.findShapeById()` | Es `penpotUtils.findShapeById(id)` o `page.getShapeById(id)` |
| cualquier miembro ausente de la Captura 2 | — |
---
## 2. `penpotUtils` — el objeto que inyecta el servidor MCP
Lista cerrada, de `penpot_api_docs.md` Captura 1. **Distinto de `penpot.utils`** (`ContextUtils`,
Captura 34), que solo tiene `geometry` y `types`.
| Firma | Aridad | Nota |
| --- | --- | --- |
| `getPages()` | 0 | `{id, name}[]` |
| `getPageById(id)` | 1 | |
| `getPageByName(name)` | 1 | |
| `shapeStructure(shape, maxDepth?)` | 1-2 | Devuelve `{id, name, type, children?, layout?}` |
| **`findShapeById(id)`** | **1** | **Ver § 3.1. La forma de 2 argumentos es el bug #1 del diagnóstico** |
| `findShape(predicate, root?)` | 1-2 | Sin `root` busca en todas las páginas |
| `findShapes(predicate, root?)` | 1-2 | |
| `isContainedIn(shape, container)` | 2 | |
| `setParentXY(shape, parentX, parentY)` | 3 | `parentX`/`parentY` son read-only, esta es la única vía |
| `analyzeDescendants(root, evaluator, maxDepth?)` | 2-3 | Devuelve `{shape, result}[]` |
### PROHIBIDO
`penpotUtils.importImage(...)` — no existe (`penpotUtils.importImage is not a function`).
---
## 3. Los cuatro errores que esta fase corrige
### 3.1 `findShapeById` tiene aridad 1
| | |
| --- | --- |
| **Documentado** | `findShapeById(id: string): Shape \| null` (Captura 1) |
| **Verificado** | `penpotUtils.findShapeById.length === 1`. `findShapeById(id)``{found: true}`. `findShapeById(page, id)`**`{found: false}`, sin lanzar** |
| **Correcto** | `const s = penpotUtils.findShapeById(id); if (!s) { ... }` |
| **PROHIBIDO** | `penpotUtils.findShapeById(page, id)`**27 ocurrencias sobre 21 de los 41 seeds viejos** |
El fallo es **silencioso**: devuelve `null` y revienta en la línea siguiente con
`Cannot read properties of null (reading '<prop>')`. El stack apunta al síntoma, no a la causa.
**Familia de búsqueda completa y permitida:**
| Forma | Cuándo |
| --- | --- |
| `penpotUtils.findShapeById(id)` | Id conocido, búsqueda global |
| `page.getShapeById(id)` | Id conocido, dentro de una página concreta |
| `penpotUtils.findShape(pred, root?)` | Primer match por predicado |
| `penpotUtils.findShapes(pred, root?)` | Todos los matches por predicado |
| `page.findShapes({name, nameLike, type})` | Búsqueda por criterio declarativo (Captura 23) |
| `penpotUtils.getPageByName(name)` | Obtener la página primero |
### 3.2 `shape.layout` no existe
| | |
| --- | --- |
| **Documentado** | `Board` declara `grid?: GridLayout` y `flex?: FlexLayout`. **No hay `layout`** (Captura 3) |
| **Verificado** | `'layout' in shape === false`; `shape.layout === undefined`. `board.flex` y `board.grid` devuelven **`null`** (no `undefined`) cuando no hay layout |
| **Correcto** | `if (board.flex) { board.flex.dir = 'column'; }` |
| **PROHIBIDO** | `shape.layout`, `board.layout`, `!!form.layout` — 8 ocurrencias sobre 5 seeds viejos |
**Origen del error, y por qué hay un seed dedicado a desambiguarlo:** la salida de
`penpotUtils.shapeStructure()` **sí** trae una clave `layout` (`{id, name, type, children?, layout?}`).
Es una clave del **output del helper**, no una propiedad del shape. Confundirlas es exactamente el error
que hay que desaprender.
### 3.3 `createText()` sin argumento devuelve `null`
| | |
| --- | --- |
| **Documentado** | Contrato: `createText(text: string): null \| Text`. **Ejemplo oficial: `text = penpot.createText();` sin argumento** (Captura 6) |
| **Verificado** | `createText('Hola mundo')``Text`. **`createText()``null`. `createText('')``null`** |
| **Correcto** | `const t = penpot.createText('Margherita'); if (!t) throw new Error('createText devolvió null');` |
| **PROHIBIDO** | `penpot.createText()` y `penpot.createText('')` |
Un modelo que consulta la documentación y sigue el ejemplo obtiene `null`, no puede crear texto, y
abandona: quedan solo rectángulos. Ésa es la mitad del síntoma reportado.
### 3.4 El gris `#B1B2B5`
| | |
| --- | --- |
| **Verificado** | El fill por defecto de `penpot.createRectangle()` es **`#B1B2B5`**. El de `createBoard()` es blanco |
| **Correcto** | Invariante R1: todo shape creado recibe `fills` explícito **antes** de insertarse |
El único ejemplo de flex layout en los 41 seeds viejos crea un board de 400×60 con dos rectángulos a los
que **nunca** asigna `fills` — el ejemplo canónico de "armar un layout" en los datos de entrenamiento
produce exactamente dos cajas grises.
---
## 4. Texto
| Miembro | Estado | Detalle verificado |
| --- | --- | --- |
| `characters` | ✅ | El contenido renderizado |
| `fontSize` | ✅ **string** | `'48'`. Los números se coercionan, pero el lint exige el string |
| `fontWeight` | ✅ **string** | `'700'` |
| `lineHeight` | ✅ **string** | `'1.2'` |
| `letterSpacing` | ✅ **string** | `'-1'` (px). **`'-0.02'` se lee de vuelta como `"0"`: los negativos en em se ignoran en silencio** |
| `fontFamily` | ✅ | `text.fontFamily = 'Work Sans'` como string directo **bindea** (`fontId: "gfont-work-sans"`). 1914 fuentes disponibles |
| `growType` | ✅ | `'auto-width'` \| `'auto-height'` \| `'fixed'`. Default `'auto-width'` |
| `align` | ✅ | `'left'` \| `'center'` \| `'right'` \| `'justify'` |
| `verticalAlign` | ✅ | `'top'` \| `'center'` \| `'bottom'` |
| `fills` | ✅ | El color del texto va acá. Default `[{fillColor:"#000000", fillOpacity:1}]` |
| `textTransform`, `textDecoration`, `direction` | ✅ | Captura 4 |
| `getRange(start, end)` | ✅ | Devuelve `TextRange` |
| `applyTypography(typography)` | ✅ | |
| **`textAlign`** | ❌ **LANZA** | `Cannot add property textAlign, object is not extensible`. **Mata todo el `execute_code`.** Usar `align` |
| **`color`** | ❌ **LANZA** | El objeto no es extensible. Usar `fills` |
| `font.applyToText(text)` | ⚠️ | Funciona, pero deja `fontId` como un objeto UUID de ClojureScript filtrado. **Preferir `fontFamily` como string** |
**Defaults de un `Text` recién creado, verificados:** `fontSize:"14"`, `fontFamily:"sourcesanspro"`,
`fontWeight:"400"`, `fills:[{fillColor:"#000000",fillOpacity:1}]`, `growType:"auto-width"`,
`width/height = [1, 1]`.
**Dimensionado (invariantes R4/R5/R6):**
- El auto-sizing **no es inmediato**: dormir ~120 ms antes de leer el bounding box.
- `resize(w, h)` setea `growType` a `'fixed'` **en silencio**. Restaurarlo si se quiere auto-sizing.
- `width` y `height` son **read-only**; `resize()` es la única vía.
- `parentX`/`parentY`/`boardX`/`boardY`/`bounds` son **read-only**; usar `penpotUtils.setParentXY()`.
---
## 5. Fills, gradientes, strokes, sombras, radios
| Miembro | Estado | Detalle |
| --- | --- | --- |
| `fills = [{fillColor, fillOpacity}]` | ✅ | |
| `fills` apilados | ✅ | Foto + scrim oscuro encima funciona |
| `fillColorGradient` | ✅ | Coords **normalizadas 0..1** con `width: 1`, aceptado verbatim |
| `fillImage` | ✅ | `fills = [{fillOpacity: 1, fillImage: img}]`; `img.keepAspectRatio = true` para fotos |
| `fillColorRefFile` / `fillColorRefId` | ✅ | Los pone `libraryColor.asFill()` |
| `strokes = [{strokeColor, strokeWidth, strokeStyle, strokeAlignment, strokeOpacity}]` | ✅ | |
| `borderRadius`, `borderRadiusTopLeft`… | ✅ | En rectángulo y board |
| `shadows = [{style, offsetX, offsetY, blur, spread, color}]` | ✅ | |
| **`Shadow.color`** | ⚠️ | Es un **`Color`** (`{color: '#000000', opacity: 0.12}`), **no un `Fill`**. `{fillColor: ...}` es el bug clásico |
| `blur` | ✅ | |
| `opacity`, `blendMode` | ✅ | |
**Gradiente, forma verificada:**
```js
fills = [{ fillOpacity: 1, fillColorGradient: {
type: 'linear', startX: 0, startY: 0, endX: 0, endY: 1, width: 1,
stops: [{ color: '#D62828', offset: 0 }, { color: '#F77F00', offset: 1 }]
}}]
```
---
## 6. Jerarquía e inserción
| Situación | Forma correcta |
| --- | --- |
| Padre **sin** layout | `parent.insertChild(parent.children.length, shape)` |
| 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 |
**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 —
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).
---
## 7. Layouts
### Flex
| Miembro | Estado | Detalle |
| --- | --- | --- |
| `board.addFlexLayout()` | ✅ | Devuelve `FlexLayout` |
| `board.flex` | ✅ | Guard: `if (board.flex)`. **`null`** si no hay layout |
| `dir` | ✅ | `'row'` \| `'row-reverse'` \| `'column'` \| `'column-reverse'` |
| `rowGap`, `columnGap` | ✅ | **No existe el shorthand `gap`** |
| `alignItems`, `alignContent`, `justifyItems`, `justifyContent` | ✅ | |
| `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` | ✅ | **Funciona** (verificado 2026-08-04, hallazgo 54). Aridad 1, preserva orden visual — preferible a `board.appendChild` para insertar en boards con flex |
### Grid
| Miembro | Estado | Detalle |
| --- | --- | --- |
| `board.addGridLayout()` | ✅ | **No `addFlexLayout()`**, como dice erróneamente el overview |
| `board.grid` | ✅ | Guard: `if (board.grid)` |
| `addRow(type, value?)`, `addColumn(type, value?)` | ✅ | `type`: `'flex'` \| `'fixed'` \| `'percent'` \| `'auto'` |
| `addRowAtIndex`, `addColumnAtIndex`, `removeRow`, `removeColumn`, `setRow`, `setColumn` | ✅ | |
| `rows`, `columns` | ✅ | `Track[]` = `{type, value}` |
| **`grid.appendChild(shape, row, column)`** | ✅ | **Índices 1-based.** `(s, 0, 0)` se clampea y se lee `[1,1]`; `(s, 1, 2)` se lee `[1,2]`. El ejemplo 0-based de la doc de tipos está mal |
| `shape.layoutCell` | ✅ | `{row, rowSpan, column, columnSpan, areaName, position}` — para leer de vuelta y reposicionar |
### `layoutChild` (el hijo dentro de un board con layout)
| Miembro | Estado | Detalle |
| --- | --- | --- |
| `layoutChild` | ✅ | **Existe solo DESPUÉS de insertar** el shape en un board con layout |
| `horizontalSizing` / `verticalSizing` | ✅ | `'fill'` \| `'auto'` \| **`'fix'`** (no `'fixed'`, no `'fit-content'`) |
| `alignSelf` | ✅ | |
| `absolute` | ✅ | `true` saca al hijo del flujo del layout |
| `*Margin`, `maxWidth`/`maxHeight`/`minWidth`/`minHeight` | ✅ | |
| **`zIndex`** | ⚠️ | Está en el tipo pero **se ignora en silencio** (se setea 10, se lee 0). Usar el orden de `children` |
**Invariante R8:** todo efecto de layout se **lee de vuelta** del objeto retornado. El seed se entrena
sobre `"titleStretched": true` leído del runtime, no sobre la esperanza de que haya funcionado.
**Invariante R9:** wrappers abrazan (`flex.horizontalSizing = 'fit-content'`), secciones llenan
(`layoutChild.horizontalSizing = 'fill'`). Los dos idioms en el mismo seed para que el contraste sea
aprendible.
---
## 8. Imágenes
| Miembro | Estado |
| --- | --- |
| `await penpot.uploadMediaUrl(name, url)``ImageData` | ✅ **Única vía** |
| `await penpot.uploadMediaData(name, bytes, mimeType)` | ✅ |
| `fills = [{fillOpacity: 1, fillImage: img}]` | ✅ |
| `img.keepAspectRatio = true` | ✅ Para fotos |
| `penpot.createImage()` | ❌ No existe |
| `penpotUtils.importImage()` | ❌ `penpotUtils.importImage is not a function` |
| herramienta MCP `import_image` | ❌ No existe en este deployment |
`uploadMediaUrl` devuelve una `Promise` y puede rechazar (`Error uploading media`): `await` dentro de
un `try/catch`.
---
## 9. Biblioteca local (tokens de diseño)
| Miembro | Estado | Detalle |
| --- | --- | --- |
| `penpot.library.local` | ✅ | |
| `library.local.createColor()` | ✅ | Luego `c.name = 'Brand/Primary'; c.color = '#D62828';` |
| `libraryColor.asFill()` | ✅ | Devuelve un `Fill` con `fillColorRefFile`/`fillColorRefId` |
| `libraryColor.asStroke()` | ✅ | |
| `library.local.createTypography()` | ✅ | |
| `library.local.createComponent(shapes)` | ✅ | |
| `component.instance()` / `mainInstance()` | ✅ | |
| `penpot.library.connected`, `availableLibraries()`, `connectLibrary(id)` | ✅ | |
| **`typography.setFont(font, variant?)`** | ❌ | Está en el tipo, **no existe en el runtime**: `t.setFont is not a function`. Setear `fontFamily`/`fontSize`/`fontWeight`/`lineHeight` una por una |
---
## 10. Verificación programática (invariante R12)
| Miembro | Estado | Uso |
| --- | --- | --- |
| `penpot.generateStyle(shapes, {type:'css', includeChildren:true})` | ✅ | Devuelve CSS real. **La opción es `includeChildren`; `withChildren` (que usa el overview) se ignora** |
| `penpot.generateMarkup(shapes, {type:'html'})` | ✅ | Devuelve HTML real |
| `penpotUtils.analyzeDescendants(root, evaluator, maxDepth?)` | ✅ | Auditoría; el evaluador puede devolver funciones correctoras |
| `penpotUtils.isContainedIn(shape, container)` | ✅ | Violaciones de contención |
| `penpotUtils.shapeStructure(shape, maxDepth)` | ✅ | Overview del árbol. **Su clave `layout` es del output, no del shape** |
| herramienta `export_shape` | ✅ | Inspección visual |
**R12: nunca terminar sin mirar y medir.** Todo seed compositivo cierra con `export_shape` + una
auditoría programática, y el mensaje final **cita los números** de esa auditoría.
---
## 11. Contramedida al system prompt del servidor
El servidor MCP inyecta verbatim (ver `penpot_system_prompt.md`):
> NEVER make assumptions about missing values and don't get overly creative (e.g. don't pick your own
> colours and stick to non-creative defaults such as white/black if you are lacking information).
**Ninguno de los 41 seeds viejos tiene mensaje `system`**, así que el modelo nunca se entrenó en
presencia de esta instrucción. En producción la aplica al revés y produce el gris.
Obligatorio en los seeds nuevos:
1. El bloque `instructions` **verbatim** como mensaje `system` en **~30 %** de los seeds (el resto sin
él, para robustez en las dos condiciones).
2. En **todo** seed creativo, `reasoning_content` que desambigüe explícitamente. La regla condiciona
sobre *"transferring styles from a Penpot design to code"*; crear un diseño nuevo es el caso
contrario: no hay diseño previo del que transferir, así que no hay "missing values" sobre los que
asumir. Elegir una paleta deliberada **es** la tarea.
---
## 12. Los doce invariantes anti-caja-gris
Cada uno presente **en los datos** y verificado por `scripts/07_lint_penpot_code.py`, no solo enunciado
en prosa.
| # | Invariante |
| --- | --- |
| R1 | Todo shape creado recibe `fills` explícito **antes** de insertarse. Los wrappers puros de layout ponen `fills = []` — transparente **por intención**, nunca "sin tocar" |
| R2 | **Cero grises de placeholder.** Todo hex debe pasar `saturación > 10` **o** `max < 100` **o** `max > 220`. El gris solo aparece en los tool results del grupo B8, y solo como *input* |
| R3 | Toda paleta es un set cerrado y nombrado de ≤ 8 roles, declarado al inicio del payload y referenciado por rol |
| R4 | Todo texto recibe `characters` + tamaño + fill + `growType` |
| R5 | Tamaño, peso e interlineado son **strings** entre comillas |
| R6 | Tras `resize()` sobre un texto, restaurar `growType` |
| R7 | Una card es fondo + radio + elevación |
| R8 | Todo hijo de layout declara su sizing, y el efecto se **lee de vuelta** del objeto retornado |
| R9 | Wrappers abrazan (`fit-content`), secciones llenan (`fill`) — los dos idioms en el mismo seed |
| R10 | Escala tipográfica, nunca tamaños ad-hoc: ≥ 3 tamaños distintos por pantalla compuesta |
| R11 | Espaciado en escala de 8 px |
| R12 | Nunca terminar sin mirar y medir: `export_shape` → auditoría → resumen que **cita los números** |
---
## 13. Resumen de patrones prohibidos (lo que el lint busca)
| Patrón | Por qué |
| --- | --- |
| `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 |
| `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 |
| Asignación a `width`/`height`/`parentX`/`parentY`/`bounds` | Read-only |
| `gap =` | No hay shorthand; son `rowGap`/`columnGap` |
| `shadows = [{... color: {fillColor` | `Shadow.color` es un `Color`, no un `Fill` |
| Hex gris de placeholder fuera del grupo B8 | Invariante R2 |
| `console.log` de algo que también se retorna | Prohibición explícita del servidor |
| `setFont(` | No existe en el runtime |
| `createText()` / `createText('')` | Devuelven `null` |
| `high_level_overview` en más de 2 seeds | Su descripción prohíbe llamarlo dos veces |
File diff suppressed because it is too large Load Diff
+176
View File
@@ -0,0 +1,176 @@
# Penpot MCP — strings de error reales
Mensajes de error **literales** que devuelve el servidor MCP de Penpot cuando un `execute_code` falla.
**Por qué existe este archivo.** El grupo D de `data/raw/seeds/penpot.jsonl` (6 seeds de auto-corrección)
entrena al modelo a diagnosticar y recuperarse de errores. Si el mensaje de error de un seed es
inventado, el modelo aprende a reaccionar a un string que nunca va a ver. Este archivo es la
**allow-list de mensajes de error**: `scripts/07_lint_penpot_code.py` verifica que todo `content` de un
mensaje `tool` que representa un error sea un string presente acá, verbatim.
**Procedencia.** Los mensajes de las secciones 1-4 fueron capturados en vivo por la sesión madre el
2026-07-30, contra el archivo real del usuario, ejecutando el código de la columna "Disparador" vía
`mcp__penpot__execute_code`. Están registrados en `PLAN.md` § "La API verificada" y en la página de
Docmost de la Fase 6 § "Diagnóstico". Los de la sección 5 son mensajes estándar del runtime de
JavaScript (V8/SpiderMonkey), deterministas dada la expresión que los produce.
**Nota operativa (2026-07-30):** al intentar re-capturar estos strings durante el paso 6.1.3, el
servidor MCP devolvió `No Penpot plugin instances are currently connected. Please ensure the plugin is
running and connected.` — el plugin del usuario no está conectado. Los mensajes de abajo se conservan
tal como los verificó la sesión madre; **la re-verificación en vivo queda pendiente** y se hace junto
con el baseline de la puerta 5 (paso 6.3.17), que también requiere el plugin conectado. Ningún seed
puede usar un string de error ausente de este archivo.
---
## 1. Propiedad inexistente sobre un objeto no extensible
El objeto `Text` (y en general los shapes) **no es extensible**: asignar una propiedad que no está en
la interfaz lanza, y la excepción **aborta todo el `execute_code`**, no solo esa línea.
| 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.
**Este es el error más caro del conjunto**, porque el modelo suele escribir `textAlign` por analogía con
CSS, en medio de un payload de 80 líneas que construye una landing entera: la excepción tira abajo la
composición completa, no solo el título.
---
## 2. Función inexistente en el runtime
| 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` |
**`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`).
El overview la menciona en prosa (`Use the export_shape and import_image tools`), lo cual es un
**anzuelo real**: la lista de herramientas que recibe el modelo es autoritativa, la prosa del
overview no. La ruta correcta es `await penpot.uploadMediaUrl(name, url)`.
- `typography.setFont` **sí está en el tipo** (`penpot_api_docs.md` Captura 26) pero **no existe en el
runtime de esta versión**. Es el caso canónico de "la documentación no es el runtime": hay que setear
las propiedades de tipografía una por una (`fontFamily`, `fontSize`, `fontWeight`, `lineHeight`).
Notar que el mensaje dice `t.setFont`, con el nombre de la variable local — no `typography.setFont`.
---
## 3. Uso de un retorno `null` sin chequear
La familia de errores más frecuente y la que produce la falla reportada por el usuario. Todas las
llamadas de creación y de búsqueda pueden devolver `null`; usar el resultado sin chequearlo produce un
`TypeError` en la **línea siguiente**, lo que hace que el stack apunte al síntoma y no a la causa.
| Disparador | Mensaje verbatim |
| --- | --- |
| `const t = penpot.createText(); t.characters = 'Hola'` | `Cannot set properties of null (setting 'characters')` |
| `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
`Cannot set properties of null (setting '<prop>')`.
**Las tres fuentes de `null` que los seeds deben enseñar a chequear:**
1. `penpot.createText()` **sin argumento** o con `''``null`. Con un string no vacío → `Text`.
El ejemplo de la documentación oficial (`penpot_api_docs.md` Captura 6) usa la forma sin argumento.
2. `penpotUtils.findShapeById(page, id)`**la forma de dos argumentos no lanza**: devuelve `null` en
silencio, porque `findShapeById` tiene aridad 1 y el segundo argumento se descarta mientras el
primero (un `Page`, no un `string`) no matchea ningún id. La forma correcta es
`penpotUtils.findShapeById(id)`.
3. `penpot.createBoolean(type, shapes)` y `penpot.createShapeFromSvg(svg)` declaran `null | T` en su
firma (Capturas 10 y 11).
---
## 4. Fallos de red y de subida de medios
| Disparador | Mensaje verbatim |
| --- | --- |
| `await penpot.uploadMediaUrl('foto', 'https://dominio-inexistente.invalid/a.jpg')` | `Error uploading media` |
`uploadMediaUrl` devuelve una `Promise`; el fallo llega como rechazo, así que hay que envolverlo en
`try/catch` **con `await` adentro del `try`** (un `.catch()` colgado de la promesa sin `await` deja el
resto del payload corriendo con `undefined`).
---
## 5. Errores estándar del runtime de JavaScript
Deterministas dada la expresión, no específicos de Penpot. Se listan porque aparecen en los seeds del
grupo D y el lint los tiene que aceptar.
| Disparador | Mensaje verbatim |
| --- | --- |
| `undefined.foo` | `Cannot read properties of undefined (reading 'foo')` |
| `shapes.map(...)` donde `shapes` es `null` | `Cannot read properties of null (reading 'map')` |
| `JSON.parse('{')` | `Unexpected end of JSON input` |
| `board.appendChild()` sin argumento | `Cannot read properties of undefined (reading 'id')` |
---
## 6. Errores a nivel de servidor MCP (no de `execute_code`)
No son excepciones de JavaScript: los devuelve el servidor MCP antes de llegar al plugin. **No pueden
aparecer como resultado de un `execute_code` en un seed**, porque no dejan al modelo en una situación
de "diagnosticá tu código" — significan que no hay con qué hablar.
| Situación | Mensaje verbatim |
| --- | --- |
| El plugin de Penpot no está abierto / no está conectado al servidor MCP | `No Penpot plugin instances are currently connected. Please ensure the plugin is running and connected.` |
Capturado en vivo el 2026-07-30 durante el paso 6.1.3 de esta fase.
---
## 7. Fallos SILENCIOSOS — no producen ningún error
**La categoría más peligrosa**, y la razón por la que el invariante R8 (`leer de vuelta el efecto`)
existe. Estas operaciones **no lanzan**, **no devuelven `null`**, y dejan el diseño mal. Un modelo que
solo maneja excepciones no las detecta nunca.
| Operación | Comportamiento real | Cómo detectarlo |
| --- | --- | --- |
| `flex.horizontalSizing = 'auto'` | Se lee de vuelta como `'auto'` pero **el board no crece** (200×200 sigue 200×200 tras insertar un hijo de 300 de ancho). Bug conocido penpot#8520 | Leer `board.width` tras insertar; hacer `board.resize()` a mano |
| `layoutChild.zIndex = 10` | Se lee de vuelta como `0`. **Se ignora** | Leer `layoutChild.zIndex`; usar el orden del array `children` para z-order |
| `text.letterSpacing = '-0.02'` | Se lee de vuelta como `"0"`. Los valores negativos en unidades tipo `em` **se descartan** | Leer `text.letterSpacing`; usar unidades tipo px (`'-1'`) |
| `penpot.createRectangle()` sin asignar `fills` | Queda con el fill por defecto **`#B1B2B5`** — el gris exacto del problema reportado | Invariante R1: `fills` explícito en todo shape creado |
| `penpotUtils.findShapeById(page, id)` | Devuelve `null`, **sin lanzar** | Chequear el retorno antes de usarlo |
| `board.layout` | `undefined`; `'layout' in shape === false`. La propiedad **no existe** | Usar `board.flex` / `board.grid`, que devuelven `null` cuando no hay layout |
| `generateStyle(shapes, {withChildren: true})` | La opción real es `includeChildren`; `withChildren` **se ignora** y el CSS sale sin los hijos | Ver `penpot_api_docs.md` Captura 8 |
| `grid.appendChild(shape, 0, 0)` | El `0` **se clampea a 1**: se lee de vuelta `[1,1]`. Los índices son 1-based | Leer `shape.layoutCell.row` / `.column` |
| `text.resize(w, h)` | Setea `growType` a `'fixed'` en silencio; el texto desborda su caja | Invariante R6: restaurar `growType` tras `resize()` |
| Leer `text.width` justo después de setear `characters` | El auto-sizing **no es inmediato**: se lee `1` | Dormir ~120 ms antes de leer el bounding box |
+60
View File
@@ -0,0 +1,60 @@
# Penpot MCP — bloque `instructions` del servidor, verbatim
Este archivo guarda **verbatim** el bloque `instructions` que el servidor MCP de Penpot inyecta en el
system prompt de todo cliente que se conecta. Es la **causa raíz #4** del diagnóstico de la Fase 6: la
regla de "don't get overly creative / don't pick your own colours" está pensada para el flujo
diseño→código, pero el modelo la aplica al revés y produce cajas grises cuando se le pide crear un
diseño con colores vibrantes.
**Procedencia:** capturado el 2026-07-30 en la Fase 6, contra el servidor MCP `penpot` conectado a esta
sesión. El texto es idéntico al que devuelve la herramienta `high_level_overview` (el servidor sirve el
mismo documento por ambas vías); la copia completa de esa captura vive en `penpot_api_docs.md`.
**Uso obligatorio:** este texto va **byte a byte** como mensaje `system` en ~30 % de los seeds nuevos de
`data/raw/seeds/penpot.jsonl`. Ninguna paráfrasis, ningún recorte. Ver `PENPOT_API_VERIFIED.md` §
"Contramedida al system prompt".
---
## Fragmento crítico (el que produce el gris)
> IMPORTANT: When transferring styles from a Penpot design to code, make sure that you strictly adhere to the design.
> NEVER make assumptions about missing values and don't get overly creative (e.g. don't pick your own colours and stick to
> non-creative defaults such as white/black if you are lacking information).
Lectura correcta, y la que los seeds deben enseñar explícitamente en `reasoning_content`: la regla
**condiciona sobre "transferring styles from a Penpot design to code"**. Cuando el usuario pide *crear*
un diseño nuevo no hay diseño previo del que transferir, así que no hay "missing values" sobre los que
asumir: elegir una paleta deliberada es la tarea, no una invención.
---
## Bloque completo, verbatim
```
You have access to Penpot tools in order to interact with a Penpot design project directly.
As a precondition, the user must connect the Penpot design project to the MCP server using the Penpot MCP Plugin.
IMPORTANT: When transferring styles from a Penpot design to code, make sure that you strictly adhere to the design.
NEVER make assumptions about missing values and don't get overly creative (e.g. don't pick your own colours and stick to
non-creative defaults such as white/black if you are lacking information).
# Executing Code
One of your key tools is the `execute_code` tool, which allows you to run JavaScript code using the Penpot Plugin API
directly in the connected project.
VERY IMPORTANT: When writing code, NEVER LOG INFORMATION YOU ARE ALSO RETURNING. It would duplicate the information you receive!
To execute code correctly, you need to understand the Penpot Plugin API. You can retrieve API documentation via
the `penpot_api_info` tool.
This is the full list of types/interfaces in the Penpot API: Penpot, ActiveUser, Blur, Board, VariantContainer, Boolean, CloseOverlay, Color, ColorShapeInfo, ColorShapeInfoEntry, Comment, CommentThread, CommonLayout, Context, ContextGeometryUtils, ContextTypesUtils, ContextUtils, Dissolve, Ellipse, EventsMap, Export, File, FileVersion, Fill, FlexLayout, Flow, Font, FontVariant, FontsContext, GridLayout, Group, GuideColumn, GuideColumnParams, GuideRow, GuideSquare, GuideSquareParams, HistoryContext, Image, Interaction, LayoutCellProperties, LayoutChildProperties, Library, LibraryColor, LibraryComponent, LibraryVariantComponent, LibraryElement, LibrarySummary, LibraryTypography, LocalStorage, NavigateTo, OpenOverlay, OpenUrl, OverlayAction, Page, Path, PathCommand, PluginData, PreviousScreen, Push, Rectangle, RulerGuide, Shadow, ShapeBase, Slide, Stroke, SvgRaw, Text, TextRange, ToggleOverlay, Track, User, Variants, Viewport, Action, Animation, BooleanType, Bounds, Gradient, Guide, ImageData, LibraryContext, Point, RulerGuideOrientation, Shape, StrokeCap, Theme, TrackType, Trigger
You use the `storage` object extensively to store data and utility functions you define across tool calls.
This allows you to inspect intermediate results while still being able to build on them in subsequent code executions.
```
El resto del documento (estructura de diseños, propiedades de shapes, z-order, layouts, texto,
`penpotUtils`, inspección visual, librerías) está capturado íntegro y verbatim en
`penpot_api_docs.md`, sección "Captura 1".
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+123 -2
View File
@@ -7,10 +7,15 @@ services:
ports:
- "8001:8000"
volumes:
- /home/aleleba/ft-models/Qwen3.6-35B-A3B-mcp-bf16:/model:ro
# Fase 6.4.25b: apunta al candidato v2b-bf16 (base + LoRA #1 + LoRA #2
# corregido con los 13 seeds del diagnostico de causa raiz), no al v2-bf16
# original (que fallo la puerta 5 modo full por el bug de formato de
# tool-call). Es el checkpoint contra el que se remide la puerta 5 tras la
# iteracion correctiva, antes de decidir NVFP4 vs fallback.
- /home/aleleba/ft-models/Qwen3.6-35B-A3B-mcp-v2b-bf16:/model:ro
command:
- "--model=/model"
- "--served-model-name=qwen3.6-35b-a3b-mcp-bf16"
- "--served-model-name=qwen3.6-35b-a3b-mcp-v2b-bf16"
- "--tensor-parallel-size=1"
- "--max-model-len=32768"
- "--enable-auto-tool-choice"
@@ -81,6 +86,122 @@ services:
retries: 5
start_period: 600s
# Fase 6 -- candidato v2b (base + LoRA #1 + LoRA #2 de diseno en Penpot,
# iteracion correctiva 6.4.25b/c, mergeado y recuantizado a NVFP4). Clon 1:1 de
# vllm-eval-nvfp4, que a su vez clona el compose real de produccion, incluido
# --speculative-config: es el contenedor contra el que se corren las puertas
# 2/3/4/5 del candidato, y solo sirve si replica exactamente los flags con los
# que se va a servir. Respecto de vllm-eval-nvfp4 cambian SOLO container_name,
# puerto (8004; 8000 produccion, 8001 Fase 4, 8002/8003 Fase 5), volumen,
# --model y --served-model-name. v2-NVFP4 (sin la "b") se salteo por completo:
# v2-bf16 disparo el fallback y la iteracion correctiva 6.4.25b/c produjo
# v2b-bf16 directamente, que es lo que se cuantiza aca. Nunca se toca
# vllm-qwen36 ni su compose real de Portainer.
vllm-eval-nvfp4-v2:
image: vllm/vllm-openai:cu130-nightly-aarch64
container_name: vllm-eval-nvfp4-v2
restart: "no"
runtime: nvidia
environment:
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: compute,utility
ports:
- "8004:8000"
ipc: host
ulimits:
memlock: -1
stack: 67108864
volumes:
- /home/aleleba/ft-models/Qwen3.6-35B-A3B-mcp-v2b-NVFP4:/models/Qwen3.6-35B-A3B-mcp-v2b-NVFP4:ro
command: >
--model /models/Qwen3.6-35B-A3B-mcp-v2b-NVFP4
--served-model-name qwen3.6-35b-a3b-mcp-v2b-nvfp4
--host 0.0.0.0
--port 8000
--tensor-parallel-size 1
--trust-remote-code
--quantization compressed-tensors
--moe-backend flashinfer_cutlass
--kv-cache-dtype fp8_e4m3
--gpu-memory-utilization 0.45
--max-model-len 524288
--max-num-seqs 8
--max-num-batched-tokens 32768
--enable-chunked-prefill
--enable-prefix-caching
--speculative-config '{"method":"mtp","num_speculative_tokens":1}'
--reasoning-parser qwen3
--tool-call-parser qwen3_coder
--enable-auto-tool-choice
--default-chat-template-kwargs '{"preserve_thinking":true}'
--limit-mm-per-prompt '{"image":4,"video":0,"audio":0}'
--generation-config vllm
--override-generation-config '{"temperature":0.6,"top_p":0.80,"top_k":20,"presence_penalty":0.0,"repetition_penalty":1.0}'
--hf-overrides '{"text_config":{"rope_scaling":{"rope_type":"yarn","factor":2.0,"original_max_position_embeddings":262144}}}'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 600s
# Fase 6 -- diagnostico de aislamiento del drift del head de MTP (riesgo #10):
# identico a vllm-eval-nvfp4-v2 pero SIN --speculative-config. El draft head de
# MTP se copia del linaje base y nunca se fine-tunea, mientras que el target
# model ya derivo DOS veces (LoRA #1 y LoRA #2), asi que la tasa de aceptacion
# del speculative decoding puede caer y degradar la calidad servida sin que la
# cuantizacion ni el dataset tengan nada que ver. Correr las mismas puertas en
# 8004 (spec) y 8005 (nospec) separa las dos causas. Es un servicio de
# diagnostico: no clona produccion 1:1 a proposito (esa es justo la variable
# que se esta aislando) y los flags de produccion NUNCA se cambian por esto,
# solo se reporta el hallazgo.
vllm-eval-nvfp4-v2-nospec:
image: vllm/vllm-openai:cu130-nightly-aarch64
container_name: vllm-eval-nvfp4-v2-nospec
restart: "no"
runtime: nvidia
environment:
NVIDIA_VISIBLE_DEVICES: all
NVIDIA_DRIVER_CAPABILITIES: compute,utility
ports:
- "8005:8000"
ipc: host
ulimits:
memlock: -1
stack: 67108864
volumes:
- /home/aleleba/ft-models/Qwen3.6-35B-A3B-mcp-v2b-NVFP4:/models/Qwen3.6-35B-A3B-mcp-v2b-NVFP4:ro
command: >
--model /models/Qwen3.6-35B-A3B-mcp-v2b-NVFP4
--served-model-name qwen3.6-35b-a3b-mcp-v2b-nvfp4-nospec
--host 0.0.0.0
--port 8000
--tensor-parallel-size 1
--trust-remote-code
--quantization compressed-tensors
--moe-backend flashinfer_cutlass
--kv-cache-dtype fp8_e4m3
--gpu-memory-utilization 0.45
--max-model-len 524288
--max-num-seqs 8
--max-num-batched-tokens 32768
--enable-chunked-prefill
--enable-prefix-caching
--reasoning-parser qwen3
--tool-call-parser qwen3_coder
--enable-auto-tool-choice
--default-chat-template-kwargs '{"preserve_thinking":true}'
--limit-mm-per-prompt '{"image":4,"video":0,"audio":0}'
--generation-config vllm
--override-generation-config '{"temperature":0.6,"top_p":0.80,"top_k":20,"presence_penalty":0.0,"repetition_penalty":1.0}'
--hf-overrides '{"text_config":{"rope_scaling":{"rope_type":"yarn","factor":2.0,"original_max_position_embeddings":262144}}}'
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 600s
# Fase 5 -- diagnostico de aislamiento: identico a vllm-eval-nvfp4 pero SIN
# --speculative-config, para determinar si la regresion de calidad observada
# en las puertas 2-3 (vs. Fase 4) viene del speculative decoding (MTP) o de
+207
View File
@@ -0,0 +1,207 @@
---
base_model: /workspace/ft-models/Qwen3.6-35B-A3B-mcp-bf16
library_name: peft
pipeline_tag: text-generation
tags:
- base_model:adapter:/workspace/ft-models/Qwen3.6-35B-A3B-mcp-bf16
- lora
- transformers
---
# Model Card for Model ID
<!-- Provide a quick summary of what the model is/does. -->
## Model Details
### Model Description
<!-- Provide a longer summary of what this model is. -->
- **Developed by:** [More Information Needed]
- **Funded by [optional]:** [More Information Needed]
- **Shared by [optional]:** [More Information Needed]
- **Model type:** [More Information Needed]
- **Language(s) (NLP):** [More Information Needed]
- **License:** [More Information Needed]
- **Finetuned from model [optional]:** [More Information Needed]
### Model Sources [optional]
<!-- Provide the basic links for the model. -->
- **Repository:** [More Information Needed]
- **Paper [optional]:** [More Information Needed]
- **Demo [optional]:** [More Information Needed]
## Uses
<!-- Address questions around how the model is intended to be used, including the foreseeable users of the model and those affected by the model. -->
### Direct Use
<!-- This section is for the model use without fine-tuning or plugging into a larger ecosystem/app. -->
[More Information Needed]
### Downstream Use [optional]
<!-- This section is for the model use when fine-tuned for a task, or when plugged into a larger ecosystem/app -->
[More Information Needed]
### Out-of-Scope Use
<!-- This section addresses misuse, malicious use, and uses that the model will not work well for. -->
[More Information Needed]
## Bias, Risks, and Limitations
<!-- This section is meant to convey both technical and sociotechnical limitations. -->
[More Information Needed]
### Recommendations
<!-- This section is meant to convey recommendations with respect to the bias, risk, and technical limitations. -->
Users (both direct and downstream) should be made aware of the risks, biases and limitations of the model. More information needed for further recommendations.
## How to Get Started with the Model
Use the code below to get started with the model.
[More Information Needed]
## Training Details
### Training Data
<!-- This should link to a Dataset Card, perhaps with a short stub of information on what the training data is all about as well as documentation related to data pre-processing or additional filtering. -->
[More Information Needed]
### Training Procedure
<!-- This relates heavily to the Technical Specifications. Content here should link to that section when it is relevant to the training procedure. -->
#### Preprocessing [optional]
[More Information Needed]
#### Training Hyperparameters
- **Training regime:** [More Information Needed] <!--fp32, fp16 mixed precision, bf16 mixed precision, bf16 non-mixed precision, fp16 non-mixed precision, fp8 mixed precision -->
#### Speeds, Sizes, Times [optional]
<!-- This section provides information about throughput, start/end time, checkpoint size if relevant, etc. -->
[More Information Needed]
## Evaluation
<!-- This section describes the evaluation protocols and provides the results. -->
### Testing Data, Factors & Metrics
#### Testing Data
<!-- This should link to a Dataset Card if possible. -->
[More Information Needed]
#### Factors
<!-- These are the things the evaluation is disaggregating by, e.g., subpopulations or domains. -->
[More Information Needed]
#### Metrics
<!-- These are the evaluation metrics being used, ideally with a description of why. -->
[More Information Needed]
### Results
[More Information Needed]
#### Summary
## Model Examination [optional]
<!-- Relevant interpretability work for the model goes here -->
[More Information Needed]
## Environmental Impact
<!-- Total emissions (in grams of CO2eq) and additional considerations, such as electricity usage, go here. Edit the suggested text below accordingly -->
Carbon emissions can be estimated using the [Machine Learning Impact calculator](https://mlco2.github.io/impact#compute) presented in [Lacoste et al. (2019)](https://arxiv.org/abs/1910.09700).
- **Hardware Type:** [More Information Needed]
- **Hours used:** [More Information Needed]
- **Cloud Provider:** [More Information Needed]
- **Compute Region:** [More Information Needed]
- **Carbon Emitted:** [More Information Needed]
## Technical Specifications [optional]
### Model Architecture and Objective
[More Information Needed]
### Compute Infrastructure
[More Information Needed]
#### Hardware
[More Information Needed]
#### Software
[More Information Needed]
## Citation [optional]
<!-- If there is a paper or blog post introducing the model, the APA and Bibtex information for that should go in this section. -->
**BibTeX:**
[More Information Needed]
**APA:**
[More Information Needed]
## Glossary [optional]
<!-- If relevant, include terms and calculations in this section that can help readers understand the model or model card. -->
[More Information Needed]
## More Information [optional]
[More Information Needed]
## Model Card Authors [optional]
[More Information Needed]
## Model Card Contact
[More Information Needed]
### Framework versions
- PEFT 0.19.1
@@ -0,0 +1,53 @@
{
"alora_invocation_tokens": null,
"alpha_pattern": {},
"arrow_config": null,
"auto_mapping": null,
"base_model_name_or_path": "/workspace/ft-models/Qwen3.6-35B-A3B-mcp-bf16",
"bias": "none",
"corda_config": null,
"ensure_weight_tying": false,
"eva_config": null,
"exclude_modules": null,
"fan_in_fan_out": false,
"inference_mode": true,
"init_lora_weights": true,
"layer_replication": null,
"layers_pattern": null,
"layers_to_transform": null,
"loftq_config": {},
"lora_alpha": 64,
"lora_bias": false,
"lora_dropout": 0.05,
"lora_ga_config": null,
"megatron_config": null,
"megatron_core": "megatron.core",
"modules_to_save": null,
"peft_type": "LORA",
"peft_version": "0.19.1",
"qalora_group_size": 16,
"r": 32,
"rank_pattern": {},
"revision": null,
"target_modules": [
"shared_expert.gate_proj",
"shared_expert.down_proj",
"k_proj",
"in_proj_qkv",
"in_proj_a",
"v_proj",
"in_proj_z",
"out_proj",
"q_proj",
"o_proj",
"shared_expert.up_proj",
"in_proj_b"
],
"target_parameters": null,
"task_type": "CAUSAL_LM",
"trainable_token_indices": null,
"use_bdlora": null,
"use_dora": false,
"use_qalora": false,
"use_rslora": false
}
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More