← Volver al blog

Publicación

Racoonity ya tiene pulso

De una arquitectura escrita en documentos a un runtime real, probado y capaz de confirmar o revertir su primera operación.

Por El equipo de Racoonity
9 min de lectura
#desarrollo#arquitectura#racoonity#openspec#golang

Racoonity ya tiene pulso

Hace unos días, Racoonity era principalmente una visión acompañada por muchos documentos.

Ya teníamos bastante claro qué queríamos construir: un sistema empresarial pequeño y sencillo por defecto, pero preparado para crecer mediante motores internos, módulos bien delimitados y contratos públicos.

También teníamos nombres para casi todas sus piezas:

  • Racoon Guildmaster para registrar capacidades.
  • Racoon Dispatcher para ejecutar acciones.
  • Racoon Librarian para resolver consultas.
  • Racoon Inspector para validar contratos.
  • Racoon Foreman para coordinar transacciones.
  • Racoon Gossip para representar el sistema de eventos.

El mapa existía.

Lo que todavía no existía era una ciudad funcionando sobre él.

Antes de establish-runtime-foundation

Antes de comenzar este cambio, el proyecto tenía una dirección arquitectónica bastante definida, pero todavía no podía demostrar casi nada mediante código ejecutable.

No había una API completa que pudiera arrancar desde una instalación limpia.

No existía un recorrido real que atravesara una petición HTTP, encontrara una capacidad, validara su entrada, ejecutara un handler y confirmara una transacción en PostgreSQL.

Tampoco podíamos demostrar todavía algunas de las promesas centrales de la arquitectura:

  • Que una operación pudiera revertirse completamente.
  • Que un doble envío no duplicara información.
  • Que los eventos se escribieran dentro de la misma transacción.
  • Que los errores internos no terminaran expuestos al usuario.
  • Que los módulos pudieran registrarse sin acoplarse directamente entre sí.
  • Que las fronteras arquitectónicas fueran algo más que buenas intenciones escritas en Markdown.

En otras palabras, Racoonity tenía planos, filosofía y nombres bastante simpáticos para sus motores, pero todavía no tenía pulso.

El objetivo del primer cambio

El cambio establish-runtime-foundation correspondió a la iteración I0: Primer latido.

Su propósito no era implementar usuarios, inventario, ventas, productos o una interfaz bonita.

El propósito era más pequeño y, al mismo tiempo, más fundamental:

Racoonity arranca
→ conecta PostgreSQL
→ registra capacidades
→ ejecuta una query
→ ejecuta una action
→ confirma o revierte una transacción
→ devuelve una respuesta pública estable

Era importante mantener el alcance bajo control.

Una base arquitectónica puede convertirse fácilmente en un framework eterno: muchas abstracciones, muchas interfaces y ningún usuario capaz de hacer algo útil.

Por eso I0 se diseñó alrededor de cuatro capacidades técnicas muy pequeñas:

system.ping
system.get_status
demo.transaction_commit
demo.transaction_rollback

No representan funcionalidades comerciales.

Representan pruebas visibles de que la maquinaria interna funciona.

Lo que existe ahora

Después de completar y archivar establish-runtime-foundation, Racoonity ya cuenta con un runtime backend real en Go.

La API puede:

  • Cargar su configuración.
  • Conectarse a PostgreSQL.
  • Ejecutar migraciones mediante un comando separado.
  • Registrar módulos y capacidades durante el arranque.
  • Validar consistencia antes de comenzar a escuchar peticiones.
  • Ejecutar actions y queries mediante una superficie HTTP uniforme.
  • Propagar correlation y causation IDs.
  • Aplicar validación estructural.
  • Autorizar capacidades mediante una implementación inicial.
  • Coordinar commits y rollbacks.
  • Registrar eventos en una outbox transaccional.
  • Manejar idempotencia.
  • Cerrar ordenadamente el servidor y la conexión a PostgreSQL.

La superficie pública mínima quedó así:

GET  /health/live
GET  /health/ready
POST /api/v1/queries/{key}
POST /api/v1/actions/{key}

También quedó establecida una respuesta común:

{
  "success": true,
  "data": {},
  "error": null,
  "correlation_id": "..."
}

La intención es que los futuros módulos de Racoonity no tengan que inventar su propia manera de recibir peticiones, devolver errores o coordinar operaciones.

La primera operación completa

La demostración más importante fue demo.transaction_commit.

Una petición atraviesa prácticamente toda la columna vertebral de Racoonity:

HTTP
→ Racoon Dispatcher
→ Capability Registry
→ autorización
→ validación
→ handler
→ Racoon Foreman
→ reserva de idempotencia
→ escritura de prueba
→ outbox
→ resultado persistido
→ commit

Todo ocurre dentro de una sola transacción.

Si la operación tiene éxito, quedan exactamente:

  • Una prueba de la operación.
  • Un evento pendiente en la outbox.
  • Un resultado de idempotencia completado.

Si la misma petición se repite con la misma clave y el mismo contenido, Racoonity devuelve el resultado anterior sin ejecutar la operación otra vez.

Si se utiliza la misma clave con un contenido diferente, responde con un conflicto de idempotencia.

También existe demo.transaction_rollback, que realiza escrituras dentro de una transacción y después provoca un error controlado.

El resultado esperado es muy sencillo:

proof
+ outbox
+ error
→ rollback
→ cero escrituras durables

Y eso ya está demostrado contra PostgreSQL real.

No solo funciona en el camino feliz

Una parte importante del trabajo fue evitar que las pruebas validaran únicamente escenarios cómodos y secuenciales.

La implementación incluye pruebas de concurrencia con varias peticiones intentando utilizar simultáneamente la misma clave de idempotencia.

