SOP Fan-In: Resumen
Un fan-in es una fuente de eventos externa que inicia ejecuciones de SOP. Cada fuente entrega eventos al motor de SOP a través de dispatch_sop_event, que compara cada evento con los desencadenadores de cada SOP cargado e inicia ejecuciones para los que coinciden.
Una instancia de ZeroClaw puede enlazar varias entradas al mismo tiempo: un tema MQTT, una ruta del sistema de archivos y una clave de enrutamiento AMQP pueden alimentar el mismo motor sin procesos separados. Cada origen tiene una guía dedicada a continuación.
Cómo funciona dispatch
- Una ruta de matcher: un solo matcher evalúa cada tipo de trigger, por lo que el matching se comporta igual independientemente del origen.
- Auditoría de inicio de ejecución: las ejecuciones iniciadas se persisten mediante
SopAuditLogger. - Ejecución headless: los disparadores cron y las entregas de webhook llevan sus ejecuciones hasta completarse. El tick de mantenimiento entrega cada
ExecuteStepoDeterministicStepde cron que se haya iniciado al controlador de ejecución headless, y la ruta de webhook entrega cadaExecuteStepiniciado a ese mismo controlador (el dispatch ya ejecuta los pasos deterministas). El controlador ejecuta el paso como el propio agente del SOP. Las fuentes que todavía no tienen un controlador activo registran las acciones deExecuteStepcomo pendientes medianteprocess_headless_results, en lugar de ejecutarlas. - Propiedad en modo headless: un paso headless se ejecuta como el agente indicado en
agentdel paso; si no lo tiene, se usa elagentdel SOP. Ese agente debe estar configurado y habilitado. No existe un turno de agente ambiental del que heredar una identidad, por lo que un procedimiento sin propietario se rechaza en el momento de la creación y se deniega al despacharlo; nunca se ejecuta como otro agente configurado. Un SOP manual es el único caso que se guarda sin propietario, porquesop_executeproporciona uno; el endpoint de ejecución del panel, que no tiene un agente detrás, se niega a iniciar dicho procedimiento. - Alcance de herramientas en modo headless: un turno headless de un paso se restringe exactamente igual que un turno en vivo: las herramientas de control del SOP (
sop_execute,sop_advance,sop_approve) siempre se eliminan para que un paso no pueda dirigir su propia ejecución, y elscopedeclarado del paso se aplica además cuandosop.step_scope_enforceestá activado. Un agente hijo generado desde el paso hereda las mismas exclusiones. - Entrada no confiable: el texto del tema y del payload están limitados, normalizados, filtrados por prompt-guard y enmarcados antes de llegar al contexto del modelo.
Fuentes
Cada tipo de desencadenador SOP, sus campos y su estado de envío, proyectados directamente desde el registro SopTrigger:
| Tipo | Campos | Notas |
|---|---|---|
mqtt | topic, condition opcional | Llegada de mensajes MQTT. En vivo: entregado por el listener de MQTT. |
webhook | path | Solicitud HTTP entrante. En producción: rutas de gateway /sop/* y rutas /webhook con prioridad SOP. |
cron | expression | Disparo basado en tiempo. En vivo: enviado por el tick de mantenimiento SOP (rutas daemon / channel-start). |
peripheral | board, signal, condition opcional | Señal de hardware. Definida y coincidente, pero ningún oyente periférico la alimenta. |
filesystem | path, opcional condition, opcional events | Cambio en Filesystem. En vivo: entregado por el monitor de Filesystem. |
calendar | calendar_source, opcional calendar_ids, opcional condition | Estado del evento del calendario. Definido y emparejado, pero ningún sondeador lo alimenta en vivo. |
channel | channel, opcional alias, opcional condition | Mensaje entrante o evento de plataforma de forge en un canal configurado (telegram, discord, slack, Git, …). En vivo: entregado por el orquestador del canal cuando el despacho SOP del canal está habilitado. El productor de forge de Git establece un tema de evento de la forma <channel>.<alias>:<event_type> y coloca event_type en la carga útil, de modo que una condition redactada filtra eventos de forge por tipo sin una segunda forma de activación. |
manual | ninguno | Ejecución iniciada por el agente mediante la herramienta sop_execute. No es una fan-in externa. |
amqp | routing_key, condition opcional | AMQP delivery. Live: entregado por el consumidor AMQP en un modo de despacho SOP. |
Cada fuente tiene una guía dedicada en la barra lateral. Las fuentes en vivo (entregadas por un listener en ejecución o una solicitud autenticada a la puerta de enlace) inician ejecuciones a medida que llegan los eventos; los activadores de cron se despachan mediante el ciclo periódico de mantenimiento de SOP del demonio; las ejecuciones iniciadas por agentes comienzan desde dentro de un turno del agente mediante sop_execute; las fuentes restantes definidas pero no conectadas (periféricos y calendario) validan y coinciden, pero todavía no tienen ninguna fuente de eventos en vivo que se enrute al despachador.
Valores predeterminados de seguridad
| Preocupación | Mecanismo |
|---|---|
| Autenticación de webhook | Autenticación bearer para el emparejamiento de Gateway, además de gateway.webhook_secret/X-Webhook-Secret opcional; /sop/* y /webhook comparten el mismo limitador de velocidad. Se debe configurar al menos un control para el envío de SOP, y todos los controles configurados deben superar la validación. Los secretos de alias independientes de [channels.webhook] nunca autorizan estas rutas |
| Protección contra ataques de repetición de webhooks | X-Idempotency-Key opcional, con un espacio de nombres por ruta SOP y con espacios de nombres independientes para /sop/* y /webhook. Las claves se reservan antes del despacho e indican que se hará como máximo un intento, no que se haya iniciado una ejecución anterior. |
| Transporte MQTT | mqtts:// con use_tls = true para transporte TLS |
| Raíces del Filesystem | Las raíces amplias (/, /home, /etc, /var, /proc, /sys, /dev, /tmp) se rechazan en la validación de la configuración a menos que allow_broad_roots; los globos de inclusión/exclusión delimitan los eventos |
| Filesystem symlinks | Las rutas de eventos de symlink se rechazan antes de leer cualquier metadato, hash o contenido de forma predeterminada; follow_symlinks = true habilita esta opción, pero aún requiere que el destino canónico resuelva dentro de una raíz vigilada |
| Entrada de activación no confiable | El texto del tema y del payload están limitados, normalizados, filtrados por prompt-guard y enmarcados antes del contexto del modelo |
| Bloque de activación no seguro | untrusted_input_guard = "block" rechaza eventos no confiables inseguros con BlockedUnsafe; warn por defecto audita y permite |
| Validación de Cron | Las expresiones cron no válidas fallan de forma segura durante el análisis y la construcción de la caché |
| Propiedad sin interfaz gráfica | Un SOP headless debe declarar un agent propietario que esté configurado y enabled; la creación bloquea el guardado y el driver rechaza el paso en lugar de tomar prestado otro agente configurado. Una ejecución manual iniciada desde el dashboard se rechaza de la misma manera. |
| Ámbito de la herramienta sin interfaz | Los turnos headless de cada paso siempre excluyen las herramientas de control del SOP y respetan el scope declarado por el paso bajo step_scope_enforce; los agentes secundarios generados desde el paso heredan esas exclusiones |
| Duración del controlador sin interfaz | Los drivers de cron y webhook pertenecen a la generación del daemon que los inició: primero se drenan (30 s) y luego se abortan y se unen (join, 5 s) antes de que una recarga reconstruya la configuración y el motor de SOP. Un driver que no alcanza ningún punto de await durante ese período de gracia sigue en ejecución y se traslada a la siguiente generación, y se registra en el log en lugar de desvincularse. |
| Despacho headless | Las fuentes sin un registro de ejecución activo muestran el progreso en lugar de ejecutar automáticamente ExecuteStep |
Solución de problemas
| Síntoma | Causa probable | Corregir |
|---|---|---|
| SOP nunca comienza a partir de una fuente en vivo | desajuste de patrón de activación o una condition fallida | Verifica que el patrón del desencadenador coincida con el evento entregado; comprueba la condition contra la carga útil |
| SOP se inició, pero un paso no se ejecutó | Un origen sin controlador activo (periférico, calendario) llegó a ExecuteStep | Usa cron, un webhook u otra fuente en vivo, ejecuta un bucle de agente para ExecuteStep o diseña la ejecución para que se pause en las aprobaciones |
| Inicio de SOP de cron; falla en cada ejecución con “no owning agent” | el procedimiento no declara ningún agent, y una ejecución headless no tiene ninguno del que heredar | Establezca agent en SOP.toml (o en el paso) con un alias de agente configurado |
| Cron SOP falla en cada ejecución con “which is disabled” | El agente propietario está configurado con enabled = false | Vuelve a habilitar el agente o apunta agent a uno que esté habilitado |
Botón de ejecución del panel devuelve 422 para un SOP manual | the procedure’s execute steps declare no owner, and a dashboard run has no agent turn to inherit one from | Configure agent en SOP.toml (o en el paso), o inicie el procedimiento desde un agente con sop_execute |
| Un paso de cron no puede llamar a una herramienta que usó de forma interactiva | la scope del paso lo excluye bajo step_scope_enforce, o es una herramienta de control de SOP | Amplía el scope del paso; las herramientas de control del SOP siguen excluidas por diseño |
| El desencadenador del webhook nunca se activa | discrepancia en la ruta exacta del desencadenador, subsistema SOP no disponible o autenticación rechazada | Ejecuta zeroclaw daemon con sop.sops_dir configurado, haz que coincida exactamente con la ruta completa de la solicitud y proporciona los encabezados bearer/secret configurados |
| El desencadenador de periférico o de calendario nunca se activa | fuente de eventos no conectada al despachador | Usa una fuente activa (Webhook, MQTT, Filesystem, AMQP) o inicia la ejecución con sop_execute |
| El desencadenador de Cron nunca se activa | el ciclo de mantenimiento no se está ejecutando (no se ejecuta zeroclaw daemon ni zeroclaw channel start; el comando independiente gateway start no lo ejecuta), sops_dir no está definido o está vacío, o maintenance_interval_secs = 0 | Ejecute zeroclaw daemon (o zeroclaw channel start) con sop.sops_dir establecido en un valor no vacío (sin establecer de forma predeterminada; el valor documentado es shared/sops) y sop.maintenance_interval_secs distinto de cero (predeterminado 60) |
Ver también
- Syntax: el formato completo de
SOP.tomlySOP.md - Cómo se ejecutan los SOPs
- Channels: Overview: el lado de transporte de MQTT, del sistema de archivos y de AMQP