Sentinel · Advanced · Tutorial 3 of 3

Reading the Run

Building a behaviour tree is the easy half. This is the other one: sixteen nodes, three agents, and a guard doing something you didn't ask for — and the four tools that tell you why.

AshForge SentinelAfter: The Contract~40 min

Save before you run. Still no unsaved-changes guard — and this tutorial has you launching a second application, which is exactly when a window gets closed by accident.

Get something worth debugging

01 Load Elite Combatant and look at the shape

Templates → Elite Combatant. Sixteen nodes, and the first thing to notice is that its composites have namesBrain, Survive, Engage, Close or Strike, Search. You can rename any node, and at this size it is the difference between a diagram and a wall.

The second thing: Brain is a Selector, and its child order is a priority list. Survive, then Engage, then Search, then a fallback. Fleeing outranks fighting; fighting outranks looking. That ordering is the personality — move Survive below Engage and you have written a fanatic.

02 Run it with a swarm

Set Agents to 3 and press Test in Crucible. Crucible opens, Sentinel connects to it over a local debug socket, and the status line reports the capture when it's done:

[INFO] (LiveDebug) Connected to Crucible live debug on 127.0.0.1:45599.
Live run finished — 53 tick(s) captured. Scrub or Play to review.

You now have a trace: every tick, for every agent, the status of every node — plus the blackboard values at that moment.

If the live connection fails, the status line tells you so and adds: “You can still 'Load Trace' once the run finishes.” The socket is a convenience; the trace file is the source of truth.

Four instruments, in the order you should use them

03 Stats — the numbers, on the nodes

Press Stats. Every node gains a line reading evaluations, successes, failures and running ticks:

Survive     53×  ✓0   ✗53  ↻0
HasTarget   53×  ✓53  ✗0   ↻0
Brain       53×  ✓18  ✗0   ↻35
Flee             · not reached

Read those four rows and you already know the story of the run. Survive was checked every single tick and failed every single time — nobody got hurt. HasTarget succeeded every tick — the enemy was always visible. Brain spent two-thirds of its life running rather than finishing, which is what a Selector does when its chosen child is mid-action.

04 Heatmap — where the pressure is

Press Heatmap. Node headers tint by evaluation count relative to the busiest node in the run. It is a relative scale, so there is always something hot; what you're looking for is the shape — which spine of the tree the agent actually lived in, and which limbs stayed cold.

05 Analytics — the summary that names the suspects

Press Analytics. With more than one agent it opens with a swarm section, then a per-agent summary:

Final outcomes3 success · 0 failure
Ticks / Duration53 · 5.5 s
Nodes16
Dead branches6 (never reached)
Busiest nodeBrain (53 evals)

Then a per-node table with success, failure and running percentages. The agent dropdown in the debug bar switches which agent you're inspecting — when one of three behaves differently, that's where you find it.

The correction: dead is not the same as broken

Tutorial one told you that a node which never fired is a wiring bug. That was a useful lie, and here is the truth.

This run reported 6 dead branches out of 16 nodes — in the template that ships with the tool, on a run where all three agents succeeded. Flee was never reached because nobody's health ever dropped. Search and Investigate were never reached because the target was visible the whole time. Those branches aren't broken. They are insurance you didn't need this run.

A dead branch is only a bug if the scenario should have reached it. The question is never "did it fire" on its own — it is "did it fire, given what happened". Which means you cannot read the dead-branch count without knowing what the run was supposed to exercise.

no yes never ✓ did ✓ branch never fired should this run have reached it? correct — not a bug check the gate condition or scenario wiring below
The only diagnostic flow you need for a silent branch. Everything hinges on the second box, which the tool cannot answer for you.

Scrubbing, and the payoff from tutorial two

06 Step through the tick that went wrong

The scrubber walks the run tick by tick; Play animates it. As you move, the graph shows each node's status at that instant — and the status bar shows the blackboard:

Tick 54/54 · Success    BB: distance=1.8  health=100  tar…

That's the contract from tutorial two, filled in. You declared distance and health; the game wrote them; the trace recorded them. This is the only place in Sentinel where blackboard variables have live values, and it is the reason declaring them carefully matters.

The technique: find the tick where behaviour diverged from what you wanted, then read the blackboard at that tick. Most "the AI is being stupid" bugs are a variable that isn't what you assumed.

A worked diagnosis

Say your guards refuse to flee, however badly hurt. Work it in order:

  1. Stats. Is Flee reached at all? If it reads not reached, the branch never ran — go up.
  2. Its gate. HealthLow shows 53× ✓0 ✗53. It was evaluated every tick and never once succeeded.
  3. The fork. Either health genuinely never dropped — a scenario problem, fix the test, not the tree — or it did drop and the condition disagreed, which is a contract problem: the game's definition of "low" isn't yours.
  4. Scrub to a tick where the agent was hurt and read health in the blackboard. That single number tells you which of the two you have.

Note what never happened: you did not stare at the tree. Three of those four steps are instrument readings, and the fourth is a number.

A quirk worth knowing: Root itself reports not reached with zero evaluations, in every run. The trace records the nodes Root drives, not Root. Don't chase it.