El resultado durable sigue siendo uno:

varias peticiones
→ una operación
→ un proof
→ un evento
→ un resultado idempotente

También se verificaron:

  • PostgreSQL no disponible.
  • Payload inválido.
  • JSON malformado.
  • Body demasiado grande.
  • Capability inexistente.
  • Permiso denegado.
  • Error interno desconocido.
  • Panic dentro de un handler.
  • Módulo demo deshabilitado.
  • Fallo de outbox.
  • Rollback posterior a una reserva idempotente.
  • Shutdown del servidor.

La intención no era conseguir una cantidad enorme de tests, sino demostrar las garantías que la arquitectura promete.

Las fronteras también se prueban

Uno de los resultados que más valoro de esta iteración es que varias decisiones arquitectónicas ya no dependen solamente de disciplina humana.

Ahora existen pruebas que inspeccionan los imports del código y protegen reglas como:

platform no depende de infraestructura
Dispatcher no depende de módulos concretos
HTTP no conoce repositories
los módulos no dependen de HTTP
Foreman no depende de pgx
la infraestructura global no conoce tablas privadas de demo

También se verifica que todavía no existan engines futuros activos, workers de outbox, consumers o mecanismos que quedaron expresamente fuera de I0.

Esto no vuelve imposible romper la arquitectura.

Pero sí vuelve mucho más difícil hacerlo accidentalmente y descubrirlo seis meses después.

La documentación también forma parte del resultado

El cierre de I0 no consistió solamente en ver todos los tests en verde.

Se preparó una guía para reproducir el recorrido completo:

base limpia
→ migraciones
→ arranque
→ liveness
→ readiness
→ queries
→ commit
→ replay
→ conflict
→ rollback
→ verificación SQL
→ shutdown

Los comandos documentados fueron ejecutados realmente.

La instalación limpia, las migraciones up, status y down, el modo productivo con demo deshabilitado y la validación estricta de OpenSpec también fueron verificados.

Esto puede parecer trabajo secundario cuando uno solamente quiere seguir programando.

Sin embargo, una arquitectura que solo puede ejecutar correctamente quien la construyó todavía no está terminada.

Algunas reflexiones

Diseñar primero no eliminó el trabajo

OpenSpec no escribió el sistema por nosotros.

Tampoco evitó bugs, decisiones difíciles o revisiones.

Lo que sí hizo fue mantener una conversación estable entre intención e implementación.

Cuando aparecía una duda, no teníamos que resolverla improvisando desde cero. Podíamos regresar a la propuesta, al diseño, a los escenarios y a las tareas.

La documentación no sustituyó el desarrollo.

Redujo la cantidad de desarrollo accidental.

La infraestructura necesita una demostración

Crear un Transaction Manager no era suficiente.

Había que demostrar un commit y un rollback.

Crear una outbox no era suficiente.

Había que demostrar que participaba en la misma transacción.

Crear idempotencia no era suficiente.

Había que demostrar replay, conflicto y concurrencia.

Esta idea probablemente seguirá guiando las siguientes iteraciones:

Toda pieza invisible debe sostener una capacidad visible o una garantía verificable.

Las abstracciones deben ganarse su lugar

Durante I0 fue tentador preparar versiones completas de motores que Racoonity utilizará mucho después.

Workflows, plugins, metadata dinámica, consumers y otros mecanismos ya tienen un lugar conceptual dentro de la visión.

Pero todavía no tienen un lugar dentro del runtime.

Mantenerlos afuera también fue una decisión arquitectónica.

Diseñar para evolucionar no significa construir anticipadamente todo el futuro.

Significa evitar decisiones que lo vuelvan innecesariamente doloroso cuando llegue.

La IA acelera, pero no decide el producto

Gran parte de la implementación fue realizada con ayuda de herramientas de inteligencia artificial.

Sin embargo, los resultados más importantes no provinieron de pedir simplemente “construye una API”.

Provinieron de definir:

  • Qué debía existir.
  • Qué no debía existir.
  • Quién era propietario de cada responsabilidad.
  • Qué comportamiento debía demostrarse.
  • Qué imports estaban prohibidos.
  • Qué evidencia era necesaria para considerar una tarea terminada.

La IA puede escribir código con enorme velocidad.

Por eso mismo, una dirección clara se vuelve todavía más importante.

Sin límites, también puede construir con enorme velocidad la arquitectura equivocada.

¿Qué sigue?

El siguiente paso será I1: Abrir la tienda.

Ahí Racoonity dejará de ser únicamente un runtime técnico y comenzará a representar una instalación real:

instalación vacía
→ configuración inicial
→ compañía y sucursal
→ administrador
→ login
→ permisos
→ contexto operativo

Entrarán Identity, Organization y Permissions en sus primeras versiones reales.

También aparecerán nuevos problemas: passwords, sesiones, inicialización única, contexto organizacional y protección del último administrador.

Pero esos problemas ya no comenzarán sobre una carpeta vacía.

Comenzarán sobre una foundation que puede arrancar, validar, confirmar, revertir y demostrar sus propias fronteras.

Conclusión

Antes de establish-runtime-foundation, Racoonity era principalmente una arquitectura planeada.

Después del cambio, sigue sin ser un ERP.

No tiene productos, ventas, inventario ni una interfaz comercial.

Pero ya posee algo que antes no tenía:

un lugar estable donde esas cosas pueden comenzar a existir.

Racoonity ya puede recibir una intención, encontrar quién debe atenderla, validar su forma, ejecutar una operación, confirmar o revertir sus efectos y dejar evidencia de lo ocurrido.

Todavía queda una ciudad entera por construir.

Pero el primer mapache ya encendió la luz.