StateGraph and the Dice RollNodes, edges, and Command routing
No narration yet
Module 3, Lesson 220 min

Nodes, edges, and Command routing

A node is a function of state that returns a partial update. Edges wire the flow. START and END are the sentinels.

A basic graph with static edges
const graph = new StateGraph(State)
  .addNode("sense", senseNode)
  .addNode("modulate", modulateNode)
  .addNode("roll", rollNode)
  .addEdge(START, "sense")
  .addEdge("sense", "modulate")
  .addEdge("modulate", "roll")
  .compile();

Command lets a node decide where to go next and what to write, together, instead of a static edge.

Command: update and route in one return
const roll: GraphNode<typeof State, "continueNode" | "wildNode" | "personalNode" | "restNode"> =
  (state) => {
    const face = rollDice(state.weights, state.random);
    return new Command({ update: { face }, goto: `${face}Node` });
  };

Your graph: a sense node (read the two sensor levels), a modulate node (modulateWeights), a roll node (rollDice returning a Command that goes to the face node), and four terminal nodes: continue, wild, personal, rest. The injectable random is your parity hook.

Practice

Try it yourself

Recall

Why injectable random matters

The point is the parity test against src/strategy/dice.ts, not general testability.

What would break about testing your graph's roll node if it called Math.random() directly instead of taking an injected random function?

Quiz

Command vs addConditionalEdges for the roll node

Both Command and addConditionalEdges can route dynamically. Why is Command the better fit specifically for the roll node?

Do

Port Impulse's cold-mode path into a StateGraph

Port the sense -> modulateWeights -> rollDice -> route path into an explicit, parity-tested StateGraph.

Tick every step to confirm you did it.

Check

Dice roll parity confirmed

Confirm the ported graph reproduces the original dice logic exactly.

You should see

Same injected random seeds produce the same faces as src/strategy/dice.ts, and quota-warning / hot / warm modulation matches the original weight vectors exactly.