 # Glossary:
-#  * Descent - What we call an attempt to traverse the tree, which may be
-#              paused because it encounters a lock on a tier.
+#  * Descent - What we call an attempt to move from a parent node to a child
+#              node in  the tree, which may be paused because it encounters a
+#              lock on a tier.
 class Mutation
   constructor: (@strata, @object, @fields, initial, subsequent, swap, penultimate, @callback) ->
-    @levels = []
     @decisions = { initial, subsequent, swap, penultimate }
-    @exclusive = false
+    @parent = new Level
+    @child = new Level
+    @exclusive = []
+    @plan = []
+
+  # Descend the tree, optionally starting an exclusive descent. Once the descent
+  # is exclusive, all subsequent descents are exclusive.
+  descend: (exclusive) ->
+    @plan.unshift { operations: [] }
+    if @exclusive.length > 1
+      @parent.release(strata)
+    exclusive or= @exclusive.length > 0
+    @parent = @child
+    @child = new Level(exclusive)
+    if exclusive
+      @exclusive.release(strata)
 
 class Level
   # Construct a new level. The `exclusive` pararameter determines how this level

  #
  # This generalized mutation will insert or remove a single item.
  _generalized: (mutation) ->
    mutation.levels.unshift new Level
    mutation.levels[0].lock @, mutation, @rootAddress, @_rootLoaded

  # Perform the root decision with only a read lock obtained.
  _rootLoaded: (mutation, root) ->
    mutation.levels[0].tier = root
    mutation.decisions.initial.call @, mutation
    @_tierDecision mutation


  # TODO Now there is a chance that this might already be in a split state. What
  # do we do? Do we create a new plan as we decend to test the current plan?
  _howToInsertLeaf: (mutation) ->
    console.log mutation
    # Find the branch that navigates to the leaf child.
    branch = @_find mutation.parentLevel.tier, mutation.fields
    @io.load @, mutation, mutation.parentLevel.tier.get(branch).address, @_inspectLeafForSplitLoaded
