En producción no puedes conectar un depurador
Un depurador muestra una operación desde dentro — pero en producción no puedes conectar uno, y una ejecución en vivo no ofrece nada a lo que aferrarse.
Durante el desarrollo, un depurador congela la ejecución en cualquier paso: ves los argumentos, los valores intermedios y lo que se pasará más adelante. En producción eso es imposible — no puedes detener el proceso por una sola solicitud, y una entrada poco frecuente es difícil de reproducir. Tampoco puedes observar una ejecución sobre la marcha: la cadena de llamadas vive en la pila de llamadas, sus valores intermedios en variables locales, y en cuanto una llamada retorna, todo eso desaparece. Los logs conservan solo valores elegidos de antemano; un trace técnico ve las llamadas y su duración, pero no sabe cuáles de ellas son pasos de negocio ni qué valores intermedios entre ellas importan. La causa hay que adivinarla a partir de pistas indirectas.
Los datos existen en tiempo de ejecución — un depurador lo demuestra. Lo que falta es otra cosa: una frontera, conocida de antemano, alrededor de la ejecución y de cada uno de sus pasos, a la que poder conectar una observación online — sin detener el proceso.
{ validated_items: 3 } · todos los valores visiblespausa en cualquier paso — se ve todo el state
no se puede detener — la parte intermedia no se ve
Las fronteras de la ejecución ya las fija la arquitectura
Para observar una ejecución como un todo, necesita una frontera precisa — y cada uno de sus pasos también.
En AOA, una operación es un Action con una frontera externa Params → Result. La ejecuta la máquina — el motor de AOA que ejecuta un Action y sabe de antemano dónde comienza y termina la ejecución. Dentro, el camino se divide en Aspects, cada uno con su propio state intermedio, state. Un Aspect recibe un snapshot del state anterior y devuelve el suyo, nuevo — que reemplaza por completo el state anterior en lugar de ampliarlo. Por eso, todo lo que necesitan los pasos siguientes lo transmite el Aspect de forma explícita, y nada se filtra entre pasos por sí solo; @result_* comprueba la salida justo en la frontera. Estas fronteras no son una herramienta de observación, sino la estructura misma de la operación; y, sin embargo, son exactamente lo que da los puntos conocidos de antemano donde se ven la entrada, la salida y el state de cada paso.
En cualquier momento la máquina conoce el marco de la ejecución y todo su recorrido contractual: qué entró en cada Aspect y qué state salió. El artefacto observable «una sola ejecución» ya lo ensambla la propia arquitectura — solo queda dejarlo salir.
{ }{ validated_items: 3 }{ validated_items: 3 }{ …, reservation_id: 'res_42' }{ …, reservation_id: 'res_42' }{ …, payment_id: 'pay_91' }Depuración online: una ejecución en vivo vista desde fuera
Como las fronteras son conocidas, la máquina emite un evento en cada una — y un observador externo los ensambla en una imagen en vivo de la ejecución.
En la frontera externa ves los Params y el Result reales; en cada una interna, el state entrante y saliente, la duración y cualquier error. La máquina conoce todos estos puntos y emite automáticamente lifecycle events; un plugin los recibe desde fuera y construye una proyección online de una ejecución concreta — un árbol de pasos con entradas, salidas, errores y tiempos reales. Igual en desarrollo, en tests y en producción — sin llamadas de logging, temporizadores manuales ni código de tracing dentro de los métodos de negocio.
Esto no es un depurador conectado ni un proceso detenido, sino su proyección online segura. El observador ve solo lo que el contrato permite: los campos sensibles permanecen opaque, y un fallo del propio plugin queda aislado y no cambia el resultado de la operación. Esto es exactamente lo que es Action X-Ray.
- start · Params
- validate · state → state′ · 0.4 ms
- reserve · state′ → state″ · 12 msopaque
- charge · error · 3 ms
- finish · Result · 15 ms
El plugin se entrega a la máquina en la creación — los métodos de negocio quedan intactos:
plugin = OpenTelemetryPlugin( tracer_provider=tracer_provider, logger_provider=logger_provider, service_name="checkout-service",)# The plugin lives outside the Action; business methods stay untouched.machine = ActionProductMachine(plugins=[plugin])result = await machine.run(Context(), CreateOrderAction(), params)En un test — la misma radiografía
El mismo snapshot online está disponible también en un test: TestBench ejecuta la misma operación a través de la misma máquina.
TestBench no crea una visibilidad especial solo para tests — ejecuta el mismo Action a través de la misma máquina y las mismas fronteras. Solo cambia el mundo exterior: en lugar del Context, los Resources y el gateway de producción se usan sus implementaciones de test, mientras que los roles, el pipeline, los checkers y el ensamblaje del Result siguen siendo reales. La operación puede ejecutarse por completo o detenerse en una sola frontera — un Aspect, summary o compensator — sin ganchos especiales en el código de negocio.
Un test verifica la misma proyección que está disponible en producción: no solo el Result final, sino cualquier state intermedio. Lo que cambia es la realidad alrededor de la operación, no la operación en sí ni la forma de observarla.
roles · pipeline · checkers · ensamblaje de Resultuna y la misma proyección onlineEl mismo Action a través de TestBench — por completo o en una sola frontera:
inventory = AsyncMock(spec=InventoryGateway)inventory.reserve.return_value = "res_42"bench = TestBench().with_user( user_id="customer", roles=(CustomerRole,)).with_mocks({InventoryGateway: inventory})# The whole operation — same machine, same boundariesresult = await bench.run(CreateOrderAction(), params, rollup=False)# Or stop at a single boundary and inspect its statestate_after = await bench.run_aspect( CreateOrderAction(), "reserve_aspect", params=params, state={"validated_items": 3},)assert state_after["reservation_id"] == "res_42"La depuración online se convierte en una propiedad de la arquitectura
AOA fija la frontera externa de un Action, las fronteras internas de sus Aspects y convierte el state intermedio en un contrato. Durante una ejecución, esas mismas fronteras se convierten en el sistema de coordenadas de los lifecycle events — y la visibilidad que antes aparecía solo bajo un depurador o tras una instrumentación manual ahora está disponible online para cada ejecución, incluida la de producción, sin código de infraestructura dentro de la operación.
