ForceSuccess의 Running 통과 규칙 (ForceSuccess's Running Pass-Through Rule)

ForceSuccess의 Running 통과 규칙 (ForceSuccess’s Running Pass-Through Rule)

1. 개요

ForceSuccess 데코레이터의 Running 통과 규칙은 자식 노드가 RUNNING 상태를 반환할 때, ForceSuccess가 이를 변환하지 않고 그대로 부모 노드에 전달하는 규칙이다. 이 규칙은 모든 반환 상태 변환 데코레이터에 공통으로 적용되는 원칙이며, 비동기 실행의 정합성을 보장한다.

2. 규칙의 정의

f_{\text{ForceSuccess}}(\text{RUNNING}) = \text{RUNNING}

ForceSuccess는 SUCCESSFAILURE를 모두 SUCCESS로 변환하나, RUNNING은 예외적으로 변환하지 않는다.

RUNNING 통과가 필요한 이유

비동기 행동의 실행 추적

ForceSuccess가 RUNNINGSUCCESS로 변환하면, 자식의 비동기 행동이 아직 진행 중임에도 불구하고 완료된 것으로 인식된다.

[올바른 동작]
Tick 1: Child=RUNNING → ForceSuccess=RUNNING → 부모가 대기
Tick 2: Child=RUNNING → ForceSuccess=RUNNING → 부모가 대기
Tick 3: Child=FAILURE → ForceSuccess=SUCCESS → 부모가 다음으로 진행

[잘못된 동작 (RUNNING 변환 시)]
Tick 1: Child=RUNNING → ForceSuccess=SUCCESS → 부모가 즉시 다음으로 진행
         (Child는 여전히 실행 중이나 아무도 tick하지 않음)

halt 전파의 정합성

RUNNING 상태가 SUCCESS로 변환되면, 부모 노드가 자식의 실행 완료를 인식하여 halt를 호출하지 않는다. 자식이 보유한 리소스(서비스 연결, 액션 서버 목표 등)가 해제되지 않아 리소스 누수가 발생한다.

시간적 동작 흐름

ForceSuccess가 적용된 비동기 액션의 tick 흐름은 다음과 같다.

Tick N:   Action 시작 → RUNNING → ForceSuccess → RUNNING
Tick N+1: Action 진행 → RUNNING → ForceSuccess → RUNNING
Tick N+2: Action 진행 → RUNNING → ForceSuccess → RUNNING
Tick N+3: Action 완료 → FAILURE → ForceSuccess → SUCCESS

자식이 최종적으로 FAILURE를 반환하는 시점에서만 ForceSuccess의 FAILURE→SUCCESS 변환이 적용된다. 실행 중에는 RUNNING이 그대로 전파된다.

Sequence에서의 효과

<Sequence>
    <ForceSuccess>
        <Action ID="LongRunningOptionalTask"/>
    </ForceSuccess>
    <Action ID="NextStep"/>
</Sequence>

LongRunningOptionalTaskRUNNING 동안에는 NextStep이 실행되지 않는다. 태스크가 최종적으로 SUCCESS 또는 FAILURE를 반환할 때, ForceSuccess가 SUCCESS를 반환하고 NextStep이 시작된다.

조건 노드에 대한 ForceSuccess

조건 노드는 RUNNING을 반환하지 않으므로, ForceSuccess의 Running 통과 규칙이 발동되지 않는다. 조건 노드에 적용된 ForceSuccess는 항상 SUCCESS를 반환하므로, 조건의 의미가 완전히 무력화된다.

<!-- 무의미한 사용: 항상 SUCCESS -->
<ForceSuccess>
    <Condition ID="AnyCondition"/>
</ForceSuccess>

이 패턴은 일반적으로 설계 오류이다.

설계 시 고려 사항

비동기 행동에 대한 ForceSuccess의 올바른 사용

ForceSuccess를 비동기 액션에 적용할 때, 액션이 완료될 때까지 대기하고 최종 결과만 변환하는 것이 올바른 동작이다. 중간의 RUNNING 상태를 변환하지 않음으로써 이 동작이 보장된다.

ForceSuccess와 Timeout의 결합

비동기 행동에 ForceSuccess만 적용하면, 행동이 무한히 RUNNING을 반환하는 경우 전체 시퀀스가 영원히 대기할 수 있다. Timeout과 결합하여 실행 시간을 제한하는 것이 안전하다.

<ForceSuccess>
    <Timeout msec="10000">
        <Action ID="OptionalLongTask"/>
    </Timeout>
</ForceSuccess>

10초 이내에 완료되지 않으면 Timeout이 FAILURE를 반환하고, ForceSuccess가 이를 SUCCESS로 변환한다.

참고 문헌

  • Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
  • BehaviorTree.CPP 공식 문서. https://www.behaviortree.dev/

버전날짜변경 사항
v0.12026-04-04초안 작성