docs: public Deferred<ArrayList<Boolean>> processTimeseriesMeta(final TSMeta meta, 
        final boolean is_testing) {
      if (tree == null || tree.getTreeId() < 1) {
        throw new IllegalArgumentException(
            "The tree has not been set or is invalid");
      }
      if (meta == null || meta.getTSUID() == null || meta.getTSUID().isEmpty()) {
        throw new IllegalArgumentException("Missing TSUID");
      }
      
      // reset the state in case the caller is reusing this object
      resetState();
      this.meta = meta;
      
      // setup a list of deferreds to return to the caller so they can wait for
      // storage calls to complete
      final ArrayList<Deferred<Boolean>> storage_calls = 
        new ArrayList<Deferred<Boolean>>();
      
      /**
       * Runs the local TSMeta object through the tree's rule set after the root
       * branch has been set. This can be called after loading or creating the
       * root or if the root is set, it's called directly from this method. The
       * response is the deferred group for the caller to wait on.
       */
      final class ProcessCB implements Callback<Deferred<ArrayList<Boolean>>, 
        Branch> {
  
        /**
         * Process the TSMeta using the provided branch as the root.
         * @param branch The root branch to use
         * @return A group of deferreds to wait on for storage call completion
         */
        @Override
        public Deferred<ArrayList<Boolean>> call(final Branch branch) 
          throws Exception {
          
          // start processing with the depth set to 1 since we'll start adding 
          // branches to the root
          processRuleset(branch, 1);
          
          if (not_matched != null && !not_matched.isEmpty() && 
              tree.getStrictMatch()) {
            
            // if the tree has strict matching enabled and one or more levels
            // failed to match, then we don't want to store the resulting branches,
            // only the TSUID that failed to match
            testMessage(
                "TSUID failed to match one or more rule levels, will not add: " + 
                meta);
            if (!is_testing && tree.getNotMatched() != null && 
                !tree.getNotMatched().isEmpty()) {
              tree.addNotMatched(meta.getTSUID(), not_matched);
              storage_calls.add(tree.flushNotMatched(tsdb));
            }
            
          } else if (current_branch == null) {
            
            // something was wrong with the rule set that resulted in an empty
            // branch. Since this is likely a user error, log it instead of
            // throwing an exception
            LOG.warn("Processed TSUID [" + meta + 
                "] resulted in a null branch on tree: " + tree.getTreeId());
            
          } else if (!is_testing) {
            
            // iterate through the generated tree store the tree and leaves,
            // adding the parent path as we go
            Branch cb = current_branch;
            Map<Integer, String> path = branch.getPath();
            cb.prependParentPath(path);
            while (cb != null) {
              if (cb.getLeaves() != null || 
                  !processed_branches.containsKey(cb.getBranchId())) {
                LOG.debug("Flushing branch to storage: " + cb);
  
                /**
                 * Since we need to return a deferred group and we can't just
                 * group the branch storage deferreds with the not-matched and 
                 * collisions, we need to implement a callback that will wait for
                 * the results of the branch stores and group that with the rest.
                 * This CB will return false if ANY of the branches failed to 
                 * be written.
                 */
                final class BranchCB implements Callback<Deferred<Boolean>, 
                  ArrayList<Boolean>> {
  
                  @Override
                  public Deferred<Boolean> call(final ArrayList<Boolean> deferreds)
                      throws Exception {
                    
                    for (Boolean success : deferreds) {
                      if (!success) {
                        return Deferred.fromResult(false);
                      }
                    }
                    return Deferred.fromResult(true);
                  }
                  
                }
                final Deferred<Boolean> deferred = cb.storeBranch(tsdb, tree, true)
                  .addCallbackDeferring(new BranchCB());
                storage_calls.add(deferred);
                processed_branches.put(cb.getBranchId(), true);
              }
              
              // move to the next branch in the tree
              if (cb.getBranches() == null) {
                cb = null;
              } else {
                path = cb.getPath();
                // we should only have one child if we're building a tree, so we 
                // only need to grab the first one
                cb = cb.getBranches().first();
                cb.prependParentPath(path);
              }
            }
            
            // if we have collisions, flush em
            if (tree.getCollisions() != null && !tree.getCollisions().isEmpty()) {
              storage_calls.add(tree.flushCollisions(tsdb));
            }
            
          } else {
            
            // we are testing, so compile the branch paths so that the caller can
            // fetch the root branch object and return it from an RPC call
            Branch cb = current_branch;
            branch.addChild(cb);
            Map<Integer, String> path = branch.getPath();
            cb.prependParentPath(path);
            while (cb != null) {
              if (cb.getBranches() == null) {
                cb = null;
              } else {
                path = cb.getPath();
                // we should only have one child if we're building
                cb = cb.getBranches().first();
                cb.prependParentPath(path);
              }
            }
          }
          
          LOG.debug("Completed processing meta [" + meta + "] through tree: " + tree.getTreeId());
          return Deferred.group(storage_calls);
        }
      
      }
  
      /**
       * Called after loading or initializing the root and continues the chain
       * by passing the root onto the ProcessCB
       */
      final class LoadRootCB implements Callback<Deferred<ArrayList<Boolean>>, 
        Branch> {
  
        @Override
        public Deferred<ArrayList<Boolean>> call(final Branch root) 
          throws Exception {
          TreeBuilder.this.root = root;
          return new ProcessCB().call(root);
        }
        
      }
      
      LOG.debug("Processing meta [" + meta + "] through tree: " + tree.getTreeId());
      if (root == null) {
        // if this is a new object or the root has been reset, we need to fetch
        // it from storage or initialize it
        LOG.debug("Fetching root branch for tree: " + tree.getTreeId());
        return loadOrInitializeRoot(tsdb, tree.getTreeId(), is_testing)
          .addCallbackDeferring(new LoadRootCB());
      } else {
        // the root has been set, so just reuse it
        try {
          return new ProcessCB().call(root);
        } catch (Exception e) {
          throw new RuntimeException("Failed to initiate processing", e);
        }
      }
    }