Index: trunk/ippTools/share/magictool_inputs.sql
===================================================================
--- trunk/ippTools/share/magictool_inputs.sql	(revision 18571)
+++ trunk/ippTools/share/magictool_inputs.sql	(revision 18573)
@@ -3,11 +3,12 @@
 -- Single skycells
 SELECT
+    magicRun.magic_id,
+    magicRun.state,
     magicInputSkyfile.node,
-    magicRun.state,
     diffSkyfile.uri,
     diffSkyfile.fault
 FROM magicInputSkyfile
 JOIN diffSkyfile
-    using(diff_id)
+    USING(diff_id)
 JOIN magicRun
     USING(magic_id)
@@ -15,6 +16,7 @@
 -- Merged skycells
 SELECT
+    magicRun.magic_id,
+    magicRun.state,
     magicTree.node,
-    magicRun.state,
     magicNodeResult.uri,
     magicNodeResult.fault
Index: trunk/ippTools/share/magictool_tomask.sql
===================================================================
--- trunk/ippTools/share/magictool_tomask.sql	(revision 18571)
+++ trunk/ippTools/share/magictool_tomask.sql	(revision 18573)
@@ -10,4 +10,5 @@
     magicRun.state = 'run'
     AND magicNodeResult.node = 'root'
+    AND magicNodeResult.fault = 0
 GROUP BY
     magic_id
Index: trunk/ippTools/share/magictool_toprocess_tree.sql
===================================================================
--- trunk/ippTools/share/magictool_toprocess_tree.sql	(revision 18571)
+++ trunk/ippTools/share/magictool_toprocess_tree.sql	(revision 18573)
@@ -3,5 +3,6 @@
     -- convert magic_id into a boolean value (1 or 0)
     -- note that the type stays a 64 bit int
-    magicNodeResult.magic_id IS TRUE as done
+    magicNodeResult.magic_id IS TRUE as done,
+    magicNodeResult.fault IS TRUE as bad
 FROM magicTree
 JOIN magicRun
Index: trunk/ippTools/src/magictool.c
===================================================================
--- trunk/ippTools/src/magictool.c	(revision 18571)
+++ trunk/ippTools/src/magictool.c	(revision 18573)
@@ -38,9 +38,12 @@
 static bool totreeMode(pxConfig *config);
 static bool inputtreeMode(pxConfig *config);
+static bool reverttreeMode(pxConfig *config);
 static bool toprocessMode(pxConfig *config);
 static bool addresultMode(pxConfig *config);
+static bool revertnodeMode(pxConfig *config);
 static bool inputsMode(pxConfig *config);
 static bool tomaskMode(pxConfig *config);
 static bool addmaskMode(pxConfig *config);
+static bool revertmaskMode(pxConfig *config);
 static bool maskMode(pxConfig *config);
 
@@ -73,9 +76,12 @@
         MODECASE(MAGICTOOL_MODE_TOTREE,         totreeMode);
         MODECASE(MAGICTOOL_MODE_INPUTTREE,      inputtreeMode);
+        MODECASE(MAGICTOOL_MODE_REVERTTREE,     reverttreeMode);
         MODECASE(MAGICTOOL_MODE_TOPROCESS,      toprocessMode);
         MODECASE(MAGICTOOL_MODE_ADDRESULT,      addresultMode);
+        MODECASE(MAGICTOOL_MODE_REVERTNODE,     revertnodeMode);
         MODECASE(MAGICTOOL_MODE_INPUTS,         inputsMode);
         MODECASE(MAGICTOOL_MODE_TOMASK,         tomaskMode);
         MODECASE(MAGICTOOL_MODE_ADDMASK,        addmaskMode);
+        MODECASE(MAGICTOOL_MODE_REVERTMASK,     revertmaskMode);
         MODECASE(MAGICTOOL_MODE_MASK,           maskMode);
         default:
@@ -512,5 +518,5 @@
 
     if (code > 0) {
-        char *query = "UPDATE magicRun SET fault = %d WHERE magic_id = %" PRId64;
+        char *query = "UPDATE magicRun SET fault = %d, state = 'stop' WHERE magic_id = %" PRId64;
         if (!p_psDBRunQuery(config->dbh, query, code, magic_id)) {
             psError(PS_ERR_UNKNOWN, false,
@@ -528,4 +534,29 @@
     return true;
 }
+
+static bool reverttreeMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-magic_id", "magic_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code", "fault", "==");
+
+    psString query = psStringCopy("UPDATE magicRun SET fault = 0, state = 'run' WHERE fault != 0");
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to revert");
+        return false;
+    }
+    return true;
+}
+
 
 static bool inputsMode(pxConfig *config)
