From b5167b71e33d6e731319bb36fb6642580931ca20 Mon Sep 17 00:00:00 2001 From: rafa-ruiz Date: Wed, 11 Mar 2026 12:22:08 -0700 Subject: [PATCH 1/2] UPDATE: Sample generator now includes a new key in each item. --- .../samples_generator/generate_mbap.py | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/scripts/pipelines/samples_generator/generate_mbap.py b/scripts/pipelines/samples_generator/generate_mbap.py index ae943ea..10dafd5 100644 --- a/scripts/pipelines/samples_generator/generate_mbap.py +++ b/scripts/pipelines/samples_generator/generate_mbap.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 """ Use: - python generate_mbpp_avap.py - python generate_mbpp_avap.py --lrm path/to/avap.md - python generate_mbpp_avap.py --lrm avap.md --output output/mbpp_avap.json --problems 300 + python generate_mbap.py + python generate_mbap.py --lrm path/to/avap.md + python generate_mbap.py --lrm avap.md --output output/mbpp_avap.json --problems 300 Requirements: pip install anthropic @@ -62,7 +62,7 @@ REGLAS ESTRICTAS para el código AVAP generado: MODO DE EJECUCIÓN — MUY IMPORTANTE: - El código se ejecuta DIRECTAMENTE, línea a línea, sin servidor ni registro de endpoints. -- NUNCA uses registerEndpoint(), NUNCA uses mainHandler(), NUNCA envuelvas el código en funciones solo para ejecutarlo salvo que queramos probar la funcionalidad de funciones. +- NUNCA uses registerEndpoint(), NUNCA uses mainHandler(), NUNCA envuelvas el código en funciones solo para ejecutarlo. - El código correcto es simplemente las instrucciones en línea, por ejemplo: result = "Hello World" addResult(result) @@ -82,9 +82,28 @@ Estructura exacta de cada elemento: "task_id": , "text": "", "code": "", + "test_inputs": { "": , "": }, "test_list": ["", ""] } +FORMATO DE test_inputs — MUY IMPORTANTE: +- Es un objeto JSON con un valor fijo para cada variable que el código recibe via addParam(). +- Los nombres de las claves deben coincidir EXACTAMENTE con el nombre de variable usado en addParam(). +- Los valores deben ser concretos y representativos del problema (no genéricos como "test" o 123). +- Si el código no tiene ningún addParam(), el campo test_inputs debe ser un objeto vacío: {} +- Estos valores son los que el evaluador inyectará en el stack antes de ejecutar el código, + de modo que las aserciones de test_list puedan validar las variables de salida resultantes. + +Ejemplo con addParam: + código: addParam("password", password)\\nencodeSHA256(password, hashed)\\naddResult(hashed) + test_inputs: { "password": "secret123" } + test_list: ["re.match(r'^[a-f0-9]{64}$', hashed)"] + +Ejemplo sin addParam: + código: randomString(16, token)\\naddResult(token) + test_inputs: {} + test_list: ["re.match(r'^[a-zA-Z0-9]{16}$', token)"] + FORMATO DE test_list — MUY IMPORTANTE: Cada aserción debe ser una expresión Python con re.match() o re.search() evaluable directamente sobre las variables del stack AVAP (disponibles como @@ -138,22 +157,26 @@ Responde ÚNICAMENTE con el array JSON. Sin texto antes ni después. def parse_response(raw: str): text = raw.strip() - if text.startswith("```"): lines = text.splitlines() inner = lines[1:] if inner and inner[-1].strip() == "```": inner = inner[:-1] text = "\n".join(inner).strip() + problems = json.loads(text) if not isinstance(problems, list): - raise ValueError("answer is not a JSON.") + raise ValueError("response is not an JSON array") for p in problems: for field in ("task_id", "text", "code", "test_list"): if field not in p: - raise ValueError(f"field '{field}' not found in a problem.") + raise ValueError(f"Field missing '{field}' in task_id={p.get('task_id','?')}.") + if "test_inputs" not in p: + p["test_inputs"] = {} + if not isinstance(p["test_inputs"], dict): + raise ValueError(f"'test_inputs' must by a JSON Object (task_id={p.get('task_id','?')}).") return problems From 90857e1b0aec4bd2a32cf3e4b5311b070569f9f2 Mon Sep 17 00:00:00 2001 From: rafa-ruiz Date: Wed, 11 Mar 2026 20:09:05 -0700 Subject: [PATCH 2/2] UPDATE: Modified LRM and generate_mbap.py to ensure better samples --- docs/LRM/avap.md | 173 ++++++++++++++---- .../samples_generator/generate_mbap.py | 10 +- 2 files changed, 138 insertions(+), 45 deletions(-) diff --git a/docs/LRM/avap.md b/docs/LRM/avap.md index 2209e9d..1805d2e 100644 --- a/docs/LRM/avap.md +++ b/docs/LRM/avap.md @@ -115,7 +115,41 @@ AVAP utiliza una gramática estructural mixta. Combina la fluidez de las palabra La estructura `if()` evalúa una expresión lógica o de comparación. Todo bloque condicional requiere un cierre explícito utilizando el comando `end()`. El comando `if()` soporta dos modos de invocación: -* **Modo 1 (comparación estructurada):** `if(variable, valor, comparador)` — evalúa la comparación entre variable y valor usando el operador indicado como string (ej. `"=="`, `">"`, `"!="`). Los dos primeros argumentos deben ser identificadores simples o literales, nunca expresiones de acceso como `dict['clave']`. Si se necesita comparar un valor extraído de una estructura, debe asignarse primero a una variable.* **Modo 2 (expresión libre):** `if(None, None, "expresion_compleja")` — evalúa directamente una expresión booleana compleja proporcionada como string. +* **Modo 1 (comparación estructurada):** `if(variable, valor, comparador)` — evalúa la comparación entre variable y valor usando el operador indicado como string (ej. `"=="`, `">"`, `"!="`). Los dos primeros argumentos deben ser identificadores simples o literales, nunca expresiones de acceso como `dict['clave']`. Si se necesita comparar un valor extraído de una estructura, debe asignarse primero a una variable.* **Modo 2 (expresión libre):** `if(None, None, expresion_compleja)` — evalúa directamente una expresión booleana compleja proporcionada como string encapsulado entre `. + +## SECCIÓN III: Lógica de Control y Estructuras de Decisión + +AVAP utiliza una gramática estructural mixta. Combina la fluidez de las palabras clave para abrir bloques funcionales con la seguridad matemática de cierres estrictos. + +### 3.1 El Bloque Condicional (if() / else() / end()) +El comando `if()` gestiona la lógica condicional mediante dos modos de invocación estrictamente diferenciados. Es imperativo respetar los delimitadores y la posición de los argumentos. + +#### Modo 1: Comparación Estructurada (Atómica) +Se utiliza para comparaciones directas entre dos valores simples. +* **Sintaxis:** `if(átomo_1, átomo_2, "operador")` +* **Argumentos 1 y 2:** Deben ser identificadores simples (variables) o literales (strings/números). **No se permite el uso de `None` en este modo.** +* **Argumento 3:** El operador de comparación debe ir obligatoriamente entre **comillas dobles** (`"=="`, `"!="`, `">"`, `"<"`, `">="`, `"<="`). +* **Restricción:** No se permiten expresiones de acceso (ej. `data.user` o `list[0]`). Estos valores deben asignarse previamente a una variable. +* **Ejemplo correcto:** `if(reintentos, 5, "<")` + +#### Modo 2: Expresión Libre (Evaluación Compleja) +Se utiliza para evaluar expresiones lógicas que no encajan en la estructura atómica. +* **Sintaxis:** `if(None, None, `expresión_compleja`)` +* **Argumentos 1 y 2:** Deben ser literalmente la palabra `None` (sin comillas). +* **Argumento 3:** La expresión completa **debe** estar encapsulada entre **acentos graves (backticks)**. Esto permite incluir lógica interna, operadores `and/or` y accesos a estructuras de datos. +* **Ejemplo correcto:** `if(None, None, `user.id > 10 and email.contains("@")`)` + +--- + +### Tabla de Validación para el Modelo + +| Entrada | Estado | Razón | +| :--- | :--- | :--- | +| `if(count, 10, "==")` | ✅ VÁLIDO | Modo 1: Átomos válidos y operador entre comillas. | +| `if(None, None, `val > 0`)` | ✅ VÁLIDO | Modo 2: Uso correcto de `None` y backticks. | +| `if(username, None, "==")` | ❌ ERROR | El Modo 1 prohíbe el uso de `None`. Debe usarse el Modo 2. | +| `if(None, None, "val > 0")` | ❌ ERROR | El Modo 2 requiere backticks (`` ` ``), no comillas. | +| `if(user.id, 10, "==")` | ❌ ERROR | El Modo 1 no permite expresiones de acceso (`.`). | ### 3.2 Iteraciones Estrictas y Deterministas (startLoop / endLoop) Para garantizar el determinismo y evitar el colapso de memoria: @@ -137,15 +171,17 @@ Diseñada para proteger la estabilidad del servidor ante fallos de I/O. [ "else()" ] "end()" -/* if() soporta dos modos: - Modo 1 — comparación estructurada: los dos primeros argumentos deben ser - identificadores simples o literales, nunca expresiones de acceso. - Si se necesita comparar un valor extraído de una estructura (ej. dict['clave']), - debe asignarse previamente a una variable. - Modo 2 — expresión libre: None, None, expresión compleja como string */ - ::= "," "," - | "None" "," "None" "," - ::= | + ::= | + + ::= "if" "(" "," "," ")" + ::= "if" "(" "None" "," "None" "," ")" + + ::= | + ::= "`" "`" + + ::= [a-zA-Z_][a-zA-Z0-9_]* +::= | +/* Nota: NO incluye la palabra "None" */ ::= "startLoop(" "," "," ")" @@ -261,59 +297,116 @@ AVAP utiliza `avapConnector("TOKEN")` para la hidratación segura de credenciale --- -## SECCIÓN VI: Utilidades, Criptografía y Manipulación de Datos +# SECCIÓN VI: Utilidades, Criptografía y Manipulación de Datos AVAP incluye un set de comandos integrados de alto nivel para manipular tipos complejos (JSON y Listas), tiempos, textos y generar hashes. -### 6.1 Manipulación Nativa de Listas y Objetos JSON -Para extraer y mutar estructuras complejas, AVAP provee comandos nativos específicos: -* **`variableToList(elemento, destino)`**: Fuerza a que una variable escalar se convierta en una estructura iterable de lista. -* **`itemFromList(lista_origen, indice, destino)`**: Extrae de forma segura el elemento contenido en la posición `indice` de una lista. -* **`variableFromJSON(json_origen, clave, destino)`**: Parsea un objeto JSON en memoria y extrae el valor correspondiente a la `clave`. -* **`AddVariableToJSON(clave, valor, json_destino)`**: Inyecta dinámicamente una nueva propiedad dentro de un objeto JSON existente. +--- -### 6.2 Criptografía y Expresiones Regulares -* **`encodeSHA256` y `encodeMD5(origen, destino)`**: Funciones criptográficas que encriptan de forma irreversible un texto. Vitales para el almacenamiento seguro de contraseñas. -* **`getRegex(origen, patron, destino)`**: Aplica una Expresión Regular (`patron`) sobre la variable de origen, extrayendo las coincidencias exactas. +## 6.1 Manipulación Nativa de Listas y Objetos JSON -### 6.3 Transformación de Tiempo y Cadenas -* **Fechas:** `getTimeStamp` (convierte un string a Epoch), `getDateTime` (Epoch a string legible), y `stampToDatetime` (Epoch a objeto datetime estructurado). Soportan formatos de calendario y cálculos con TimeDeltas. -* **Cadenas:** `replace` (saneamiento y sustitución de texto) y `randomString` (generación determinista de claves/tokens aleatorios). +Para extraer y mutar estructuras complejas, AVAP provee comandos nativos específicos. En AVAP, las listas **no se instancian con literales de array**, sino que se construyen y recorren a través de un conjunto cerrado de comandos especializados: -### Especificación BNF (Sección VI) +* **`variableToList(elemento, destino)`**: Fuerza a que una variable escalar se convierta en una estructura iterable de lista de un único elemento. Es el punto de entrada canónico para construir una lista desde cero a partir de un valor existente. + +* **`itemFromList(lista_origen, indice, destino)`**: Extrae de forma segura el elemento contenido en la posición `indice` (base 0) de una lista. Equivale a un acceso por índice controlado. + +* **`getListLen(lista, destino)`**: Calcula el número total de elementos contenidos en `lista` y almacena el resultado entero en `destino`. Imprescindible para construir bucles de recorrido seguro y para validar listas antes de acceder a sus índices. Se recomienda llamar siempre a `getListLen` antes de `itemFromList` para evitar accesos fuera de rango. + +* **`variableFromJSON(json_origen, clave, destino)`**: Parsea un objeto JSON en memoria y extrae el valor correspondiente a la `clave`, almacenándolo en `destino`. El acceso es directo por nombre de propiedad. + +* **`AddVariableToJSON(clave, valor, json_destino)`**: Inyecta dinámicamente una nueva propiedad dentro de un objeto JSON existente. Si la clave ya existe, su valor es sobreescrito. + +**Patrón de recorrido típico en AVAP:** + +```avap +// 1. Obtener longitud de la lista +getListLen(myList, len) + +// 2. Iterar con índice controlado +i = 0 +while (i < len) { + itemFromList(myList, i, currentItem) + // ... procesar currentItem ... + i = i + 1 +} +``` + +--- + +## 6.2 Criptografía y Expresiones Regulares + +* **`encodeSHA256(origen, destino)`** y **`encodeMD5(origen, destino)`**: Funciones criptográficas que encriptan de forma irreversible un texto. Vitales para el almacenamiento seguro de contraseñas y la verificación de integridad de datos. SHA-256 produce un digest de 64 caracteres hexadecimales y ofrece mayor resistencia criptográfica que MD5 (32 caracteres); se recomienda SHA-256 para nuevos desarrollos. + +* **`getRegex(origen, patron, destino)`**: Aplica una Expresión Regular (`patron`) sobre la variable de origen, extrayendo la primera coincidencia exacta encontrada. El patrón sigue la sintaxis estándar compatible con Python `re`. + +--- + +## 6.3 Transformación de Tiempo y Cadenas + +### Fechas y Timestamps + +AVAP provee tres comandos complementarios para cubrir todas las conversiones posibles entre representaciones de tiempo. Los tres soportan formatos de calendario en notación `strftime` de Python y cálculos con `TimeDelta` expresados en segundos (positivo para sumar, negativo para restar): + +| Comando | Entrada | Salida | +|---|---|---| +| `getTimeStamp(fecha_string, formato, timedelta, destino)` | String de fecha | Epoch (entero) | +| `stampToDatetime(epoch, formato, timedelta, destino)` | Epoch (entero) | String de fecha | +| `getDateTime(formato, timedelta, zona_horaria, destino)` | — (ahora mismo) | String de fecha | + +* **`getTimeStamp(fecha_string, formato, timedelta, destino)`**: Convierte un string de fecha legible a su valor Epoch (entero Unix). Útil para almacenar fechas y realizar cálculos aritméticos sobre ellas. + +* **`stampToDatetime(epoch, formato, timedelta, destino)`**: Convierte un valor Epoch a un string de fecha con el formato especificado. Útil para presentar timestamps almacenados de forma legible. + +* **`getDateTime(formato, timedelta, zona_horaria, destino)`**: Captura la fecha y hora actuales del sistema, aplica el ajuste `timedelta` y las convierte a la `zona_horaria` indicada antes de almacenar el resultado. Acepta cualquier zona horaria reconocida por la librería `pytz` de Python. + +### Cadenas de Texto + +* **`randomString(patron, longitud, destino)`**: Genera una cadena aleatoria de `longitud` caracteres cuyos símbolos están restringidos al conjunto definido por `patron` (expresión regular de caracteres). Útil para generar tokens de sesión, contraseñas temporales o identificadores únicos. + +* **`replace(origen, patron_busqueda, reemplazo, destino)`**: Localiza todas las ocurrencias de `patron_busqueda` dentro de `origen` y las sustituye por `reemplazo`, almacenando el resultado en `destino`. Facilita el saneamiento y normalización de datos de entrada antes de su procesamiento o almacenamiento. + +--- + +## BNF — Gramática Formal de los Comandos de Utilidad ```bnf -/* [CORRECCIÓN] Todas las subreglas de están ahora completamente expandidas. */ - ::= | | | | | | + ::= | | + | | | | /* Manipulación de listas y JSON */ - ::= "variableToList(" "," ")" - | "itemFromList(" "," "," ")" - | "variableFromJSON(" "," "," ")" - | "AddVariableToJSON(" "," "," ")" + ::= "variableToList(" "," ")" + | "itemFromList(" "," "," ")" + | "getListLen(" "," ")" + | "variableFromJSON(" "," "," ")" + | "AddVariableToJSON(" "," "," ")" /* Criptografía */ - ::= "encodeSHA256(" "," ")" - | "encodeMD5(" "," ")" + ::= "encodeSHA256(" "," ")" + | "encodeMD5(" "," ")" /* Expresiones regulares */ - ::= "getRegex(" "," "," ")" + ::= "getRegex(" "," "," ")" - ::= "getDateTime(" "," "," "," ")" -/* Argumentos: formato_salida, epoch_origen, zona_horaria, destino */ +/* Fecha/hora actual → string */ + ::= "getDateTime(" "," "," "," ")" +/* Argumentos: formato_salida, timedelta, zona_horaria, destino */ - ::= "stampToDatetime(" "," "," "," ")" +/* Conversiones epoch ↔ string */ + ::= "stampToDatetime(" "," "," "," ")" /* Argumentos: epoch_origen, formato, timedelta, destino */ - | "getTimeStamp(" "," "," "," ")" + | "getTimeStamp(" "," "," "," ")" /* Argumentos: fecha_string, formato_entrada, timedelta, destino */ - ::= "randomString(" "," ")" -/* Argumentos: longitud, destino */ +/* Cadenas */ + ::= "randomString(" "," "," ")" +/* Argumentos: patron, longitud, destino */ - ::= "replace(" "," "," "," ")" + ::= "replace(" "," "," "," ")" /* Argumentos: origen, patron_busqueda, reemplazo, destino */ ``` + --- ## SECCIÓN VII: Arquitectura de Funciones y Ámbitos (Scopes) diff --git a/scripts/pipelines/samples_generator/generate_mbap.py b/scripts/pipelines/samples_generator/generate_mbap.py index 10dafd5..a567d4d 100644 --- a/scripts/pipelines/samples_generator/generate_mbap.py +++ b/scripts/pipelines/samples_generator/generate_mbap.py @@ -53,7 +53,7 @@ REGLAS ESTRICTAS para el código AVAP generado: 5. if() Modo 1: if(var_o_literal, var_o_literal, "operador") — los argumentos NO pueden ser expresiones de acceso como dict['key']; hay que extraer el valor a una variable propia primero. -6. if() Modo 2: if(None, None, "expresion_completa_como_string") +6. if() Modo 2: if(None, None, `expresion_completa_como_string`) 7. _status se asigna con: addVar(_status, 404) 8. ormAccessSelect firma: ormAccessSelect(campos, "tabla", selector, varTarget) — selector puede ser cadena vacía. @@ -105,25 +105,25 @@ Ejemplo sin addParam: test_list: ["re.match(r'^[a-zA-Z0-9]{16}$', token)"] FORMATO DE test_list — MUY IMPORTANTE: -Cada aserción debe ser una expresión Python con re.match() o re.search() +Cada aserción debe ser una expresión Python con re.match() evaluable directamente sobre las variables del stack AVAP (disponibles como variables Python locales). El módulo 're' está siempre disponible. La expresión debe devolver un match object (truthy) si el test pasa. Reglas estrictas: -- USA ÚNICAMENTE re.match(r'', ) o re.search(r'', str()) +- USA ÚNICAMENTE re.match(r'', ) +- NO combines expresiones re.match en una aserción, cada asercion tiene que ser un unico re.match(r'', ) - Convierte a string si es necesario: re.match(r'^\\d+$', str(result)) - Puedes encadenar con 'and': re.match(r'^[a-zA-Z0-9]{32}$', token) and re.match(r'.{32}', token) - Las variables referenciadas deben existir en el stack tras ejecutar el código. - NUNCA uses comparaciones directas (==, !=, >, <). - NUNCA uses isinstance(), len(), assert, ni texto descriptivo. -- NUNCA uses nada que no sea re.match() o re.search(). +- NUNCA uses nada que no sea re.match(). Ejemplos correctos de test_list: "re.match(r'^[a-f0-9]{64}$', hashed)" "re.match(r'^[a-zA-Z0-9]{32}$', token)" "re.match(r'^\\d{4}-\\d{2}-\\d{2}$', date_str)" - "re.search(r'Hello', result)" "re.match(r'^-?\\d+(\\.\\d+)?$', str(result))" "re.match(r'^(par|impar)$', result)" "re.match(r'^40[134]$', str(_status))"