Cauce

Build log

Cada unidad de trabajo que ha aterrizado, de la más reciente a la primera, cada una con el commit que la cerró y la limitación que dejó atrás. Puedes contrastar cualquiera contra el repositorio en lugar de fiarte de mi palabra.

Unidades
42102 commits
Módulos
13de 15 · 2 aún vacíos
Tests
953en verde, 0 fallos
Desde
18 may2026 · una persona
Mostrar
Siguiente sin empezar

Que la pantalla de auditoría muestre lo que ahora dice la API

El endpoint de verificación ganó cuatro estados de veredicto, un informe de firmas y un ancla; la pantalla sigue pintando los dos antiguos. Conectarla implica también devolver la cabeza como ancla para la siguiente comprobación.

playground

Firmas

unidades 39–42 · Septiembre
Breaking 18e2401 2026-09-11

Un veredicto con cuatro respuestas en lugar de dos

La verificación responde ahora VALID, BROKEN, TRUNCATED o UNVERIFIABLE, lleva un informe de firmas y se escribe a sí misma en la cadena que acaba de verificar. El truncamiento solo se afirma contra un ancla que aporta quien llama: una cadena no puede detectar su propia cola ausente.

La pantalla del playground todavía no consume los campos nuevos. Una verificación aterriza en la cadena un tick de drenado después, no en la respuesta que la produjo.

cauce-governancecauce-apiplayground
Entregado 856b355 2026-09-11

Cada entrada de auditoría lleva ahora una firma

Ed25519 sobre el hash v2 de la entrada. La clave privada vive en la configuración del proceso y nunca toca la base de datos, así que una base de datos por sí sola no basta para falsificar una entrada. El registro de id de clave a clave pública es un fichero que se lee desde fuera de la base de datos.

El JDK no puede derivar la clave pública a partir de la privada, así que se configuran ambas y el par se autocomprueba al arrancar. El informe de cobertura de firmas se quedó interno hasta la unidad 42.

cauce-governancecauce-memorycauce-api
Entregado 94de4c0 2026-09-11

Fijar exactamente qué entra en el hash

El id entra en la preimagen, los timestamps se serializan con precisión fija de microsegundos y las cadenas de texto se normalizan a NFC, de modo que la misma entrada produce el mismo hash en todas partes. Las entradas antiguas no se recalculan; el verificador bifurca según el esquema que declara cada fila.

Un esquema desconocido se reportaba como entrada malformada, lo cual inducía a error. Corregido en la unidad 42. La especificación de la preimagen vive en Javadoc, no en docs.

cauce-governance
Decisión b9b19c9 2026-09-11

Decidir cómo funcionaría la firma, antes de escribirla

El ADR 0003 fija Ed25519, una clave por instancia guardada fuera de la base de datos, cuatro estados de veredicto y un registro de claves publicado en abierto. Un segundo commit corrige una afirmación falsa que el ADR hacía sobre los guards de vocabulario.

Marcado como «aceptado, aún no implementado». Artefacto de exportación, verificador independiente, anclaje temporal externo y claves por tenant, todo diferido.

docs/adr

Una ventana a la máquina

unidades 31–38 · De agosto a septiembre
Entregado 9587141 2026-09-08

Uso de tokens, por invocación

El endpoint de invocación devuelve los datos de tokens que el libro mayor registró para esa llamada, como campo aditivo y anulable.

Sigue sin haber agregación por tenant ni materialización del coste.

cauce-apicauce-orchestration
Entregado 75deab3 2026-09-08

Siete pantallas contra el backend real

Sesión, conversación, tenants, agentes, claves de API, invocaciones y la cadena de auditoría, todas construidas contra los mockups y leyendo de la API en marcha. Un guard de build falla si la pantalla de auditoría deriva hacia lenguaje de veredicto.

Sin arnés de tests en el frontend; su puerta es un build más verificación manual. El guard de vocabulario cubría la vista de auditoría y su hoja de estilos, no los tipos del wire: ampliado en la unidad 40.

playground
Decisión 2142a32 2026-09-01

Dibujar todas las pantallas antes de construir ninguna

Mockups en HTML estático, un fichero por viewport, cada uno declarando su propio contrato hasta los estados de foco, autocompletado y movimiento reducido. Especificación, no código.

playground
Entregado 11c6dd3 2026-08-25

La clave sabe quién es

El playground lee su propia identidad en lugar de pedirte que la pegues, y pinta la traza completa de herramientas a partir del contenido estructurado.

El número de rondas sigue sin poder derivarse del wire.

playground
Entregado 73f18ca 2026-08-13

Un endpoint que responde «quién soy»

