diff --git a/ChangeLog b/ChangeLog
index cb72ff6b1ac02c05ffa8702c3f6e487392232287..aa0a2cb677c1d6f9b4c5eaa535e1084f013fcded 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,12 @@ train-2012.04.11:
   * developers link now points to MDN: #1397
   * fix issues that were introduced while implementing the above features: #1349, #1348, #1354, #1357, #1374, #1399, #1400, #1408, #1395, #1406, #1405, #1390, #1391
   * (hotfix 2012.04.12) return 400 rather than 500 for invalid params to stage_user or stage_email: #1429
+  * (hotfix 2012.04.12) fix broken string, "is this your computer" was broken into two fragments: #1425
+  * (hotfix 2012.04.16) fix API regression that would cause javascript error when .get() invoked without second arg: #1442
+  * (hotfix 2012.04.16) update load_gen to new server apis that require an `ephemeral` argument: #1436
+  * (hotfix 2012.04.17) fix broken reset password flow - button was non-responsive in dialog: #1440
+  * (hotfix 2012.04.17) mitigate errors seen when adding a secondary email to an acct with only primary emails: #1445
+  * (hotfix 2012.04.18) fix error where under certain conditions user could see an error immediately after authenticating: #1449
 
 train-2012.03.28:
   * work towards better user messaging for when cookies are disabled: #1167, #1302
diff --git a/lib/wsapi/complete_email_addition.js b/lib/wsapi/complete_email_addition.js
index 1359b49c379efab649d942f988f37f8c466c7dfa..6e7dd2a4df4ce2116142fe5603d848ae43f9cccf 100644
--- a/lib/wsapi/complete_email_addition.js
+++ b/lib/wsapi/complete_email_addition.js
@@ -41,27 +41,32 @@ exports.process = function(req, res) {
       });
     }
 
