Lección 08 — Listas de funciones como primitivas del harness
Lección 08 — Listas de funciones como primitivas del harness
Le pedís a un agente que construya un sitio de e-commerce. Cuando termina, te dice “listo”. Mirás el código: la autenticación funciona, pero el botón de checkout del carrito no hace nada y el flujo de pago no está conectado. El problema: nunca le dijiste qué significa “listo”, así que usó su propio estándar —“escribí mucho código y parece bastante completo”—.
Para mucha gente, las listas de funciones son una nota: escribís cosas para no olvidarlas y después las dejás de lado. Pero en el mundo del harness, una lista de funciones no es una nota para humanos: es la columna vertebral de todo el harness. El scheduler depende de ella para elegir tareas, el verifier para juzgar la finalización y el handoff reporter para generar resúmenes. Si rompés la columna, todo el cuerpo queda paralizado.
Anthropic y OpenAI enfatizan lo mismo: los artefactos deben externalizarse. El estado de las funciones debe vivir en un archivo legible por máquina dentro del repo, no en texto de conversación sin estructura.
Los agentes no saben qué significa “listo”
Decís “agregá una función de carrito de compras” y el modelo puede interpretar eso como “escribí un componente Cart y un método addToCart”. Pero vos querías “el usuario puede navegar productos, agregarlos al carrito y completar el checkout end-to-end”. Sin una lista de funciones, esta brecha de entendimiento persiste, y el agente usa su estándar implícito: normalmente “el código no tiene errores de sintaxis obvios”.
Mirá esta nota de progreso, tan común:
Hice user auth, el carrito casi listo, faltan los pagos
¿Puede una sesión nueva responder preguntas con esa nota? ¿Qué significa “casi listo”? ¿Qué tests pasó el carrito? ¿Qué bloquea los pagos? La respuesta a todo es “nadie sabe”.
Resultado: la sesión nueva gasta 20 minutos infiriendo el estado del proyecto y quizás reimplementa funciones ya terminadas. Los datos de ingeniería de Anthropic muestran que buenos registros de progreso reducen el tiempo de diagnóstico al iniciar sesión entre 60% y 80%.
La feature list como primitiva del sistema
flowchart TD
FL[("feature_list.json<br/>fuente única de verdad")]
FL --> S["Scheduler<br/>elige la siguiente<br/>not_started"]
FL --> V["Verifier<br/>ejecuta el comando<br/>y decide la transición"]
FL --> H["Handoff reporter<br/>genera el resumen<br/>de traspaso"]
FL --> P["Progress tracker<br/>distribución de estados<br/>y salud del proyecto"]
V -->|única vía de promoción| FL
S -.WIP=1.-> FL
Los documentos son para que los lean humanos; las primitivas son para que las ejecuten sistemas. Los documentos pueden ignorarse; las primitivas no pueden saltearse. Pensá en la diferencia entre una restricción de trigger en la base de datos y un check en la capa de aplicación: la primera la impone el motor, ningún SQL puede saltearla.
Conceptos clave
- Las listas de funciones son primitivas del harness: no son “herramientas opcionales de planificación”, sino estructuras de datos fundacionales de las que dependen los demás componentes.
- Triple conductual: cada función es una tripleta
(descripción de comportamiento, comando de verificación, estado actual). Si falta cualquier elemento, el ítem está incompleto. - Modelo de máquina de estados: cuatro estados —
not_started,active,blocked,passing—. Las transiciones las controla el harness, no las cambia libremente el agente. - Pass-state gating: la única forma de pasar de
activeapassinges que el comando de verificación se ejecute con éxito. - Single source of truth: toda la información sobre “qué hay que hacer” debe derivarse de una sola lista. Sin contradicciones entre la lista y el historial de conversación.
- Contrapresión (back-pressure): el número de funciones que todavía no pasaron es la presión que el harness ejerce sobre el agente. Presión cero = proyecto completo.
Cómo hacerlo bien
1. Definí un formato mínimo
No necesitás un sistema complejo: sirve un archivo Markdown estructurado o JSON. La clave es que cada entrada tenga la tripleta:
{
"id": "F03",
"behavior": "POST /cart/items con {product_id, quantity} devuelve 201",
"verification": "curl -X POST http://localhost:3000/api/cart/items -H 'Content-Type: application/json' -d '{\"product_id\":1,\"quantity\":2}' | jq .status == 201",
"state": "passing",
"evidence": "commit abc123, log de salida del test"
}
2. Dejá que el harness controle las transiciones
El agente no puede cambiar directamente el estado de una función a passing. Solo puede enviar una solicitud de verificación; el harness ejecuta el comando y decide si permite la transición. Eso es pass-state gating.
3. Escribí las reglas en el archivo de instrucciones
## Reglas de la lista de funciones
- Archivo: /docs/features.md
- Solo una función activa a la vez
- El comando de verificación debe pasar antes de marcar como passing
- No modifiques los estados vos mismo: el script de verificación los actualiza
4. Calibrá la granularidad
Cada función debe tener un alcance “completable en una sesión”.
| Granularidad | Ejemplo | Veredicto |
|---|---|---|
| Demasiado amplia | ”Implementar el carrito” | No se va a terminar |
| Correcta | ”El usuario puede agregar ítems al carrito” | Completable y verificable |
| Demasiado estrecha | ”Crear el campo name en el modelo Cart” | El costo de gestión supera el beneficio |
Caso real
Una plataforma de e-commerce con 10 funciones, dos enfoques de seguimiento:
Modo memo: notas sin estructura. Después de 3 sesiones quedan como “hice user auth y product list, el carrito casi listo pero con bugs, payments sin empezar”. La sesión nueva necesita 20 minutos para inferir el estado y termina reimplementando funciones ya completadas.
Modo columna vertebral: cada función tiene estado claro y comando de verificación. La sesión nueva lee la lista y en 3 minutos sabe que F01-F05 están passing, F06 está active y F07-F10 están not_started. Continúa directamente desde F06, sin retrabajo.
Resultado cuantificado: los proyectos que usan listas de funciones estructuradas muestran una tasa de finalización 45% mayor que el seguimiento libre, con cero implementaciones duplicadas.
Ideas clave
- Las listas de funciones son la columna vertebral del harness, no notas para humanos.
- Cada función debe tener la tripleta: descripción de comportamiento + comando de verificación + estado actual.
- Las transiciones de estado las controla el harness: pasar la verificación es el único camino de promoción.
- La lista es el single source of truth del proyecto: toda la información de “qué hacer” deriva de una sola lista.
- Calibrá la granularidad a “completable en una sesión”.
Ejercicios
- Diseño de lista de funciones: definí un esquema JSON mínimo con id, descripción de comportamiento, comando de verificación, estado actual y referencia de evidencia. Usalo para describir un proyecto real con 5 funciones.
- Comparación de estrictez: elegí 3 funciones y diseñá una verificación laxa (“el código no tiene errores de sintaxis”) y una estricta (“el test end-to-end pasa”). Compará la tasa de falsos positivos.
- Auditoría de fuente única: revisá un proyecto con agentes y buscá información de alcance que contradiga la lista de funciones (requisitos implícitos en conversaciones, comentarios TODO en código). Diseñá un plan para unificar todo en la lista.
Lecturas adicionales
- Anthropic: Building Effective Agents
- OpenAI: Harness Engineering
- Design by Contract — Bertrand Meyer
- How Google Tests Software
Anterior: Lección 07 — Definí límites claros para las tareas · Siguiente: Lección 09 — Evitá que el agente declare victoria antes de tiempo