@@ -622,4 +653,9 @@
 bool findReadyNodes(void *arg, pxNode *node)
 {
+    if (!node) {
+        // It's not there --- must have failed
+        return false;
+    }
+
     if (psMetadataLookupBool(NULL, node->data, "done")) {
         // It's already done
@@ -632,7 +668,4 @@
         psMetadataRemoveKey(work, "dep");
         psMetadataRemoveKey(work, "done");
-#if 0
-        psMetadataRemoveKey(work, "uri");
-#endif
         pxNode *child = NULL;
         while ((child = psListGetAndIncrement(iter))) {
@@ -644,6 +677,10 @@
                 psAbort("failed to lookup value for done column");
             }
-
-            if (!done) {
+            psS16 bad = psMetadataLookupS16(&status, data, "bad");
+            if (!status) {
+                psAbort("failed to lookup value for bad column");
+            }
+
+            if (!done || bad) {
                 // if a child isn't "done", give up on this node and continue
                 // to crawl the tree
@@ -652,12 +689,4 @@
                 return true;
             }
-#if 0
-            char *uri = psMetadataLookupStr(&status, data, "uri");
-            if (!status) {
-                psAbort("failed to lookup value for uri column");
-            }
-
-            psMetadataAddStr(work, PS_LIST_TAIL, "uri", PS_META_DUPLICATE_OK, NULL, uri);
-#endif
         }
         psFree(iter);
@@ -835,4 +864,30 @@
 }
 
+static bool revertnodeMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-magic_id", "magic_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-node", "node", "==");
+    PXOPT_COPY_S16(config->args, where, "-code", "fault", "==");
+
+    psString query = psStringCopy("DELETE FROM magicNodeResult WHERE fault != 0");
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to revert");
+        return false;
+    }
+    return true;
+}
+
+
 static bool tomaskMode(pxConfig *config)
 {
@@ -885,5 +940,5 @@
     if (psArrayLength(output)) {
         // negative simple so the default is true
-        if (!ippdbPrintMetadatas(stdout, output, "toprocess", !simple)) {
+        if (!ippdbPrintMetadatas(stdout, output, "tomask", !simple)) {
             psError(PS_ERR_UNKNOWN, false, "failed to print array");
             psFree(output);
@@ -924,4 +979,7 @@
         )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         return false;
     }
@@ -931,4 +989,7 @@
     if (!query) {
         psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         return false;
     }
@@ -940,4 +1001,7 @@
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
         return false;
     }
@@ -948,4 +1012,70 @@
         return false;
     }
+
+    return true;
+}
+
+static bool revertmaskMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-magic_id", "magic_id", "==");
+    PXOPT_COPY_S16(config->args, where, "-code", "fault", "==");
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    // Set to "run"
+    {
+        psString query = psStringCopy("UPDATE magicRun JOIN magicMask USING(magic_id) "
+                                      "SET magicRun.state = 'run' WHERE magicMask.fault != 0");
+
+        if (psListLength(where->list)) {
+            psString whereClause = psDBGenerateWhereConditionSQL(where, "magicMask");
+            psStringAppend(&query, " AND %s", whereClause);
+            psFree(whereClause);
+        }
+
+        if (!p_psDBRunQuery(config->dbh, query)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to revert");
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            return false;
+        }
+
+        psFree(query);
+    }
+
+    // Delete failed attempt at mask
+    {
+        psString query = psStringCopy("DELETE FROM magicMask WHERE fault != 0");
+
+        if (psListLength(where->list)) {
+            psString whereClause = psDBGenerateWhereConditionSQL(where, "magicMask");
+            psStringAppend(&query, " AND %s", whereClause);
+            psFree(whereClause);
+        }
+
+        if (!p_psDBRunQuery(config->dbh, query)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to revert");
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            return false;
+        }
+
+        psFree(query);
+    }
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    psFree(where);
 
     return true;
