To check which recovery branch ran, inspect the relevant nodes’ observed transitions and outcomes rather than only the tree’s final SUCCESS. Attach a TreeObserver before ticking, preserve the actual tree’s node identities, and compare statistics within a defined test case. The evidence concerns software control flow; it does not establish that a sensor was truthful or a physical recovery succeeded.
This guide uses the BehaviorTree.CPP 4.8 documentation and the 4.8.0 observer header, checked on October 15, 2026. The fixtures below are proposed tests. No tree was built, ticked or executed on a robot.
Start with two cases that could both finish successfully
Imagine a primary action with a local recovery and a later escalation path. In one proposed case, the primary action succeeds without recovery. In another, a controlled fixture makes it fail, local recovery changes the condition, and a subsequent primary action succeeds. Both cases can end in root SUCCESS, but the expected branch evidence differs.
Choose expectations before running either case. Identify the primary action, local recovery, control nodes connecting them and the escalation node. The tree XML and fixture determine the expected outcomes; do not choose the expectations afterward to fit whichever branch happened to return success.
| Proposed fixture | Observe together | A result that needs explanation |
|---|---|---|
| Primary action succeeds normally | Primary success and recovery-node statistics | A recovery transition with no fixture reason |
| Primary fails before local recovery | Primary failure, local recovery outcome, later primary outcome | Root SUCCESS with no expected recovery evidence |
| Local remedy cannot resolve the fixture | Recovery failure and the declared escalation path | A successful root result from an unintended fallback |
This worksheet describes control-flow cases, not instructions to inject faults into operating equipment. Give the fixture a reproducible input and a bounded stopping condition in a suitable software test environment.
Bind each assertion to the tree that produced it
The 4.8 observer tutorial identifies nodes by UID and by fullPath(). UID follows the tree’s depth-first structure. A path includes subtree hierarchy and a node name, which may be supplied in XML or generated. Record the UID-to-path map for the actual tree instead of treating an old numeric UID as a permanent identity across XML changes.
Resolve each assertion to its intended node before ticking. Repeated action types inside different subtrees need distinct bindings. Keep the tree artifact and relevant blackboard or fixture inputs with that mapping so a passing check can be interpreted after a later tree revision.
Use a fresh observation interval for each case. A new observer or the supported statistics reset can prevent earlier outcomes from leaking into the next case’s comparison. If using before-and-after snapshots instead, define the interval explicitly and retain both snapshots.
Transition counters are not tick counters
The 4.8.0 observer header defines separate success, failure and skip transition counts. transitions_count excludes transitions to IDLE. It also distinguishes last_result, the last SUCCESS or FAILURE result, from current_status, which can also be IDLE or SKIPPED. Before a valid result, last_result is initialized to IDLE. The observer stores the last transition timestamp.
Do not interpret those fields as a count of every tick or as a complete ordered event trace. For an exact retry-attempt requirement, examine the particular control node’s semantics and retain additional attempt evidence when status transitions alone cannot represent the question. Zero observed transitions also needs the observation interval and starting-state assumptions before it is used to discuss an unused branch.
When order matters, collect the required transition history through the logger callback or another verified test recorder. The last timestamp in an aggregate is insufficient to reconstruct an entire retry sequence.
Keep the recovery policy separate from the observer result
The Nav2 recovery-design guide explains why retries and escalation need task-specific limits. Observer statistics add a narrower software check: did the fixture produce the transitions expected from that policy in this tree?
Retain the expected node outcomes, actual statistics, observation interval, tree identity and the first discrepancy. Investigate that discrepancy before celebrating the final root status. A coherent branch record makes a recovery test useful without turning it into a claim about navigation progress, physical motion or robot safety.