-    db.gotVerificationSecret(req.body.token, req.body.pass, function(e, email, uid) {
+    // got verification secret's second paramter is a password.  That password
+    // will only be used on new account creation.  Because we know this is not
+    // a new account, we don't provide it.
+    db.gotVerificationSecret(req.body.token, "", function(e, email, uid) {
       if (e) {
         logger.warn("couldn't complete email verification: " + e);
         wsapi.databaseDown(res, e);
       } else {
         // now do we need to set the password?
         if (r.needs_password && req.body.pass) {
+          // requiring the client to wait until the bcrypt process is complete here
+          // exacerbates race conditions in front-end code.  We'll return success early,
+          // here, then update the password after the fact.  The worst thing that could
+          // happen is that password update could fail (due to extreme load), and the
+          // user will have to reset their password.
+          wsapi.authenticateSession(req.session, uid, 'password');
+          res.json({ success: true });
+
           wsapi.bcryptPassword(req.body.pass, function(err, hash) {
             if (err) {
               logger.warn("couldn't bcrypt password during email verification: " + err);
-              return res.json({ success: false });
+              return;
             }
             db.updatePassword(uid, hash, function(err) {
               if (err) {
                 logger.warn("couldn't update password during email verification: " + err);
-                wsapi.databaseDown(res, err);
-              } else {
-                // XXX: what if our software 503s?  User doesn't get a password set and
-                // cannot change it.
-                wsapi.authenticateSession(req.session, uid, 'password');
-                res.json({ success: !err });
               }
             });
           });
diff --git a/resources/static/dialog/controllers/check_registration.js b/resources/static/dialog/controllers/check_registration.js
index 7e4e90ab8e5de2856bfc2c87e518ef28cace42c1..3389f3f9e0ca7b47bb22e796e3c8135c91af9ce0 100644
--- a/resources/static/dialog/controllers/check_registration.js
+++ b/resources/static/dialog/controllers/check_registration.js
@@ -40,7 +40,10 @@ BrowserID.Modules.CheckRegistration = (function() {
           });
         }
         else if (status === "mustAuth") {
-          self.close("authenticate", { email: self.email });
+          user.addressInfo(self.email, function(info) {
+            self.close("authenticate", info);
+          });
+
           oncomplete && oncomplete();
         }
       }, self.getErrorDialog(errors.registration, oncomplete));
diff --git a/resources/static/dialog/controllers/dialog.js b/resources/static/dialog/controllers/dialog.js
index 9d5c2693bbeeacea1e703d51b0403967feff70b3..1d3e57b872a4fc526677fe7189401bfc9a688f71 100644
--- a/resources/static/dialog/controllers/dialog.js
+++ b/resources/static/dialog/controllers/dialog.js
@@ -86,7 +86,7 @@ BrowserID.Modules.Dialog = (function() {
     if (/^http/.test(url)) u = URLParse(url);
     else if (/^\//.test(url)) u = URLParse(origin + url);
     else throw "relative urls not allowed: (" + url + ")";
-    return u.validate().normalize().toString();
+    return encodeURI(u.validate().normalize().toString());
   }
 
   var Dialog = bid.Modules.PageModule.extend({
diff --git a/resources/static/dialog/resources/state.js b/resources/static/dialog/resources/state.js
index 1d8bcfdbceb2c2f6124112342c0d0ff39bda75be..126e68878274f2fe717617c23c50be583386544e 100644
--- a/resources/static/dialog/resources/state.js
+++ b/resources/static/dialog/resources/state.js
@@ -243,6 +243,8 @@ BrowserID.State = (function() {
     handleState("reset_password", function(msg, info) {
       // reset password says the password has been reset, now waiting for
       // confirmation.
+      info = info || {};
+      self.stagedEmail = info.email;
       startAction(false, "doResetPassword", info);
     });
 
diff --git a/resources/static/dialog/views/is_this_your_computer.ejs b/resources/static/dialog/views/is_this_your_computer.ejs
index 2ab5bd1789788cf4abb72f2860898db25bd4982c..d592e7714619c878d42a04f96b45c2c55499e40e 100644
--- a/resources/static/dialog/views/is_this_your_computer.ejs
+++ b/resources/static/dialog/views/is_this_your_computer.ejs
@@ -12,8 +12,7 @@
 
     <p>
       <button class="this_is_not_my_computer negative" tabindex="3"><%= gettext('no') %></button>
-      <%= gettext('If you\'re at a public computer such as a library or internet cafe, we\'ll ask you ' +
-                  'for your password again in an hour.') %>
+      <%= gettext('If you\'re at a public computer such as a library or internet cafe, we\'ll ask you for your password again in an hour.') %>
     </p>
   </div>
 
diff --git a/resources/static/test/cases/controllers/check_registration.js b/resources/static/test/cases/controllers/check_registration.js
index 8619cfa0a11c0b392b7cf7529ffdd3d12ac5aea3..03a01bf0a23fed05da0e3de64fab2eb43843e9eb 100644
--- a/resources/static/test/cases/controllers/check_registration.js
+++ b/resources/static/test/cases/controllers/check_registration.js
@@ -48,10 +48,18 @@
     controller.startCheck();
   }
 
-  asyncTest("user validation with mustAuth result", function() {
+  asyncTest("user validation with mustAuth result - callback with email, type and known set to true", function() {
     xhr.useResult("mustAuth");
-
-    testVerifiedUserEvent("authenticate", "User Must Auth");
+    createController("waitForUserValidation");
+    register("authenticate", function(msg, info) {
+      // we want the email, type and known all sent back to the caller so that
+      // this information does not need to be queried again.
+      equal(info.email, "registered@testuser.com", "correct email");
+      ok(info.type, "type sent with info");
+      ok(info.known, "email is known");
+      start();
+    });
+    controller.startCheck();
   });
 
   asyncTest("user validation with pending->complete result ~3 seconds", function() {
diff --git a/resources/static/test/cases/resources/state.js b/resources/static/test/cases/resources/state.js
index 1c32995418eb58c6e2c785a5530d5a8bd791f23b..b620cdf598dbe85f3965123ff82e95e598c1a551 100644
--- a/resources/static/test/cases/resources/state.js
+++ b/resources/static/test/cases/resources/state.js
@@ -218,6 +218,14 @@
     equal(actions.info.doAuthenticate.email, TEST_EMAIL, "authenticate called with the correct email");
   });
 
+  test("reset_password through to validation on same browser - call doEmailConfirmed with email address", function() {
+    mediator.publish("reset_password", { email: TEST_EMAIL });
+    mediator.publish("user_confirmed");
+
+    equal(actions.info.doEmailConfirmed.email, TEST_EMAIL, "doEmailConfirmed called with correct email");
+  });
+
+
   asyncTest("assertion_generated with null assertion - redirect to pick_email", function() {
     mediator.subscribe("pick_email", function() {
       ok(true, "redirect to pick_email");
diff --git a/resources/static/test/mocks/xhr.js b/resources/static/test/mocks/xhr.js
index 14c08098bdb87b1653e03db4ce9e85cc62811596..17aa6c9851933562e057afbd92c26cb68fa1d4af 100644
--- a/resources/static/test/mocks/xhr.js
+++ b/resources/static/test/mocks/xhr.js
@@ -110,6 +110,7 @@ BrowserID.Mocks.xhr = (function() {
       "get /wsapi/address_info?email=unregistered%40testuser.com primary": { type: "primary", auth: "https://auth_url", prov: "https://prov_url" },
       "get /wsapi/address_info?email=testuser%40testuser.com unknown_secondary": { type: "secondary", known: false },
       "get /wsapi/address_info?email=testuser%40testuser.com known_secondary": { type: "secondary", known: true },
+      "get /wsapi/address_info?email=registered%40testuser.com mustAuth": { type: "secondary", known: true },
       "get /wsapi/address_info?email=testuser%40testuser.com primary": { type: "primary", auth: "https://auth_url", prov: "https://prov_url" },
       "get /wsapi/address_info?email=testuser%40testuser.com ajaxError": undefined,
       "post /wsapi/add_email_with_assertion invalid": { success: false },
diff --git a/scripts/browserid.spec b/scripts/browserid.spec
index 1e657bbbdc2c46358c2d12bee05773efcc44520d..d24a0871ee13bd830ca4fd6bd1c6c119859fdc28 100644
--- a/scripts/browserid.spec
+++ b/scripts/browserid.spec
@@ -1,7 +1,7 @@
 %define _rootdir /opt/browserid
 
 Name:          browserid-server
-Version:       0.2012.04.25
+Version:       0.2012.04.27
 Release:       1%{?dist}_%{svnrev}
 Summary:       BrowserID server
 Packager:      Pete Fritchman <petef@mozilla.com>
diff --git a/tests/primary-then-secondary-test.js b/tests/primary-then-secondary-test.js
index bfb72c4b064f3bfd937f25348442d3d07fb11abf..11104396191720812da44e195cb6b2020aea0751 100755
--- a/tests/primary-then-secondary-test.js
+++ b/tests/primary-then-secondary-test.js
@@ -141,6 +141,24 @@ suite.addBatch({
 });
 
 
+// after a small delay, we can authenticate with our password
+suite.addBatch({
+  "after a small delay": {
+    topic: function() { setTimeout(this.callback, 1500); },
+    "authenticating with our newly set password" : {
+      topic: wsapi.post('/wsapi/authenticate_user', {
+        email: TEST_EMAIL,
+        pass: TEST_PASS,
+        ephemeral: false
+      }),
+      "works": function(err, r) {
+        assert.strictEqual(r.code, 200);
+      }
+    }
+  }
+});
+
+
 // adding a second secondary will not let us set the password
 suite.addBatch({
   "add a new email address to our account": {
@@ -159,7 +177,7 @@ suite.addBatch({
         this._token = t;
         assert.strictEqual(typeof t, 'string');
       },
-      "and to complete":  {
+      "and to complete": {
         topic: function(t) {
           wsapi.get('/wsapi/email_for_token', {
             token: t