diff --git a/tests/gtest_parallel.cpp b/tests/gtest_parallel.cpp
index 8dd8769c9..8cc35dd8a 100644
--- a/tests/gtest_parallel.cpp
+++ b/tests/gtest_parallel.cpp
@@ -591,3 +591,106 @@ TEST(Parallel, PauseWithRetry)
// the whole process should take about 300 milliseconds
ASSERT_LE(toMsec(t2 - t1) - 300, margin_msec * 2);
}
+
+// Issue #819: Demonstrates that Sequence does NOT re-evaluate conditions
+// while a sibling action is RUNNING, whereas ReactiveSequence DOES.
+// This is expected behavior, not a bug.
+TEST(Parallel, Issue819_SequenceVsReactiveSequence)
+{
+ using namespace BT;
+
+ // Test 1: Regular Sequence - condition NOT re-evaluated
+ {
+ static const char* xml_text = R"(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+)";
+ BehaviorTreeFactory factory;
+ std::array tick_counts = { 0, 0 };
+
+ // Register conditions that count their ticks
+ factory.registerSimpleCondition("TestCondition", [&](TreeNode& node) {
+ const std::string& name = node.name();
+ if(name == "cond1")
+ tick_counts[0]++;
+ else if(name == "cond2")
+ tick_counts[1]++;
+ return NodeStatus::SUCCESS;
+ });
+
+ auto tree = factory.createTreeFromText(xml_text);
+
+ // First tick: both conditions evaluated
+ auto status = tree.tickExactlyOnce();
+ ASSERT_EQ(NodeStatus::RUNNING, status);
+ ASSERT_EQ(1, tick_counts[0]); // cond1 ticked once
+ ASSERT_EQ(1, tick_counts[1]); // cond2 ticked once
+
+ // Second tick: conditions should NOT be re-evaluated (Sequence behavior)
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ status = tree.tickExactlyOnce();
+ ASSERT_EQ(NodeStatus::RUNNING, status);
+ // Conditions are NOT re-ticked because Sequence remembers current_child_idx_
+ ASSERT_EQ(1, tick_counts[0]); // Still 1 - NOT re-evaluated
+ ASSERT_EQ(1, tick_counts[1]); // Still 1 - NOT re-evaluated
+ }
+
+ // Test 2: ReactiveSequence - condition IS re-evaluated every tick
+ {
+ static const char* xml_text = R"(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+)";
+ BehaviorTreeFactory factory;
+ std::array tick_counts = { 0, 0 };
+
+ factory.registerSimpleCondition("TestCondition", [&](TreeNode& node) {
+ const std::string& name = node.name();
+ if(name == "cond1")
+ tick_counts[0]++;
+ else if(name == "cond2")
+ tick_counts[1]++;
+ return NodeStatus::SUCCESS;
+ });
+
+ auto tree = factory.createTreeFromText(xml_text);
+
+ // First tick
+ auto status = tree.tickExactlyOnce();
+ ASSERT_EQ(NodeStatus::RUNNING, status);
+ ASSERT_EQ(1, tick_counts[0]);
+ ASSERT_EQ(1, tick_counts[1]);
+
+ // Second tick: conditions SHOULD be re-evaluated (ReactiveSequence behavior)
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ status = tree.tickExactlyOnce();
+ ASSERT_EQ(NodeStatus::RUNNING, status);
+ // Conditions ARE re-ticked because ReactiveSequence always starts from index 0
+ ASSERT_EQ(2, tick_counts[0]); // Re-evaluated!
+ ASSERT_EQ(2, tick_counts[1]); // Re-evaluated!
+ }
+}