@@ -1012,5 +1142,5 @@
     if (psArrayLength(output)) {
         // negative simple so the default is true
-        if (!ippdbPrintMetadatas(stdout, output, "magicNode", !simple)) {
+        if (!ippdbPrintMetadatas(stdout, output, "magicMask", !simple)) {
             psError(PS_ERR_UNKNOWN, false, "failed to print array");
             psFree(output);
Index: trunk/ippTools/src/magictool.h
===================================================================
--- trunk/ippTools/src/magictool.h	(revision 18571)
+++ trunk/ippTools/src/magictool.h	(revision 18573)
@@ -32,9 +32,12 @@
     MAGICTOOL_MODE_TOTREE,
     MAGICTOOL_MODE_INPUTTREE,
+    MAGICTOOL_MODE_REVERTTREE,
     MAGICTOOL_MODE_TOPROCESS,
     MAGICTOOL_MODE_INPUTS,
     MAGICTOOL_MODE_ADDRESULT,
+    MAGICTOOL_MODE_REVERTNODE,
     MAGICTOOL_MODE_TOMASK,
     MAGICTOOL_MODE_ADDMASK,
+    MAGICTOOL_MODE_REVERTMASK,
     MAGICTOOL_MODE_MASK,
 } MAGICtoolMode;
Index: trunk/ippTools/src/magictoolConfig.c
===================================================================
--- trunk/ippTools/src/magictoolConfig.c	(revision 18571)
+++ trunk/ippTools/src/magictoolConfig.c	(revision 18573)
@@ -93,4 +93,9 @@
     psMetadataAddS16(inputtreeArgs, PS_LIST_TAIL, "-code", 0, "set fault code", 0);
 
+    // -reverttree
+    psMetadata *reverttreeArgs = psMetadataAlloc();
+    psMetadataAddS64(reverttreeArgs, PS_LIST_TAIL, "-magic_id", 0, "search by magictool ID", 0);
+    psMetadataAddS16(reverttreeArgs, PS_LIST_TAIL, "-code", 0, "search by fault code", 0);
+
     // -inputs
     psMetadata *inputsArgs = psMetadataAlloc();
@@ -110,6 +115,12 @@
     psMetadataAddS64(addresultArgs, PS_LIST_TAIL, "-magic_id", 0, "define magictool ID (required)", 0);
     psMetadataAddStr(addresultArgs, PS_LIST_TAIL, "-node", 0, "define symbolic node name (required)", NULL);
-    psMetadataAddStr(addresultArgs, PS_LIST_TAIL, "-uri", 0, "define URI (required)", NULL);
+    psMetadataAddStr(addresultArgs, PS_LIST_TAIL, "-uri", 0, "define URI", NULL);
     psMetadataAddS16(addresultArgs, PS_LIST_TAIL, "-code", 0, "set fault code", 0);
+
+    // -revertnode
+    psMetadata *revertnodeArgs = psMetadataAlloc();
+    psMetadataAddS64(revertnodeArgs, PS_LIST_TAIL, "-magic_id", 0, "search by magictool ID", 0);
+    psMetadataAddStr(revertnodeArgs, PS_LIST_TAIL, "-node", 0, "search by node name", NULL);
+    psMetadataAddS16(revertnodeArgs, PS_LIST_TAIL, "-code", 0, "search by fault code", 0);
 
     // -tomask
@@ -124,4 +135,9 @@
     psMetadataAddS32(addmaskArgs, PS_LIST_TAIL, "-streaks", 0, "define number of streaks", 0);
     psMetadataAddS16(addmaskArgs, PS_LIST_TAIL, "-code", 0, "set fault code", 0);
+
+    // -revertmask
+    psMetadata *revertmaskArgs = psMetadataAlloc();
+    psMetadataAddS64(revertmaskArgs, PS_LIST_TAIL, "-magic_id", 0, "search by magictool ID", 0);
+    psMetadataAddS16(revertmaskArgs, PS_LIST_TAIL, "-code", 0, "search by fault code", 0);
 
     // -mask
@@ -143,9 +159,12 @@
     PXOPT_ADD_MODE("-totree",          "", MAGICTOOL_MODE_TOTREE,          totreeArgs);
     PXOPT_ADD_MODE("-inputtree",       "", MAGICTOOL_MODE_INPUTTREE,       inputtreeArgs);
+    PXOPT_ADD_MODE("-reverttree",      "", MAGICTOOL_MODE_REVERTTREE,      reverttreeArgs);
     PXOPT_ADD_MODE("-toprocess",       "", MAGICTOOL_MODE_TOPROCESS,       toprocessArgs);
     PXOPT_ADD_MODE("-inputs",          "", MAGICTOOL_MODE_INPUTS,          inputsArgs);
     PXOPT_ADD_MODE("-addresult",       "", MAGICTOOL_MODE_ADDRESULT,       addresultArgs);
+    PXOPT_ADD_MODE("-revertnode",      "", MAGICTOOL_MODE_REVERTNODE,      revertnodeArgs);
     PXOPT_ADD_MODE("-tomask",          "", MAGICTOOL_MODE_TOMASK,          tomaskArgs);
     PXOPT_ADD_MODE("-addmask",         "", MAGICTOOL_MODE_ADDMASK,         addmaskArgs);
+    PXOPT_ADD_MODE("-revertmask",      "", MAGICTOOL_MODE_REVERTMASK,      revertmaskArgs);
     PXOPT_ADD_MODE("-mask",            "", MAGICTOOL_MODE_MASK,            maskArgs);
 
