Index: branches/eam_branches/ipp-dev-20210817/psastro/src/psastroAstromGuess.c
===================================================================
--- branches/eam_branches/ipp-dev-20210817/psastro/src/psastroAstromGuess.c	(revision 41876)
+++ branches/eam_branches/ipp-dev-20210817/psastro/src/psastroAstromGuess.c	(revision 41877)
@@ -342,7 +342,10 @@
         if (!updates) goto skip_chip;
 
+	// in psastroOneChipFit & psastroMosaicOneCihp, astrometry failures are marked with NASTRO = 0
+	// these should be ignored when checking the overall solution
         int nAstro = psMetadataLookupS32 (&status, updates, "NASTRO");
         if (!nAstro) goto skip_chip;
 
+	// it is not clear when astError = 0.0
         float astError = psMetadataLookupF32 (&status, updates, "CERROR");
         if (fabs(astError) < 1e-6) goto skip_chip;
Index: branches/eam_branches/ipp-dev-20210817/psastro/src/psastroMetadataStats.c
===================================================================
--- branches/eam_branches/ipp-dev-20210817/psastro/src/psastroMetadataStats.c	(revision 41876)
+++ branches/eam_branches/ipp-dev-20210817/psastro/src/psastroMetadataStats.c	(revision 41877)
@@ -37,4 +37,5 @@
         psMetadataItemSupplement(&status, stats, header, "ZPT_ERR");
         psMetadataItemSupplement(&status, stats, header, "CERROR");
+        psMetadataItemSupplement(&status, stats, header, "CERSTD");
         psMetadataItemSupplement(&status, stats, header, "NASTRO");
         psMetadataItemSupplement(&status, stats, header, "AST_R0");
Index: branches/eam_branches/ipp-dev-20210817/psastro/src/psastroMosaicOneChip.c
===================================================================
--- branches/eam_branches/ipp-dev-20210817/psastro/src/psastroMosaicOneChip.c	(revision 41876)
+++ branches/eam_branches/ipp-dev-20210817/psastro/src/psastroMosaicOneChip.c	(revision 41877)
@@ -44,7 +44,10 @@
 
     // allowed limits for valid solutions
+    // CERROR is currently tested during the iterations, but not CERSTD
     snprintf (errorWord, 64, "PSASTRO.MOSAIC.MAX.ERROR.N%d", iteration);
-    REQUIRED_RECIPE_VALUE (float maxError, errorWord, F32, "failed to find single-chip max allowed error\n");
-    REQUIRED_RECIPE_VALUE (int minNstar, "PSASTRO.MOSAIC.MIN.NSTAR", S32, "failed to find single-chip min allowed stars\n");
+    snprintf (stdevWord, 64, "PSASTRO.MOSAIC.MAX.STDEV.N%d", iteration);
+    REQUIRED_RECIPE_VALUE (float maxError,                  errorWord, F32, "failed to find single-chip max allowed error\n");
+    REQUIRED_RECIPE_VALUE (float maxStdev,                  stdevWord, F32, "failed to find single-chip max allowed stdev\n");
+    REQUIRED_RECIPE_VALUE (int   minNstar, "PSASTRO.MOSAIC.MIN.NSTAR", S32, "failed to find single-chip min allowed stars\n");
 
     // set the order of the per-chip fit (higher order only if iteration > 0)
@@ -146,9 +149,12 @@
     bool validSolution = true;
 
-    // XXX should these result in errors or be handled another way?
-    // psLogMsg ("psastro", PS_LOG_INFO, "astrometry solution: error: %f arcsec, Nstars: %d", astError, astNstar);
+    // We have options to exclude chips on the basis of NASTRO, CERROR, CERSTD
     psLogMsg ("psastro", PS_LOG_INFO, "astrometry solution: error: %f arcsec, Nstars: %d, stdev: %f arcsec", astError, astNstar, astStdev);
     if ((maxError > 0) && (astError > maxError)) {
         psLogMsg("psastro", PS_LOG_INFO, "residual error is too large, failed to find a solution: %f > %f", astError, maxError);
+        validSolution = false;
+    }
+    if ((maxStdev > 0) && (astStdev > maxStdev)) {
+        psLogMsg("psastro", PS_LOG_INFO, "residual stdev is too large, failed to find a solution: %f > %f", astStdev, maxStdev);
         validSolution = false;
     }
@@ -158,5 +164,5 @@
     }
 
-    // DVO expects NASTRO = 0 if we fail to find a solution
+    // DVO expects NASTRO = 0 if we fail to find a solution, NASTUSED is the true number
     psMetadataAddF32 (updates, PS_LIST_TAIL, "PERROR",   PS_META_REPLACE, "astrometry error (pixels)", pixError);
     psMetadataAddF32 (updates, PS_LIST_TAIL, "CERROR",   PS_META_REPLACE, "astrometry error (arcsec)", astError);
@@ -165,7 +171,9 @@
         psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "astrometry precision (arcsec)", astError/sqrt(astNstar));
         psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "number of astrometry stars", astNstar);
+        psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTUSED", PS_META_REPLACE, "number of astrometry stars", astNstar);
     } else {
         psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "astrometry precision (arcsec)", 0.0);
         psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "number of astrometry stars", 0);
+        psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTUSED", PS_META_REPLACE, "number of astrometry stars", astNstar);
     }
     psMetadataAddF32 (updates, PS_LIST_TAIL, "EQUINOX",  PS_META_REPLACE, "", 2000.0); // XXX this is bogus: should be defined based on equinox of refstars
Index: branches/eam_branches/ipp-dev-20210817/psastro/src/psastroOneChipFit.c
===================================================================
--- branches/eam_branches/ipp-dev-20210817/psastro/src/psastroOneChipFit.c	(revision 41876)
+++ branches/eam_branches/ipp-dev-20210817/psastro/src/psastroOneChipFit.c	(revision 41877)
@@ -40,5 +40,6 @@
     // allowed limits for valid solutions
     REQUIRED_RECIPE_VALUE (float maxError, "PSASTRO.MAX.ERROR", F32);
-    REQUIRED_RECIPE_VALUE (int minNstar, "PSASTRO.MIN.NSTAR", S32);
+    REQUIRED_RECIPE_VALUE (float maxStdev, "PSASTRO.MAX.STDEV", F32);
+    REQUIRED_RECIPE_VALUE (int   minNstar, "PSASTRO.MIN.NSTAR", S32);
 
     psArray *match = NULL;
@@ -208,4 +209,8 @@
         validSolution = false;
     }
+    if (astStdev > maxStdev) {
+	psLogMsg("psastro", PS_LOG_INFO, "residual stdev is too large, failed to find a solution: %f > %f", astStdev, maxStdev);
+        validSolution = false;
+    }
     if (astNstar < minNstar) {
         psLogMsg("psastro", PS_LOG_INFO, "solution uses too few stars: %d < %d", astNstar, minNstar);
@@ -220,6 +225,8 @@
         psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "astrometry precision (arcsec)", astError/sqrt(astNstar));
         psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "number of astrometry stars", astNstar);
+        psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTUSED", PS_META_REPLACE, "number of astrometry stars", astNstar);
     } else {
 	psastroChipFailureHeader (updates);
+        psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTUSED", PS_META_REPLACE, "number of astrometry stars", astNstar);
     }
     psMetadataAddF32 (updates, PS_LIST_TAIL, "EQUINOX",  PS_META_REPLACE, "equinox of ref catalog", 2000.0); // XXX this is bogus: should be defined based on equinox of refstars
