Spanda autonomous systems are trigger-driven. Sensors publish data, timers elapse, safety conditions change, state machines transition, and AI agents complete goals — each of these is a trigger that can invoke reactive handler code.
The unified trigger model extends existing Spanda primitives (event/on/emit, task every,
topics, state machines, safety) rather than replacing them.
Autonomous robots do not run a single linear program. They:
Triggers make this reactive structure a first-class language concept with shared registration, priority ordering, metrics, and scheduler integration.
| Category | Syntax | Status |
|---|---|---|
| Event | on ObstacleDetected { ... } |
Implemented |
| Message | on lidar_scan { ... } |
Implemented (dispatches on publish) |
| Timer | every 100ms { ... } |
Implemented |
| Condition (edge) | when expr { ... } |
Implemented (fires once when becoming true) |
| Condition (level) | while expr { ... } |
Implemented (fires each tick while true) |
| State | on state Entered(Navigating) { ... } |
Implemented |
| Safety | on safety EmergencyStop priority critical { ... } |
Implemented |
| Hardware | on hardware CameraFailure { ... } |
Implemented (monitor + fault injection) |
| AI | on ai GoalCompleted { ... } |
Implemented (plan complete, confidence) |
| Verification | on verification Failed / Warning { ... } |
Implemented |
| Digital Twin | on twin DivergenceDetected / FaultInjected { ... } |
Implemented |
| Transport inbound | subscribed topics on ROS2/MQTT/DDS/WebSocket | Implemented (polled each tick) |
event ObstacleDetected;
on ObstacleDetected {
wheels.stop();
}
behavior run() {
emit ObstacleDetected;
}
topic lidar_scan: Scan subscribe on "/scan";
on lidar_scan {
update_world_model();
}
Handlers fire when the topic is published (in-process via publish).
every 100ms {
publish_pose();
}
every 1s {
publish_status();
}
Timer triggers integrate with the deterministic scheduler (same base tick as multiplexed tasks).
when lidar.nearest_distance < 1.0 m {
stop();
}
The compiler validates that the condition expression is boolean. Conditions are edge-triggered (fire once when becoming true).
For continuous monitoring while a condition holds, use while:
while battery.level < 20% {
return_home();
}
Level triggers fire on each scheduler tick while the condition is true (subject to trigger storm limits).
verify {
true; // hard rule — failure stops execution
warning false; // soft rule — dispatches on verification Warning
}
on verification Failed {
block_deployment();
}
on verification Warning {
request_review();
}
Hardware triggers dispatch when simulate_compatibility faults are injected, sensor reads fail
repeatedly, or comm faults match sensor types:
simulate_compatibility { fault LidarFailure; }
on hardware LidarFailure {
enter_safe_mode();
}
on ai GoalCompleted {
notify_operator();
}
on ai ConfidenceLow {
request_human_review();
}
GoalCompleted fires after a successful agent.plan(). ConfidenceLow fires when
planner.reason() returns low confidence (derived from sensor context).
on twin DivergenceDetected {
create_alert();
}
on twin FaultInjected {
run_recovery();
}
Twin divergence is detected when mirrored shadow state diverges from live robot state beyond a
threshold. Fault injection via simulate_compatibility or comm faults dispatches FaultInjected.
state_machine Nav {
state Idle;
state Navigating;
transition Idle -> Navigating;
}
on state Entered(Navigating) {
start_navigation();
}
on state Exited(Navigating) {
cleanup();
}
on safety EmergencyStop priority critical {
stop_all_actuators();
}
Safety triggers use the same priority levels as tasks: critical, high, normal, low.
on safety EmergencyStop priority critical {
stop_all_actuators();
}
Critical triggers run before lower-priority handlers in the same dispatch cycle.
agent Vision {
on camera_frame {
process_frame();
}
}
Agent-scoped triggers register against declared topics or events.
All triggers register in a unified TriggerRegistry at robot setup:
emit dispatches synchronously (existing behavior, now via registry)publish invokes matching topic handlersenter invokes Entered/Exited handlersEventBus — backward compatible; events also register in TriggerRegistryCommBus — topic publish path invokes message triggersSafetyMonitor — emergency stop dispatches on safety EmergencyStopTriggerMetrics records executions, failures, missed deadlinesA per-tick dispatch limit (MAX_TRIGGERS_PER_TICK, default 64) prevents trigger storms from
overwhelming devices.
spanda run robot.sd --trace-triggers
spanda sim robot.sd --trace-events
RunResult.metrics.triggers contains per-handler execution counts, failures, and timing.
Trigger execution uses the same interpreter path in spanda run, spanda sim, and replay modes.
Timer triggers advance with simulation time.
examples/triggers_demo.sd — comprehensive trigger example