diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/AutomationRuleForm.vue b/app/javascript/dashboard/routes/dashboard/settings/automation/AutomationRuleForm.vue index 7f405f4d6..10fe92b9d 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/automation/AutomationRuleForm.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/automation/AutomationRuleForm.vue @@ -311,10 +311,12 @@ const resetToSupportedCondition = () => { ]; }; -// Turning on a delay narrows the condition options; reset only the conditions a delayed rule -// can't use (e.g. a mutable attribute) to a supported default. Actions are kept. -watch(isDelayed, delayed => { - if (!delayed || !automation.value) return; +// A delay narrows the condition options, so whenever the rule becomes unsupported while the +// wait is on — toggling it on, or switching to an event whose default condition isn't allowed +// (e.g. conversation_opened defaults to browser_language) — reset to a supported default. +// Actions are kept. Resetting makes the rule supported again, so this can't loop. +watch([isDelayed, isDelaySupported], () => { + if (!isDelayed.value || !automation.value) return; if (!isDelaySupported.value) resetToSupportedCondition(); }); diff --git a/app/models/automation_rule_pending_execution.rb b/app/models/automation_rule_pending_execution.rb index c0e2b5bd6..455312f64 100644 --- a/app/models/automation_rule_pending_execution.rb +++ b/app/models/automation_rule_pending_execution.rb @@ -62,7 +62,11 @@ class AutomationRulePendingExecution < ApplicationRecord return unless message && !message.incoming? row = find_by!(automation_rule_id: rule.id, conversation_id: conversation.id, episode_key: key) - row.update!(due_at: rule.execution_delay.minutes.since(anchor), message_id: message.id) if row.pending? + # Jobs can arrive out of order; only a newer reply moves the clock, so a late older reply + # can't pull due_at backwards and fire before the delay elapses since the latest reply. + return unless row.pending? && message.id > row.message_id + + row.update!(due_at: rule.execution_delay.minutes.since(anchor), message_id: message.id) end # The wait is measured from when the qualifying event happened, not when this (possibly