diff --git a/bin/load_gen b/bin/load_gen
index 980e35d6a57f413cb69a439626cdfe784c3937df..99f492bfb8c983ea84b5a367f521b8a3dac77df7 100755
--- a/bin/load_gen
+++ b/bin/load_gen
@@ -40,6 +40,9 @@
  * tool, which is capable of analysing the maximum active users that
  * a browserid deployment can support */
 
+const winston = require('winston');
+
+
 // option processing with optimist
 var argv = require('optimist')
 .usage('Apply load to a BrowserID server.\nUsage: $0', [ "foo" ])
@@ -64,6 +67,7 @@ if (args.h) {
   process.exit(1);
 }
 
+
 // global configuration
 const configuration = {
   verifier: args.v ? args.v : args.s + "/verify",
@@ -103,10 +107,12 @@ var activity = {
     // users forget their password once every 4 weeks
     probability: (1.0 / (40 * 28.0))
   },
+*/
   "add_email": {
     // users add a new email address once every 2 weeks
     probability: (1.0 / (40 * 14.0))
   },
+/*
   "reauth": {
     // users must re-authenticate to browser id once a week
     // (once every two weeks per device)
@@ -182,6 +188,7 @@ function poll() {
     if (!args.o || act !== 'include_only') {
       outstanding++;
       activity[act].startFunc(configuration, function(err) {
+        if (err) winston.error(err);
         outstanding--;
         if (undefined === completed[act]) completed[act] = [ 0, 0 ];
         completed[act][err ? 1 : 0]++;
diff --git a/lib/load_gen/activities/add_email.js b/lib/load_gen/activities/add_email.js
index f93d4a84f41414a398118a359cb9de5a43800b40..aa12ba00d45ce82202512b4d8d63840d0b484829 100644
--- a/lib/load_gen/activities/add_email.js
+++ b/lib/load_gen/activities/add_email.js
@@ -38,49 +38,29 @@
  * user with an active session adding a new email with browserid. */
 
 const
-wcli = require("../../libs/wsapi_client.js"),
-userdb = require("./user_db.js"),
-winston = require('winston');
-
-function authenticated(cfg, context, email, password, cb) {
-  wcli.get(cfg, '/wsapi/am_authed', context, {}, function(r) {
-    if (r.body === 'true') cb();
-    else {
-      wcli.post(
-        cfg, '/wsapi/authenticate_user', context,
-        { email: email, pass: password },
-        function(r) {
-          if (r.code != 200 || r.body !== "true") {
-            winston.error('authentication failure: ' + r.code + "/" + r.body);
-          }
-          cb();
-        });
-    }
-  });
-}
+wcli = require("../../wsapi_client.js"),
+userdb = require("../user_db.js"),
+winston = require('winston'),
+prepare = require('../prepare.js');
 
 exports.startFunc = function(cfg, cb) {
-  // 1. RP includes include.js 
-  // 2. users' browser loads all code associated with dialog
-  // 3. /wsapi/add_email is called to stage the email address
-  // 4. in the load testing environment, we make a call to the server to get
-  //    the email verification token
-  // 5. /prove is called on the server, passing in the authentication token
-  // 6. /manage is called on the server as the user's page transitions from
-  //    the verify screen to the manage screen.
-  // 7. /wsapi/sync_emails is called from the client upon verification
-  //    (this is a bug, isn't it?)
-  // 8. /wsapi/set_key is called from the client to inform the server of the
-  //    user's public key for this new email (XXX: this will go away when we migrate to certificates
-  //    and instead, the server will be asked to sign the user's public key.)
-  // 9. the RP calls /verify to verify a generated assertion
+  // 1. RP includes include.js
+  // 2. session_context is called
+  // 3. list_emails is called
+  // 4. stage_email is called
+  // 5. email_addition_status is invoked some number of times while the dialog polls
+  // 6. landing page is loaded:
+  //   6a. session_context
+  //   6b. complete_email_addition
+  // 7. email_addition_status returns 'complete'
+  // 8. a key is generated and added
 
   // first let's get an existing user
   var user = userdb.getExistingUser();
 
   if (!user) {
     winston.warn("can't achieve desired concurrency!  not enough users!");
-    return cb(false);
+    return cb("not enough users");
   }
 
   // user will be "released" once we're done with her.
@@ -98,44 +78,67 @@ exports.startFunc = function(cfg, cb) {
   // pick one of the user's emails that we'll use
   var email = userdb.addEmailToUser(user);
 
-  var keypair = userdb.addKeyToUserCtx(context, email);
+  var origin = userdb.any(user.sites);
 
-  authenticated(cfg, context, user.emails[0], user.password, function() {
+  prepare.auth(cfg, user, context, user.emails[0], function(err) {
+    if (err) return cb(err);
     // stage them
-    wcli.post(cfg, '/wsapi/add_email', context, {
+    wcli.post(cfg, '/wsapi/stage_email', context, {
       email: email,
-      pubkey: keypair.pub,
       site: userdb.any(user.sites)
     }, function (r) {
       if (r.code !== 200) {
-        winston.error('failed to add email: ' + email + ' to existing user ' + user.emails[0]);
-        console.log(r);
-        return cb(false);
+        var msg = 'failed to add email: ' + email + ' to existing user ' +
+          user.emails[0];
+        winston.error(msg);
+        return cb(msg);
       }
       // now get the verification secret
       wcli.get(cfg, '/wsapi/fake_verification', context, {
         email: email
       }, function (r) {
         if (r.code !== 200) {
-          winston.error('failed to fetch verification token for email: ' + email);
-          return cb(false);
+          var err ='failed to fetch verification token for email: ' + email;
+          winston.error(err);
+          return cb(err);
         }
         var token = r.body;
+
         // and simulate clickthrough
-        wcli.get(cfg, '/wsapi/prove_email_ownership', context, {
+        wcli.post(cfg, '/wsapi/complete_email_addition', context, {
           token: token
         }, function (r) {
-          if (r.code !== 200 || r.body !== 'true') {
-            winston.error('failed to prove email owndership for: ' + email + ' (' + token + ')');
-            return cb(false);
+          try {
+            if (r.code !== 200) throw "bad response code";
+            if (JSON.parse(r.body).success !== true) throw "success?  no.";
+          } catch (e) {
+            var err = 'failed to complete email addition for: ' + email + ' (' + token + '): ' + e.toString();
+            winston.error(err);
+            process.exit(1);
+            return cb(err);
           }
+
           // and now we should call registration status to complete the
           // process
-          wcli.get(cfg, '/wsapi/registration_status', context, {
+          wcli.get(cfg, '/wsapi/email_addition_status', context, {
+            email: email
           }, function(r) {
-            var rv = (r.code === 200 && r.body === '"complete"');
-            if (!rv) winston.error("registration_status failed during signup: " + JSON.stringify(r));
-            cb(rv);
+            try {
+              if (r.code !== 200) throw "bad response code";
+              if (JSON.parse(r.body).status !== 'complete') throw "addition not complete?  wrong: " + r.body;
+            } catch(e) {
+              var err = "registration_status failed during signup: " + e.toString();
+              winston.error(err);
+              return cb(err);
+            }
+
+            // now generate a key
+            prepare.authAndKey(cfg, user, context, email, function(err) {
+              if (err) return cb(err);
+              prepare.genAssertionAndVerify(cfg, user, context, email, origin, function(err) {
+                cb(err);
+              });
+            });
           });
         });
       });
diff --git a/lib/load_gen/activities/reauth.js b/lib/load_gen/activities/reauth.js
index de9e9f2fb5e60ecd7ac8d937a8d62ecb8959c7dc..6a5085cb9c1769d628376519ea36c4e8e0c4e4cb 100644
--- a/lib/load_gen/activities/reauth.js
+++ b/lib/load_gen/activities/reauth.js
@@ -89,7 +89,7 @@ function syncEmails(cfg, context, cb) {
 }
 
 exports.startFunc = function(cfg, cb) {
-  // 1. RP includes include.js 
+  // 1. RP includes include.js
   // 2. users' browser loads all code associated with dialog
   // 3. in page javascript calls CSRF to get a CSRF token
   // 4. /wsapi/authenticate_user is called once the user enters credentials
diff --git a/lib/load_gen/activities/signin.js b/lib/load_gen/activities/signin.js
index 079293de0535a14f57d705ecf9fa4f0f6a1ddf8b..e75613f13335d1112e35d0538ad3781804fc92bd 100644
--- a/lib/load_gen/activities/signin.js
+++ b/lib/load_gen/activities/signin.js
@@ -58,7 +58,7 @@ exports.startFunc = function(cfg, cb) {
 
   if (!user) {
     winston.warn("can't achieve desired concurrency!  not enough users!");
-    return cb(false);
+    return cb("not enough users");
   }
 
   // unlock the user when we're done with them
@@ -79,39 +79,10 @@ exports.startFunc = function(cfg, cb) {
   var origin = userdb.any(user.sites);
 
   // establish session context and authenticate if needed
-  prepare(cfg, user, context, email, function(err) {
-    try {
-      serverTime = new Date(context.session.server_time);
-      wcli.get(cfg, '/wsapi/list_emails', context, undefined, function (r) {
-        // just verify that we got a JSON object, we don't care about
-        // the contents so much
-        try {
-          if (!typeof JSON.parse(r.body) === 'object') throw 'bogus response';
-        } catch(e) {
-          return cb(false);
-        }
-
-        var assertion = crypto.getAssertion({
-          now: serverTime,
-          secretKey: context.keys[email].keyPair.secretKey,
-          cert: context.keys[email].cert,
-          audience: origin,
-          email: email
-        });
-
-        wcli.post(cfg, '/verify', {}, {
-          audience: origin,
-          assertion: assertion
-        }, function (r) {
-          try {
-            cb(JSON.parse(r.body).status === 'okay' ? undefined : "verification failed");
-          } catch(e) {
-            return cb(e.toString);
-          }
-        });
-      });
-    } catch(e) {
-      cb(e.toString());
-    }
+  prepare.authAndKey(cfg, user, context, email, function(err) {
+    if (err) return cb(err);
+    prepare.genAssertionAndVerify(cfg, user, context, email, origin, function(err) {
+      cb(err);
+    });
   });
 };
diff --git a/lib/load_gen/activities/signup.js b/lib/load_gen/activities/signup.js
index e5c650595cd724a0a6d9c2648e87fc10bf5d4623..e628b39581682ffa7f2fce56967486934f469e79 100644
--- a/lib/load_gen/activities/signup.js
+++ b/lib/load_gen/activities/signup.js
@@ -96,7 +96,6 @@ exports.startFunc = function(cfg, cb) {
     if (r.code !== 200) return cb(false);
     // now get the verification secret
     wcli.get(cfg, '/wsapi/fake_verification', context, {
-
       email: email
     }, function (r) {
       if (r.code !== 200) return cb(false);
@@ -106,11 +105,12 @@ exports.startFunc = function(cfg, cb) {
         pass: user.password
       }, function (r) {
         r.body = JSON.parse(r.body);
-        if (r.code !== 200 || r.body.success !== true) return cb(false);
-
+        if (r.code !== 200 || r.body.success !== true) {
+          return cb("failed to complete user creation");
+        }
         // and now let's prepare this idenity in this context (get a keypair
         // and certify it)
-        prepare(cfg, user, context, email, function(err) {
+        prepare.authAndKey(cfg, user, context, email, function(err) {
           cb(err);
         });
       });
diff --git a/lib/load_gen/prepare.js b/lib/load_gen/prepare.js
index f5e29d8efc4d0caa27a189110f08762a3954e23a..cfb891898d198fac4f3754a120c639f5e9c23fe5 100644
--- a/lib/load_gen/prepare.js
+++ b/lib/load_gen/prepare.js
@@ -1,35 +1,30 @@
-// the common steps required to "prepare" an identity for use inside
-// a simulated browser context live here.  This includes:
-//
-//  1. authenticating if requried
-//  2. generating a keypair if required
-//  3. certifying that keypair
-//  4. storing all this crap on the session.
+// some common procedures.
 
 const
 wcli = require("../wsapi_client.js"),
-userdb = require("./user_db.js");
+userdb = require("./user_db.js"),
+crypto = require("./crypto.js");
 
-module.exports = function(cfg, user, ctx, email, cb) {
-  function doAuth(lcb) {
-    if (ctx.session && ctx.session.authenticated) {
-      lcb();
-    } else {
-      wcli.post(
-        cfg, '/wsapi/authenticate_user', ctx,
-        { email: email, pass: user.password },
-        function(r) {
-          if (JSON.parse(r.body).success !== true) return cb("failed to authenticate");
-          ctx.session.authenticated = true;
-          lcb();
-        }
-      );
-    }
-  };
+exports.auth = function(cfg, user, ctx, email, cb) {
+  if (ctx.session && ctx.session.authenticated) {
+    cb();
+  } else {
+    wcli.post(
+      cfg, '/wsapi/authenticate_user', ctx,
+      { email: email, pass: user.password },
+      function(r) {
+        if (JSON.parse(r.body).success !== true) return cb("failed to authenticate");
+        ctx.session.authenticated = true;
+        cb();
+      }
+    );
+  }
+};
 
-  function genKey(lcb) {
+exports.authAndKey = function(cfg, user, ctx, email, cb) {
+  function genKey(cb) {
     if (ctx.keys && ctx.keys[email]) {
-      lcb();
+      cb();
     } else {
       var keypair = userdb.addKeyToUserCtx(ctx, email);
         // and now let's certify the pubkey
@@ -39,15 +34,46 @@ module.exports = function(cfg, user, ctx, email, cb) {
         }, function(resp) {
           if (typeof resp.body !== 'string') return cb("can't certify key");
           userdb.addCertToUserCtx(ctx, email, resp.body);
-          lcb();
+          cb();
         });
     }
   };
 
-  doAuth(function() {
-    genKey(function() {
-      // all done!
-      cb();
+  exports.auth(cfg, user, ctx, email, function(err) {
+    if (err) return cb(err);
+    genKey(cb);
+  });
+};
+
+exports.genAssertionAndVerify = function(cfg, user, ctx, email, audience, cb) {
+  var serverTime = new Date(ctx.session.server_time);
+  wcli.get(cfg, '/wsapi/list_emails', ctx, undefined, function (r) {
+    // just verify that we got a JSON object, we don't care about
+    // the contents so much
+    try {
+      if (!typeof JSON.parse(r.body) === 'object') throw 'bogus response';
+    } catch(e) {
+      return cb(e.toString());
+    }
+
+    var assertion = crypto.getAssertion({
+      now: serverTime,
+      secretKey: ctx.keys[email].keyPair.secretKey,
+      cert: ctx.keys[email].cert,
+      audience: audience,
+      email: email
+    });
+
+    wcli.post(cfg, '/verify', {}, {
+      audience: audience,
+      assertion: assertion
+    }, function (r) {
+      try {
+        cb(JSON.parse(r.body).status === 'okay' ? undefined : "verification failed");
+      } catch(e) {
+        return cb("response body: " + r.body + " error: " + e.toString());
+      }
     });
   });
-};
\ No newline at end of file
+}
+
diff --git a/lib/verifier/certassertion.js b/lib/verifier/certassertion.js
index e7beb9c8fa0cedc21bdb33e16be1b87b16d7f2ae..4e54eb943f5300be3e5c9dabaa74d1914f651b07 100644
--- a/lib/verifier/certassertion.js
+++ b/lib/verifier/certassertion.js
@@ -77,7 +77,7 @@ function https_complete_get(host, url, successCB, errorCB) {
     });
 
   }).on('error', function(e) {
-    console.log(e.toString());
+    logger.warn(e.toString());
     errorCB(e);
   });
 }
@@ -103,7 +103,7 @@ function retrieveHostPublicKey(host, successCB, errorCB) {
       // FIXME do we need to check hm:Host?
 
       var pk_location = null;
-      
+
       // get the public key location
       var links = parsedDoc["Link"];
       if (links instanceof Array) {
@@ -203,7 +203,6 @@ function verify(assertion, audience, successCB, errorCB, pkRetriever) {
       // primary?
       if (theIssuer != config.get('hostname')) {
         // then the email better match the issuer
-        console.log(principal);
         if (!principal.email.match("@" + theIssuer + "$"))
           return errorCB();
       }