La pregunta que estoy revisando ahora
Mi investigación ya abarca más proyectos que ese entrenamiento. Estoy probando formas de coordinar agentes, mantener documentación viva y decidir cuándo una respuesta necesita rigidez y cuándo conviene dejar espacio para explorar.
Se están haciendo tests para evitar errores, pero sigo viendo una parte pendiente: el criterio para elegirlos, también al trabajar con modelos de frontera. Una prueba puede pasar y aun así no responder a la pregunta que necesitábamos resolver.
Cómo leer el caso documentado
Los 29 casos de abajo pertenecen al registro de NEAT, con su versión técnica al 17/09/2026. Los mantengo como evidencia de ese proyecto; no son una lista de incidentes de todos los proyectos que estoy revisando ahora ni resultados de las pruebas con PPO.
Cada entrada cuenta qué pasó, qué costó y la regla que quedó. Algunas son muy propias del motor de física; otras permiten discutir problemas de coordinación y proceso que pueden aparecer al trabajar sobre un mismo proyecto.
- Corrida
- Una ejecución completa de entrenamiento o de evaluación.
- Registro (raw)
- Lo que el motor escribe mientras corre. Es la única fuente que cuenta como prueba.
- Compuerta
- Una comprobación automática que decide si una corrida pasa o no.
- Control negativo
- Una prueba hecha para fallar a propósito. Si no falla, la compuerta no sirve.
- ULP
- El paso más pequeño que puede dar un número decimal en la computadora. Se usa para comparar resultados sin engañarse.
Errores de rótulo Familia A · decir que algo es lo que no es
Los más tontos y los que más se repitieron. Un nombre mal puesto hace que otros trabajen sobre algo que no existe.
Qué pasó. Se llamó «entorno» a un lector de contrato, y después a un lazo sin recompensa. Ninguno ejecutaba reset ni step.
Qué costó. Dos ciclos de trabajo sobre algo que no simulaba nada.
Regla. Una pieza se llama por lo que el registro del motor demuestra que ejecutó. «Listo para X» exige el registro de X.
Qué pasó. Un valor fijo (physicalResetNoExtraSimStep: True) viajó en el registro como si fuera un dato medido, durante muchos ciclos. Al medirlo había 3 ticks, y en otra función.
Qué costó. Tres afirmaciones sin medir y una discusión sobre un dato que no existía.
Regla. Nada que afirme un hecho físico entra al registro sin un contador o una lectura real detrás. Los valores fijos se marcan como tales.
Qué pasó. El video de Isaac decía «objetivo 39 / 59 / 115 / 155 (validación)» y en realidad corrió un solo objetivo de entrenamiento cuatro veces.
Qué costó. Un video que no se podía comparar, entregado, y una recaptura.
Regla. El rótulo se lee del motor, no del argumento con que se lanzó. Detector: cuatro mínimos idénticos hasta 18 decimales. Una coincidencia imposible dice tanto como una discrepancia.
Qué pasó. El descriptor de salida decía «miembros RUN resueltos» y era copia byte a byte del de entrada, con cinco PENDING.
Qué costó. Un archivo de identidad que no identificaba nada.
Regla. La identidad de una corrida es su registro. Ningún consumidor lee el descriptor de salida hasta que se haya escrito.
Qué pasó. Campos como «corrida corta, 50 updates» viajaron a la referencia de la corrida larga y al auditor de Unity.
Qué costó. Rótulos falsos circulando entre equipos.
Regla. Los consumidores deciden por el SHA del archivo en disco, nunca por un rótulo dentro del JSON. Cada corrida regenera su procedencia.
Errores de medición Familia B · números que no medían lo que decían
Aquí el dato existía, pero no significaba lo que se afirmó. Son los más fáciles de publicar por error.
Qué pasó. Un umbral fijo de 1e-6 m rechazaba poses exactas a 33 m y aceptaba corrupción a 1.5 m.
Qué costó. Tres rondas de compuertas inútiles.
Regla. Presupuestos según la representación del número (ULP) y compuertas que predicen el valor exacto.
Qué pasó. Una corrida legítima dio 4 ULP y fue rechazada.
Qué costó. Falsos negativos.
Regla. Se predice el valor por el mecanismo (el recorrido pasa por el centro de masa), no con una tolerancia genérica.
Qué pasó. Se tomó 250.84 como retorno inicial (R₀); era el retorno tras 10 updates. El campo de al lado, updateIndex, no se miró. Llegó a un descriptor sellado y desplegado.
Qué costó. Un umbral mal derivado y una versión extra del paquete.
Regla. R₀ se mide en el update 0 de la propia corrida, antes del primer aprendizaje. Una cita verifica que el valor está, no que signifique lo que se dijo.
Qué pasó. Se publicó «ganancia 3.96, ×4 por paso». Era una secante entre amplitudes; la incremental decae a 0.23.
Qué costó. Una justificación falsa, publicada y difundida.
Regla. Una magnitud de amplitud no es sensibilidad. La sensibilidad se mide con un Δ pequeño sobre datos reales (salió p50 4.27).
Qué pasó. Observación sintética y pesos distintos de los de la corrida. La monotonía «4 → 8 → 12 ULP» era un artefacto.
Qué costó. Una conclusión falsa: «1024 es el peor caso». El peor caso era lote 100.
Regla. Las pruebas de la red usan observaciones reales y los pesos exactos de la corrida, identificados por SHA.
Qué pasó. Ratios de sensibilidad por componente de hasta 3.7e4 porque el denominador era el ULP de un valor casi cero.
Qué costó. Casi se publicó.
Regla. Solo se citan cocientes con denominador homogéneo. Los ratios por componente sirven para ordenar, no para acotar.
Qué pasó. El criterio de parada miró el retorno, ya saturado contra su techo, mientras la métrica de tarea seguía mejorando a buen ritmo.
Qué costó. La corrida paró en el primer punto posible con pendiente.
Regla. El criterio mira la métrica de tarea sostenida, no solo el retorno. Se instrumentó C2 (mejor error por episodio) antes de la corrida; sin ella se habría leído «no aprendió».
Errores de instrumento Familia C · compuertas que no podían fallar
Una compuerta que siempre pasa no es una compuerta. Todos estos parecían funcionar.
Qué pasó. Cuando las sondas fallaban, comparaba None con None y escribía «IDÉNTICOS».
Qué costó. Un falso positivo en la compuerta que habilitaba el lanzamiento.
Regla. Toda compuerta se prueba primero contra una entrada que debe hacerla fallar.
Qué pasó. El generador tenía fijos la fila y el límite anteriores. El negativo «pasó» y no acreditaba nada.
Qué costó. Un control que no controlaba.
Regla. El elemento y el límite del negativo se derivan del registro que se audita.
Qué pasó. Cuatro entornos con el mismo input se trataron como cuatro observaciones distintas.
Qué costó. Un determinismo que no acreditaba nada.
Regla. El control debe variar la variable: seguir al valor, seguir al eje.
Qué pasó. Mataba «todo python salvo ComfyUI», y se incluyó en la lista.
Qué costó. No escribió la medición posterior al cierre.
Regla. Una lista por negación protege lo que nombra y nada más. Hay que excluir el propio proceso y su árbol.
Qué pasó. El YAML tenía claves repetidas (YAML se queda con la última sin avisar) y se perdió un campo en silencio.
Qué costó. Un valor superado apareciendo junto a una razón que hablaba de otro.
Regla. Un validador acredita lo que comprueba, no el archivo entero. Se buscan claves duplicadas y se lee el registro, no lo que uno cree haber escrito.
Qué pasó. En cada evaluación, la observación del paso 0 era la guardada del último paso de entrenamiento, no la del objetivo asignado.
Qué costó. Una acción de 240 por episodio calculada sobre otro estado, en las 11 evaluaciones.
Regla. Tras asignar objetivos se reconstruye la observación desde el estado. Detector: dos corridas «idénticas» que no coincidieron bit a bit.
Errores de física y API Familia D · costaron construcciones
Los más específicos del motor. Si no trabajas con Isaac Lab o Unity, quédate con D4: es universal.
Qué pasó. Reescribir posiciones y velocidades con los mismos valores dejaba los bits iguales, pero cambiaba la evolución.
Qué costó. El bit a bit del reset se rompió dos veces.
Regla. El reset escribe solo las filas de los entornos terminados, por índice, en los cinco tensores.
Qué pasó. app.close de Kit no vuelve: el proceso queda vivo con la GPU tomada.
Qué costó. Corridas que «no terminaban» y mediciones posteriores imposibles.
Regla. El registro se sella antes de cerrar; un vigilante externo mata el proceso huérfano después y escribe el archivo lateral.
Qué pasó. Importar onnxruntime dentro de Kit produce una violación de acceso.
Qué costó. Dos construcciones perdidas.
Regla. La traza va en dos etapas: torch dentro de Kit, onnxruntime en un proceso aparte, y se comparan por fila.
Qué pasó. Dos construcciones de 1024 entornos perdidas por un IndexError que con 4 entornos habría aparecido en segundos.
Qué costó. Dos horas de GPU.
Regla. Nada corre a 1024 sin pasar de punta a punta con N=4, con el mismo script.
Qué pasó. Las escrituras a la raíz hechas antes de activar el cuerpo se perdían: iteraciones, profundidad de penetración, inmóvil.
Qué costó. Configuración que no se aplicaba.
Regla. Todo ajuste de raíz se aplica y se verifica después de la activación.
Errores de proceso Familia E · los más caros, por repetidos
Ninguno tiene que ver con física. Son de cómo se coordina el trabajo, y fueron los que más horas se llevaron.
Qué pasó. El ejecutor cerraba su turno «ocioso» con trabajo pendiente («Sigo…» y nada más). Ocho veces.
Qué costó. Ciclos de 20 minutos perdidos. La corrida larga corrió dos horas sin ningún reporte, y el retorno inicial lo tuvo que leer otro del disco.
Regla. Un turno no termina con trabajo pendiente, salvo bloqueo contractual o corrida en vuelo con vigía. Encargos de un solo entregable.
Qué pasó. Mensajes en cola llegaban desordenados y duplicados; uno decía algo y el siguiente lo corregía.
Qué costó. Confusión en tres chats.
Regla. Un mensaje consolidado por chat y por ciclo, con visto bueno humano. Tope de 40 líneas. Sin acuses de recibo.
Qué pasó. Hashes de git publicados junto a SHA-256 crudos, sin rótulo.
Qué costó. Casi se leyó como una diferencia real entre la máquina local y la remota.
Regla. Cada SHA se publica con la pregunta contra la que se comparó.
Qué pasó. Dos copias del paquete en la máquina remota; una quedó vencida y se seguía llamando «el desplegado».
Qué costó. Riesgo de lanzar contra la copia equivocada.
Regla. Las órdenes citan rutas completas. Un nombre en singular que apunta a varios objetos es una trampa.
Qué pasó. El contrato P2 tuvo cuatro versiones antes de ejecutar nada. Se consultó al Crítico por cuestiones de redacción.
Qué costó. Horas de proceso sin una sola medición nueva.
Regla. Correr primero lo que ya tiene insumos. El Crítico entra solo en compuertas de fase. Se registran decisiones y defectos, no lecciones.
Qué pasó. Los defectos conocidos se dejaban en lista en vez de corregirse juntos.
Qué costó. Cada medición nueva tropezaba con un defecto viejo.
Regla. Una versión del paquete con todos los defectos conocidos corregidos en un solo cambio, antes de la siguiente fase.
Lo que funcionó en ese proyecto y hay que conservar
- Medir antes de diseñar: la medición invalidó dos contratos antes de que costaran GPU.
- Predicción sellada antes de correr, con fecha verificable, en vez de explicar después.
- Controles negativos reales y verificación cruzada entre dos máquinas y dos operadores.
- Un Crítico adversarial con la tabla completa: retiró argumentos del Arquitecto, del coordinador y del ejecutor.
- Sellar lo que se consumió y verificar que consumido = sellado antes de cada veredicto.
- Un fallo bien reportado valió más que un pase forzado, todas las veces.
El criterio que quiero pedirle a una prueba
Esta es la revisión que quiero hacer al decidir qué tests necesita un cambio:
- ¿Qué comportamiento o fallo concreto está intentando comprobar?
- ¿Podría fallar si ese comportamiento estuviera roto, o solo está repitiendo lo que dice la implementación?
- ¿Usa datos y condiciones que representen el caso que importa?
- ¿Qué demuestra al pasar y qué queda fuera de su alcance?
- ¿Su costo y su mantenimiento tienen sentido para el riesgo de ese cambio?
No quiero medir la calidad por la cantidad de tests. Quiero comprobar si ayudan a detectar problemas reales y si sus resultados permiten tomar la siguiente decisión.
Documentación viva y reglas claras
También estoy revisando cómo mantener las decisiones vigentes al trabajar con varios agentes. Una documentación que nadie actualiza puede seguir circulando como si fuera válida. Y una instrucción rígida aplicada fuera de su contexto puede consumir trabajo sin resolver el problema.
La prueba con mensajes entre agentes forma parte de esa investigación. Quiero separar lo que necesita una regla precisa —permisos, responsabilidades, condiciones de entrega— de lo que necesita margen para explorar. Todavía estoy comprobando dónde poner esa separación.
Lo que sigo revisando
En el caso de NEAT, los errores más caros fueron de rótulo y de proceso. En los proyectos que estoy revisando ahora, el foco sigue en aclarar reglas, mantener el contexto al día y elegir pruebas con criterio. Registrar resultados ayuda, pero también hay que saber qué permiten afirmar y qué sigue pendiente.