Introspección de claves, contenido estructurado de herramientas en el DTO de mensaje, y UUIDs malformados en un body respondidos con 400 en lugar de 500.

cauce-api
Entregado d57feaa 2026-08-13

El árbol de tenants, y los agentes dentro

Los tres niveles pintados como un árbol, con agentes creados en el contexto en el que estás.

El id del tenant del workspace había que pegarlo a mano, porque aún no existía un endpoint de identidad.

playground
Entregado 49adc01 2026-08-12

Ver trabajar al agente

Enviar a un agente real, consultar el estado de la invocación cada dos segundos y ver el bucle de herramientas como una traza plegable. Sin streaming falso: el motor es asíncrono y la interfaz lo dice.

No hay enlace mensaje-invocación en el wire, así que los metadatos de invocación son por vista.

playground
Entregado e404672 2026-08-12

Un sitio donde dejar la clave

Shell, sonda de salud y pantalla de sesión. La clave de API vive solo en memoria y nunca se escribe en ningún sitio.

El proxy de desarrollo suple el CORS, que el backend sigue sin configurar.

playground

La cadena

unidades 26–30 · De julio a agosto
Entregado d229793 2026-08-10

La cadena puede comprobarse desde fuera

Un endpoint autenticado recalcula la cadena de un tenant y devuelve el veredicto, la secuencia en la que se rompe por primera vez con una clasificación pública, el recuento de filas previas a la cadena y un bloque de alcance que nombra lo que el recálculo no detecta.

Solo dos estados de veredicto en este punto, y el alcance decía que la firma estaba reservada: cierto entonces, superado por la unidad 41.

cauce-api
Entregado c9c6f7f 2026-07-25

Los actos administrativos entran en la cadena

Crear un tenant, un agente o una clave, revocar una, configurar un canal: cada uno auditado dentro de la transacción de la propia operación, en la cadena del sujeto, con el tenant que actúa como actor.

Atribución del actor por id de clave, diferida. Dos hooks reservados sin emisión. El bootstrap del operador es la excepción génesis sin auditar.

cauce-governancecauce-tenancy
Entregado ab915a3 2026-07-25

Lo que hizo el agente, registrado según ocurre

Mensaje recibido, agente respondió, invocación fallida: cada uno emitido dentro de la transacción del hecho que audita, de modo que un evento auditado y uno sin registrar no pueden separarse.

Cuatro tipos de evento reservados sin emisión: acción externa, acceso a datos, escalado a humano, respuesta entregada.

cauce-governancecauce-core
Entregado 7f09be7 2026-07-25

Cada entrada lleva la anterior

Una cadena de hashes por tenant, con una fila de cabeza como única fuente de secuencia. Altera una entrada antigua y todos los enlaces posteriores dejan de cuadrar; el verificador reporta la secuencia exacta en la que se rompe por primera vez.

La firma sigue reservada, y con ella el residuo documentado: un atacante con privilegios que recalcule toda la cadena y reescriba la cabeza no es detectable solo con el recálculo.

cauce-governancecauce-memory
Entregado 848b936 2026-07-25

Captura que no se puede saltar

Un outbox escrito dentro de la propia transacción de negocio de quien llama, y un registro de solo anexado donde update y delete están revocados para el rol de base de datos de la aplicación. Si el hecho de negocio hace commit, su registro de auditoría hace commit con él.

Columnas de cadena creadas reservadas y a null. Todavía sin emisores reales.

cauce-governancecauce-memory

Puesto a punto

unidades 22–25 · Julio
Entregado 82a1795 2026-07-25

Un libro mayor de lo que gastó cada tenant

Una fila inmutable por llamada al LLM, escrita de forma síncrona antes de publicar el evento de respuesta. Si el insert en el libro mayor falla, la invocación falla.

Coste deliberadamente no materializado: el precio será una tabla versionada y una vista. Sin endpoint de consulta, sin agregaciones.

cauce-orchestrationcauce-memory
Entregado 047bdcd 2026-07-23

Clónalo y mira a un agente responder

Un perfil de compose que levanta la app y un Ollama local, descarga el modelo, crea un agente de demo y envía el primer mensaje con uso de herramientas. El modelo por defecto llamó a la herramienta de reloj cinco veces de cinco.

El job de CI solo construye la imagen.

dockerscripts
Breaking 440bd0e 2026-07-17

Listas que aguantan cuando crecen

Paginación por keyset sobre el id ordenado en el tiempo, un sobre uniforme en todos los endpoints de listado. Una ruptura de contrato respecto a los arrays desnudos que había antes.

El listado de claves de API se quedó fuera del contrato y sigue devolviendo un array desnudo.

