Workflows — Reglas oficiales
Reglas fundamentales del sistema de Workflows y Automatizaciones de BoostCRM. Toda implementacion (backend, frontend, seeds, tests) debe cumplir estas reglas el 100% de las veces. No son sugerencias — son invariantes del sistema.
Modelo conceptual
Section titled “Modelo conceptual”Workflow (scoped a entity_id) ├── Trigger (entry point — crea la ejecucion) └── Steps (ordenados) ├── Step 1: entry point del flujo (el trigger lo activa) └── Steps 2+: alcanzados por actions terminales └── Actions (secuenciales dentro del step) ├── No-terminales: enviar, asignar, consultar, pausar └── Terminal (ultima): flow.end, flow.goto_step, flow.condition, flow.evaluate_replyUn workflow se activa por un trigger que crea la ejecucion, ejecuta actions en cada step, y puede ramificarse con actions terminales que transfieren a otros steps.
Nota conceptual: el trigger es logicamente del workflow, no del step. Es el mecanismo que crea la ejecucion — no ejecuta actions ni pertenece a la secuencia de un step. En la implementacion vive asociado al Step 1 por simplicidad de modelo de datos, pero conceptualmente el trigger es del workflow y el Step 1 es el primer step que ejecuta actions.
Reglas generales (G)
Section titled “Reglas generales (G)”G1 — No duplicar logica
Section titled “G1 — No duplicar logica”Si algo ya existe como servicio en el backend (asignar vendedor, enviar mensaje, crear evento), el action lo invoca, no lo reimplementa.
Razon: Mantenibilidad. Un bug se arregla en un solo lugar.
G2 — Todo workflow pertenece a una entity_id
Section titled “G2 — Todo workflow pertenece a una entity_id”No existen workflows globales. Todo workflow esta scoped a una entity.
Razon: Consistencia con el modelo multi-tenant actual.
G3 — Un contacto puede estar en multiples workflows pero no en dos ejecuciones del mismo workflow
Section titled “G3 — Un contacto puede estar en multiples workflows pero no en dos ejecuciones del mismo workflow”Un contacto puede tener activos un flujo de seguimiento y uno de calificacion al mismo tiempo. Pero no puede estar ejecutando dos instancias del mismo workflow.
Razon: Evita spam y loops, pero permite flexibilidad de automatizacion.
G4 — Contexto de ejecucion
Section titled “G4 — Contexto de ejecucion”Cada ejecucion tiene un context_json que viaja por TODA la ejecucion.
Es acumulativo — nunca se reinicia entre steps. Contiene:
- Datos del trigger (contexto inicial)
- Resultados de actions previos (context enrichment)
- Respuestas del contacto (reply data)
- Datos de consultas externas (Zauru, namespaced)
Las actions leen y enriquecen este contexto. Nunca lo reemplazan completo.
Razon: Permite encadenar actions. Ejemplo:
zauru.read_invoices agrega context.zauru.recent_invoices para que
flow.condition lo evalue y comms.send_template lo use en variables.
G5 — Si un workflow falla, se pausa
Section titled “G5 — Si un workflow falla, se pausa”Nunca se pierde. Se marca status: paused_error con el log del error,
y un admin puede retomar o cancelar.
Razon: No queremos perdida silenciosa de ejecuciones.
G6 — Un workflow JAMAS puede afectar a otra entity
Section titled “G6 — Un workflow JAMAS puede afectar a otra entity”Un workflow de entity A no puede enviar mensajes, asignar vendedores, consultar datos ni ejecutar acciones sobre entity B. Esto aplica tambien para superadmins:
- Si un superadmin esta en entity A y crea un workflow, ese workflow es de entity A y solo opera sobre entity A.
- Si el superadmin cambia a entity B, los workflows que cree ahi son de entity B.
- El
WorkflowAuthServicesiempre resuelve el auth con elentity_iddel workflow, no con el del usuario actual. - Los servicios internos (InteractionsService, RecordAssignmentsService,
GroupInvoicesService) ya validan
entity_iden todas sus queries.
Razon: Aislamiento multi-tenant. Un error de configuracion en una entity nunca puede causar dano en otra. Esto es un invariante de seguridad, no solo una conveniencia.
Reglas de triggers (T)
Section titled “Reglas de triggers (T)”T1 — Nunca triggers de categoria Zauru
Section titled “T1 — Nunca triggers de categoria Zauru”Para consultar datos de Zauru, usar un trigger programado (scheduled)
combinado con actions de Zauru que consulten los datos.
Razon: Zauru no emite webhooks. Pollear como trigger es fragil y caro. Mejor controlamos nosotros cuando consultar.
T2 — Solo un trigger por workflow
Section titled “T2 — Solo un trigger por workflow”El Step 1 tiene exactamente un trigger. No combinaciones AND/OR de triggers. Si necesitas dos triggers diferentes, son dos workflows diferentes.
Razon: Simplifica la UX y el engine.
T3 — Al crear un trigger, debe existir al menos un action en el mismo step
Section titled “T3 — Al crear un trigger, debe existir al menos un action en el mismo step”Un trigger sin accion no tiene sentido. El sistema lo valida al guardar.
Razon: Prevencion de configuraciones invalidas.
T4 — Los triggers solo detectan, no transforman
Section titled “T4 — Los triggers solo detectan, no transforman”Un trigger pone datos en el contexto (quien escribio, de que canal, metadata del evento) pero no ejecuta logica ni modifica datos.
Razon: Separacion clara: trigger = evento, action = reaccion.
T5 — Los triggers programados deben definir hora y zona horaria
Section titled “T5 — Los triggers programados deben definir hora y zona horaria”Siempre se ejecutan en la timezone de la entity, no UTC.
Razon: Evita confusiones de “a las 8am” que corren a las 2am.
T6 — First-match wins para triggers de mensajes
Section titled “T6 — First-match wins para triggers de mensajes”Un trigger message.inbound solo matchea mensajes que NO estan siendo
procesados por otro workflow. El primer workflow que matchea (por prioridad
definida por el usuario) gana.
Razon: Evita que un mismo mensaje dispare 5 workflows. El usuario define prioridad.
Pipeline de mensaje inbound (T6 + A12 unificados)
Section titled “Pipeline de mensaje inbound (T6 + A12 unificados)”Cuando llega un mensaje de un contacto, el engine ejecuta este pipeline en orden estricto. Un mensaje SOLO puede ser consumido por UN destino.
Llega mensaje inbound de contacto+chat │ ▼ 1. ¿Existe ejecucion en estado `waiting_for_reply` para este contacto+chat? │ ├── SI → reanudar esa ejecucion (A12) │ El mensaje se consume. FIN. │ ▼ 2. Evaluar workflows activos por prioridad (la prioridad la define el usuario en la UI) │ ▼ 3. Para cada workflow (de mayor a menor prioridad): │ ├── ¿El FilterEngine matchea? (evento + filtros) │ │ │ ├── SI → crear nueva ejecucion (T6) │ │ El mensaje se consume. FIN. │ │ │ └── NO → siguiente workflow │ ▼ 4. Ningun workflow matcheo → mensaje no dispara nada. (El mensaje se recibe normal en InteractionsService, sin ejecucion de workflow)Reglas del pipeline:
- Un mensaje = un destino. Nunca dispara dos workflows ni reanuda y dispara al mismo tiempo.
- waiting_for_reply siempre gana sobre triggers nuevos (A12). La ejecucion activa tiene prioridad absoluta.
- La prioridad es por entity. Cada entity ordena sus workflows. El primer match gana (T6).
- Si no hay match, no pasa nada. El mensaje existe en el sistema de interacciones pero no genera ejecucion de workflow.
Reglas de steps (S)
Section titled “Reglas de steps (S)”S1 — Step 1 SIEMPRE tiene exactamente un trigger
Section titled “S1 — Step 1 SIEMPRE tiene exactamente un trigger”Es el unico entry point del workflow. No hay otra forma de iniciar una ejecucion.
S2 — Steps 2+ NUNCA tienen trigger
Section titled “S2 — Steps 2+ NUNCA tienen trigger”Solo se alcanzan por actions terminales de otro step. Poner un trigger en Step 2+ es un error de configuracion que el sistema rechaza.
S3 — Steps 2+ se alcanzan SOLO por actions terminales
Section titled “S3 — Steps 2+ se alcanzan SOLO por actions terminales”Las unicas formas de llegar a otro step son:
flow.goto_step(transfer directo)flow.condition(branching true/false)flow.evaluate_reply(branching por respuesta)
No existe “next_step automatico”. Cada step debe terminar explicitamente.
S4 — Cada step DEBE terminar con exactamente una action terminal
Section titled “S4 — Cada step DEBE terminar con exactamente una action terminal”La ultima action de un step debe ser una action terminal:
flow.end, flow.goto_step, flow.condition, o flow.evaluate_reply.
Si un step no tiene action terminal, el sistema rechaza la configuracion.
Razon: Elimina ambiguedad de “que pasa despues”. Siempre esta explicito.
S5 — Actions dentro de un step ejecutan secuencialmente
Section titled “S5 — Actions dentro de un step ejecutan secuencialmente”Misma regla que A4 aplicada a nivel de step. No hay ejecucion paralela.
S6 — Pausas ocurren DENTRO del mismo step
Section titled “S6 — Pausas ocurren DENTRO del mismo step”response_policy.await_reply, flow.wait_for_reply y flow.delay pausan la ejecucion
pero NO transfieren a otro step. Cuando la pausa termina, la siguiente
action del MISMO step continua.
Reglas de actions (A)
Section titled “Reglas de actions (A)”A1 — Toda action pertenece a exactamente una categoria
Section titled “A1 — Toda action pertenece a exactamente una categoria”Las categorias son: comunicacion (comms.*), flujo (flow.*),
crm (crm.*), notificaciones (notification.*), datos (zauru.*).
No puede existir un action sin categoria.
Razon: Organizacion para la UI y para validaciones.
A2 — Las actions de flujo no producen efecto lateral
Section titled “A2 — Las actions de flujo no producen efecto lateral”Solo controlan ejecucion: condicional, esperar, evaluar respuesta, ir a step, terminar. No envian mensajes, no crean records, no modifican datos.
Razon: Clara separacion entre “decidir/esperar” y “hacer”.
A3 — Las actions de comunicacion usan los servicios existentes de InteractionsModule
Section titled “A3 — Las actions de comunicacion usan los servicios existentes de InteractionsModule”Nunca llaman directo al API de Communications.
Razon: Reutiliza validacion de sesion, permisos, rate limiting ya implementados.
A4 — Las actions se ejecutan secuencialmente dentro de un step
Section titled “A4 — Las actions se ejecutan secuencialmente dentro de un step”Si una falla, las siguientes NO se ejecutan y el step se pausa con
status: paused_error.
Razon: Consistencia. No queremos medio-step ejecutado sin saber cual fallo.
A5 — flow.wait_for_reply y response_policy.await_reply SIEMPRE con timeout
Section titled “A5 — flow.wait_for_reply y response_policy.await_reply SIEMPRE con timeout”Minimo 1 hora, maximo 30 dias.
Razon: Evita ejecuciones zombie que esperan para siempre.
A6 — flow.delay tiene maximo 30 dias
Section titled “A6 — flow.delay tiene maximo 30 dias”Si necesitas mas de 30 dias, probablemente es otro workflow.
Razon: Pragmatismo y limpieza de ejecuciones.
A7 — Las actions de Zauru son solo de LECTURA para MVP
Section titled “A7 — Las actions de Zauru son solo de LECTURA para MVP”Consultar facturas, consultar ordenes. No crear ni aprobar. Cuando se habilite escritura post-MVP, se requiere validacion adicional y confirmacion explicita.
Razon: Reducir riesgo. Escritura en Zauru desde un workflow automatico puede ser destructivo.
A8 — Toda action recibe el context y puede enriquecerlo
Section titled “A8 — Toda action recibe el context y puede enriquecerlo”Cada action declara un output_schema que define que campos agrega
al contexto. Los datos de Zauru se guardan namespaced con output_key
bajo context.zauru.*.
Razon: Permite encadenar: leer facturas -> condicional (tiene facturas?) -> enviar template con datos de factura.
A9 — Limites para actions de datos externos (Zauru)
Section titled “A9 — Limites para actions de datos externos (Zauru)”| Limite | Valor | Razon |
|---|---|---|
| Max items por consulta | 100 | Evitar contexto gigante |
| Timeout por request | 15s | Zauru puede ser lento, no bloquear |
| Campos devueltos | Subset | Solo lo util, no todo el JSON de Zauru |
| Retry on failure | 1 | Un intento mas, despues paused_error |
A10 — Actions NUNCA crean ejecuciones nuevas
Section titled “A10 — Actions NUNCA crean ejecuciones nuevas”Solo los triggers crean ejecuciones. Todas las actions — incluyendo
flow.wait_for_reply y response_policy.await_reply — continuan una ejecucion existente
con el mismo execution_id y el mismo context_json.
Razon: Esta es la linea que separa triggers de actions. Ver seccion “Frontera Trigger vs Action”.
A11 — Pausas de espera son continuaciones, no triggers
Section titled “A11 — Pausas de espera son continuaciones, no triggers”response_policy.await_reply y flow.wait_for_reply son PAUSAS de una
ejecucion existente. Cuando llega un mensaje que las reanuda, NO es un
trigger nuevo — es la continuacion del mismo workflow, mismo execution_id,
mismo contexto.
Razon: Si fueran triggers, crearian ejecuciones nuevas y perderian el contexto acumulado. Las pausas mantienen todo el estado.
A12 — Ejecucion pausada tiene prioridad sobre triggers nuevos
Section titled “A12 — Ejecucion pausada tiene prioridad sobre triggers nuevos”Si un mensaje inbound llega y hay un workflow PAUSADO esperando respuesta de ese contacto+chat, ese mensaje REANUDA la ejecucion pausada. NO dispara el trigger de otro workflow para ese contacto+chat.
Razon: Si no, el wait_for_reply nunca recibiria respuestas porque los triggers se las “robarian”. La ejecucion activa siempre gana.
A13 — Actions de datos consultan activamente, triggers escuchan pasivamente
Section titled “A13 — Actions de datos consultan activamente, triggers escuchan pasivamente”Las actions de datos (zauru.*) CONSULTAN — el workflow decide cuando. Los triggers ESCUCHAN — el evento externo decide cuando. Esta distincion es la razon por la que Zauru es action y no trigger (T1).
Razon: El workflow tiene control sobre cuando consultar. Los triggers reaccionan a eventos que no controlamos.
A14 — Un contacto+chat solo puede tener UNA ejecucion en waiting_for_reply
Section titled “A14 — Un contacto+chat solo puede tener UNA ejecucion en waiting_for_reply”Si ya existe un workflow esperando respuesta de un contacto+chat,
otro workflow que intente entrar en waiting_for_reply para ese mismo
contacto+chat entra en queued_wait_conflict.
No es un error. Es un conflicto de recursos — el slot de espera esta ocupado. El workflow B no fallo, simplemente no puede esperar respuesta mientras el workflow A ya esta esperando.
Opciones para resolver:
- Esperar: cuando el workflow A consuma la respuesta y libere el slot, el workflow B puede reintentar (manual o automatico)
- Cancelar: un admin decide que el workflow B no es necesario
Razon: Evita ambiguedad de que workflow consume la respuesta.
Usar un estado explicito (queued_wait_conflict) en vez de paused_error
porque no es una excepcion tecnica — es una condicion esperada del sistema.
A15 — WorkflowAuthService resuelve el Auth para cada ejecucion
Section titled “A15 — WorkflowAuthService resuelve el Auth para cada ejecucion”Todos los servicios del backend requieren un objeto Auth con entity_id,
user_id, employee_id. Los workflows necesitan ejecutar estos servicios
sin depender de que un usuario este logueado.
WorkflowAuthService resuelve el Auth segun el tipo de trigger:
| Trigger | ¿Como se resuelve el Auth? |
|---|---|
manual |
Auth del usuario que hizo click (ya existe) |
message.inbound |
Auth del sistema para la entity del contacto |
scheduled |
Auth del sistema para la entity del workflow |
El “sistema auth” usa un workflow_system_user_id configurado por entity.
Este usuario tiene permisos admin para que los servicios internos
(como assertConversationVisibleToActor en InteractionsService)
no bloqueen la ejecucion.
Razon: Los workflows deben funcionar sin depender de que alguien este logueado. Un trigger programado a las 8am no tiene usuario activo.
A16 — Actions de Zauru usan un empleado API dedicado por entity
Section titled “A16 — Actions de Zauru usan un empleado API dedicado por entity”Cada entity que use actions zauru.* en workflows configura un empleado
“Boost API” creado exclusivamente en Zauru para ese entity.
- Cada entity tiene su propio empleado Zauru → su propia sesion JWT independiente
- El auto-refresh de JWT funciona normal (las credenciales/API key estan en DB)
- Si 30 entities ejecutan workflows a la misma hora, cada una usa su propio JWT sin cola ni conflictos
- Si un empleado real se va de la empresa, el workflow no se rompe
Un admin se logea UNA vez en Boost con las credenciales del empleado API de Zauru.
A partir de ahi, ZauruSessionService.resolveRuntimeGraphqlJwt() refresca
el JWT automaticamente con el API key guardado.
El workflow_zauru_user_id se configura por entity, no por workflow.
WorkflowAuthService lo usa cuando ejecuta actions con prefijo zauru.*.
Razon: Un solo empleado Zauru global crearia un cuello de botella secuencial — cada JWT de Zauru esta atado a una entity. Con un empleado por entity, hay paralelismo total entre entities.
Reglas de flujo entre steps (F)
Section titled “Reglas de flujo entre steps (F)”F1 — El Step 1 siempre es el entry point
Section titled “F1 — El Step 1 siempre es el entry point”No se puede saltar al Step 3 desde fuera. Punto de entrada unico, trigger unico.
F2 — Un step puede apuntar a cualquier step posterior O anterior
Section titled “F2 — Un step puede apuntar a cualquier step posterior O anterior”Esto permite loops (reintentos, “preguntale de nuevo”), pero con proteccion contra loops infinitos.
Mecanismo: step_visit_count
Cada ejecucion mantiene un contador de visitas por step:
{ "workflow": { "step_visits": { "step_1": 1, "step_2": 3, "step_bienvenida": 2 } }}Cuando flow.goto_step transfiere a un step:
- Incrementa
step_visits[target_step_id] - Si
step_visits[target_step_id] >= max_step_visits→paused_errorcon razon"max_step_visits_exceeded" - Si no, ejecuta el step normalmente
Configuracion:
max_step_visitsse configura por workflow. Default: 10.- El scope es por step individual, no por workflow ni por transicion.
- Ejemplo: un step puede visitarse 10 veces maximo en una sola ejecucion.
Cuando se usa flow.goto_step hacia un step anterior con skip_trigger: true,
se re-ejecutan las actions del step sin disparar el trigger.
Razon: Permite reintentos sin loops infinitos. El conteo por step es mas intuitivo que por transicion — “este step se ejecuto 10 veces” es una pregunta que un admin puede entender facilmente.
F3 — Sin action terminal explicita, el sistema rechaza el step
Section titled “F3 — Sin action terminal explicita, el sistema rechaza el step”A diferencia de antes, NO asumimos “si no hay next_step, termina”. Ahora todo step requiere action terminal explicita (S4).
F4 — Solo flow.condition y flow.evaluate_reply pueden generar branching
Section titled “F4 — Solo flow.condition y flow.evaluate_reply pueden generar branching”Son las unicas actions que pueden enviar la ejecucion a step A o step B. Las demas actions avanzan linealmente dentro del step. Estas actions DEBEN ser la ultima action del step (son terminales).
Razon: Claridad de que puede bifurcar y que no.
Frontera Trigger vs Action
Section titled “Frontera Trigger vs Action”Esta seccion define la linea que NUNCA se cruza.
La pregunta definitoria
Section titled “La pregunta definitoria”¿Crea una ejecucion nueva o continua una existente?
- Si CREA → es trigger.
- Si CONTINUA → es action.
Comparacion detallada
Section titled “Comparacion detallada”| Aspecto | Trigger | Action |
|---|---|---|
| ¿Crea ejecucion? | SI — nuevo execution_id | NO — mismo execution_id |
| ¿Genera contexto? | SI — desde cero | NO — enriquece el existente |
| Comportamiento | Listener PASIVO | Comando ACTIVO |
| ¿Quien decide cuando? | El evento externo | El workflow decide ejecutar |
| ¿Tiene timeout? | NO — espera indefinidamente | SI — timeout configurable |
| ¿Scope? | Todos los workflows que matcheen | UNA ejecucion especifica |
| ¿Donde vive? | Solo Step 1 | Cualquier step |
| FilterEngine | Decide SI arranca | Decide ADONDE va el flujo |
| ¿Sabe del contexto? | NO — lo crea | SI — lo lee y enriquece |
El caso de wait_for_reply
Section titled “El caso de wait_for_reply”wait_for_reply y response_policy.await_reply NO son triggers aunque “escuchen” mensajes:
- No crean ejecucion nueva — reanudan la existente
- Estan atados a un contacto+chat especifico — no matchean globalmente
- Tienen timeout — los triggers no
- El workflow DECIDIO pausarse — es un comando activo, no un listener pasivo
- Mantienen el contexto acumulado — un trigger lo crearia desde cero
Lo que NUNCA deberia existir
Section titled “Lo que NUNCA deberia existir”- Un action que cree una ejecucion nueva de otro workflow
- Un trigger en Step 2+
- Un action que genere contexto desde cero (siempre enriquece)
- Un trigger que modifique datos
- Un action que escuche eventos globales (solo su propia ejecucion)
Arquitectura de triggers — 3 capas
Section titled “Arquitectura de triggers — 3 capas”Ver documento dedicado: Workflows — Triggers
Resumen:
- Capa 1 — Eventos reales:
message.inbound,scheduled,manual - Capa 2 — FilterEngine universal: evalua
context[field] operator value - Capa 3 — Presets: tarjetas de UI que pre-llenan evento + filtros
Arquitectura de actions
Section titled “Arquitectura de actions”Ver documento dedicado: Workflows — Actions
Resumen:
- ActionRegistry + Handlers: cada action type tiene un handler con
execute(ctx, config) - TemplateEngine: resuelve
{{variables}}contra el contexto - FilterEngine (reutilizado):
flow.conditionyflow.evaluate_replyusan el mismo motor - 5 categorias UI: Comunicacion, CRM, Flujo, Tiempo/Esperas, Datos
Catalogo de actions (MVP)
Section titled “Catalogo de actions (MVP)”| Action | Codigo | Categoria | Terminal? |
|---|---|---|---|
| Enviar mensaje | comms.send_message |
Comunicacion | No |
| Enviar plantilla WA | comms.send_template |
Comunicacion | No |
| Enviar botones | comms.send_interactive |
Comunicacion | No |
| Condicion (if/else) | flow.condition |
Flujo | SI |
| Evaluar respuesta | flow.evaluate_reply |
Flujo | SI |
| Ir a step | flow.goto_step |
Flujo | SI |
| Finalizar workflow | flow.end |
Flujo | SI |
| Esperar tiempo | flow.delay |
Tiempo | No |
| Esperar respuesta | flow.wait_for_reply |
Tiempo | No |
| Asignar vendedor | crm.assign_seller |
CRM | No |
| Notificacion interna | notification.send_internal |
CRM | No |
| Buscar facturas | zauru.read_invoices |
Datos | No |
Catalogo de actions (post-MVP)
Section titled “Catalogo de actions (post-MVP)”| Action | Codigo | Categoria |
|---|---|---|
| Enviar lista interactiva | comms.send_list |
Comunicacion |
| Enviar email | comms.send_email |
Comunicacion |
| Agregar etiqueta | crm.add_tag |
CRM |
| Crear lead | crm.create_lead |
CRM |
| Mover oportunidad | crm.move_opportunity |
CRM |
| Actualizar campo | crm.update_field |
CRM |
| Iterar sobre lista | flow.for_each |
Flujo |
| Consultar productos | zauru.read_products |
Datos |
| Crear orden | zauru.create_order |
Datos |
| Webhook externo | integration.webhook |
Datos |
Convenciones
Section titled “Convenciones”- Eventos reales (engine):
dominio.accion(ej:message.inbound,lead.assigned) - Codigo de action:
categoria.verbo_sustantivo(ej:comms.send_template,flow.delay) - Categorias internas de actions:
comms,flow,crm,notification,zauru - Categorias UI de actions: Comunicacion, Flujo, Tiempo/Esperas, CRM, Datos
- Categorias UI de trigger presets: Mensajeria, Tiempo, Manual, CRM
- Actions terminales:
flow.end,flow.goto_step,flow.condition,flow.evaluate_reply - Estados de ejecucion:
running— ejecutando actionswaiting_for_reply— pausado esperando mensaje del contactowaiting_delay— pausado esperando que pase el tiempo (flow.delay)queued_wait_conflict— no puede esperar respuesta porque otro workflow ya ocupa el slot (A14). No es error.paused_error— fallo tecnico (API caido, Zauru timeout, etc). Reintentable.completed— workflow termino exitosamente (flow.end con status completed)cancelled— workflow cancelado (manual o flow.end con status cancelled)
- Filtros:
{ field, operator, value }— evaluados por el FilterEngine universal - Operadores MVP:
eq,neq,contains,not_contains,in,not_in,is_empty,is_not_empty,gt,gte,lt,lte