cauce-apicauce-memory
Entregado b97fd5f 2026-07-17

Puedes preguntar qué pasó con tu petición

La respuesta aceptada devuelve un id de invocación, y un endpoint informa de su estado en vocabulario público desacoplado del ciclo de vida interno.

Las invocaciones abandonadas por el reaper y los fallos de preparación ajenos al LLM no dejan mensaje en la conversación; su única señal visible es el estado de la invocación.

cauce-apicauce-orchestration

Hacia el mundo

unidades 20–21 · Julio
Entregado 957cc03 2026-07-04

La respuesta vuelve a salir

Entrega saliente a través de un puerto de despacho en el dominio, invocado una vez que el último mensaje del agente ha hecho commit.

Explícitamente best-effort: sin outbox, sin reintentos, sin deduplicación en la entrega.

cauce-channelscauce-core
Entregado b388e1f 2026-07-04

El primer canal real

Una SPI de canal, un binding de una instancia de canal a un agente, y un adaptador de entrada de Telegram cuya ingesta es idempotente sobre el propio update id de la plataforma.

La credencial del bot se guarda en claro en reposo: cifrado diferido junto con las credenciales de LLM por tenant. Los canales soportados siguen siendo un conjunto hardcodeado.

cauce-channelscauce-api

Que aguante

unidades 17–19 · Julio
Entregado 1582098 2026-07-04

Lo primero que escucha los eventos

Los ocho eventos de orquestación se convierten en métricas en un endpoint de actuator autenticado. Los hooks tendidos dos unidades antes tienen ya un consumidor.

Sin exportador: ni OpenTelemetry ni Prometheus, en ningún módulo.

cauce-observability
Entregado e50786e 2026-07-04

Enviar el mismo mensaje dos veces no duplica nada

Una cabecera de idempotencia opcional: una repetición con la misma clave para el mismo agente devuelve los ids originales y no ingesta nada, sostenida por un bloqueo insert-first sobre una restricción de unicidad.

Sin huella del cuerpo de la petición y sin purga de retención.

cauce-apicauce-orchestration
Entregado 9ad26b0 2026-07-03

El orquestador empieza a decir lo que hizo

Un módulo hoja con un contrato sellado de ocho eventos, emitidos en cada paso del bucle. Nada los consume todavía: existen para que la auditoría pueda engancharse después sin reabrir el orquestador.

Un evento se publica dentro de la transacción de ingesta, así que un consumidor que persista necesitará un hook after-commit o un outbox.

cauce-orchestration-events

Dejó de ser un chatbot

unidades 14–16 · 13 de junio
Entregado a6f962d 2026-06-13

El bucle se cierra

El orquestador ofrece herramientas, ejecuta las que pide el modelo, devuelve los resultados e invoca de nuevo, hasta diez rondas. Las llamadas al modelo corren sin retener una conexión a la base de datos.

El timeout del reaper pasó a ser doce minutos planos en lugar de un heartbeat. Los esquemas de las herramientas no cuentan contra la ventana de contexto.

cauce-orchestration
Entregado 5cfa65c 2026-06-13

Los dos proveedores aprenden a hablar herramientas

El mismo modelo neutral de herramientas se mapea sobre los bloques de contenido de Anthropic y sobre la forma compatible con OpenAI. El core nunca aprendió ninguno de los dos formatos.

cauce-llm-anthropiccauce-llm-openai
Entregado 279115c 2026-06-13

Una forma de describir una herramienta que no pertenece a ningún proveedor

Definiciones, llamadas y resultados de herramientas como tipos sellados en el dominio, un contrato ejecutable en un módulo nuevo, y mensajes de herramienta persistidos con su payload. Una herramienta de reloj viene incorporada, sobre todo para probar el contrato de extremo a extremo.

El registro de herramientas es global: sin ámbito por agente.

cauce-corecauce-toolscauce-memory

El bucle se hace público

unidades 11–13 · Junio
Decisión 3736694 2026-06-10

Poner por escrito lo que se dejó sin hacer a propósito

Un registro duradero de trabajo diferido conscientemente, guardado en el fichero que lee el tooling. Los huecos conocidos dejan de ser folclore y pasan a ser una lista.

docs
Entregado 5832df4 2026-06-03

Publica un mensaje, recibe una respuesta

Un endpoint resuelve o abre la conversación, anexa el mensaje y encola el trabajo en una sola transacción, a prueba de carreras bajo un índice único parcial. La respuesta llega de forma asíncrona.

La respuesta aceptada omitía el id de invocación, así que un cliente no podía preguntar qué había pasado. Corregido en la unidad 22.

cauce-apicauce-orchestration
Entregado 94b0ac0 2026-06-02

Un adaptador, tres proveedores

Un único adaptador compatible con OpenAI registrado como tres proveedores condicionales, con un modelo local sin clave como valor por defecto en desarrollo. El segundo adaptador entró sin tocar la interfaz: la única prueba real que recibe una abstracción.

cauce-llm-openai

Quién puede entrar

unidades 7–10 · De mayo a junio
Decisión 9e77dfc 2026-06-02

La autoridad es la jerarquía, no una tabla de permisos

Autenticación real por clave en cada ruta: qué tenant eres sale de la clave validada, nunca de una cabecera. Las claves se hashean con un pepper. El ADR 0002 fija que la autoridad es la relación de visibilidad que la base de datos ya impone.

Sin roles y sin scopes. Sigue siendo cierto hoy.

cauce-apicauce-tenancydocs/adr
Decisión 6838a14 2026-06-02

La aplicación deja de ser la dueña de la base de datos

Ahora se conecta como un rol de mínimo privilegio con row-level security activa en tiempo de ejecución. La reclamación entre tenants del worker en segundo plano pasa por funciones de ámbito estrecho, y el ADR 0001 fija esas tres como las únicas salidas sancionadas.

No es un pendiente sino una restricción permanente: cada nueva necesidad entre tenants exige una función nueva y una razón documentada.

cauce-memorycauce-orchestrationdocs/adr
Entregado 58a37b3 2026-05-29

La primera superficie REST

Tenants y agentes sobre HTTP, con un contrato global de errores y un id de petición que recorre los logs y vuelve en una cabecera.

Una cabecera de desarrollo hacía las veces de tenant, emparejada con una ruta abierta. Ambas estaban marcadas explícitamente para desaparecer, y desaparecieron, en la unidad 10.

cauce-api
Entregado 49145fd 2026-05-26

Las claves existen antes de que nada las use

La entidad de clave y el filtro de autenticación aterrizan en el pipeline de seguridad sin ningún endpoint detrás todavía.

cauce-apicauce-core

El motor

unidades 5–6 · Mayo
Entregado 73c1b3f 2026-05-26

El trabajo sale del hilo de la petición

Una cola sobre la base de datos, ensamblado de contexto acotado por la ventana del modelo, un worker que reclama filas sin bloquear a sus vecinos, backoff en el reintento y un reaper para las reclamaciones cuyo worker murió. Todo lo que vino después se apoya en esto.

La reclamación y el reap cruzan tenants y aún no funcionaban bajo un rol de mínimo privilegio. Resuelto en la unidad 9.

cauce-orchestration
Entregado 5e9324a 2026-05-23

El core nunca sabrá qué modelo respondió

Un contrato neutral de proveedor con un registro y un modelo neutral de invocación, más el primer adaptador detrás.

Streaming dejado fuera del contrato a propósito. Un proveedor. Sin credenciales por tenant.

cauce-llmcauce-llm-anthropic

Aislamiento, en la base de datos

unidades 3–4 · Mayo
Entregado 7727733 2026-05-23

Conversaciones, y lo que las cierra

Conversaciones y mensajes bajo el mismo aislamiento jerárquico, ids ordenados en el tiempo desde un único punto del dominio, y transiciones de ciclo de vida explícitas.

El escalado se escribió sin ningún llamador. Sigue sin tenerlo: es un hook reservado, y el log lo dice en lugar de dar a entender que la funcionalidad existe.

cauce-corecauce-memory
Entregado 220b577 2026-05-21

Tres niveles que la base de datos se niega a mezclar

Operador, partner, cliente: con la visibilidad impuesta por row-level security, donde la regla de cada entidad llama a la de su padre. Olvidar un filtro no puede filtrar las filas de otro tenant, porque la base de datos no las devolverá.

El campo de proveedor era una cadena libre validada contra un conjunto hardcodeado, a la espera del contrato que llegó en la unidad 5.

cauce-corecauce-memorycauce-tenancy

Antes de cualquier código

unidades 1–2 · 18–21 de mayo
Decisión 28844f1 2026-05-21

Diez módulos, todos vacíos

El build, el stack local y la integración continua, con la forma ya dibujada y nada dentro. Nombrar pronto los módulos vacíos es lo que evita que los llenos crezcan unos dentro de otros más adelante.

all
Decisión 2494022 2026-05-20

La licencia antes de la primera línea

Readme, licencia y contexto del proyecto. Source-available ahora, Apache 2.0 cuatro años después de cada release. Sin código todavía, y el fichero lo decía.

repo root

Primer commit: 18 de mayo de 2026.