diff --git a/helios/migrations/0002_v3_1_new_election_and_voter_fields.py b/helios/migrations/0002_v3_1_new_election_and_voter_fields.py
index dd41fc6356da2a93c52bcc206dc89f06788e7ee2..e75643d805af504ee5b6ec6275150b2c876b8062 100644
--- a/helios/migrations/0002_v3_1_new_election_and_voter_fields.py
+++ b/helios/migrations/0002_v3_1_new_election_and_voter_fields.py
@@ -24,7 +24,8 @@ class Migration(SchemaMigration):
         db.add_column('helios_voter', 'voter_email', self.gf('django.db.models.fields.CharField')(max_length=250, null=True), keep_default=False)
 
         # Adding field 'Election.datatype'
-        db.add_column('helios_election', 'datatype', self.gf('django.db.models.fields.CharField')(default='2011/01/election', max_length=250), keep_default=False)
+        # manually tweaked default value to ensure proper datatype for older elections
+        db.add_column('helios_election', 'datatype', self.gf('django.db.models.fields.CharField')(default='legacy/election', max_length=250), keep_default=False)
 
         # Adding field 'Election.election_type'
         db.add_column('helios_election', 'election_type', self.gf('django.db.models.fields.CharField')(default='election', max_length=250), keep_default=False)
diff --git a/helios/models.py b/helios/models.py
index ba0e3a148875e682f4a16f096d69451a0b6422b4..115056492228d1132def4fa4f7f39d4392ce368a 100644
--- a/helios/models.py
+++ b/helios/models.py
@@ -87,6 +87,13 @@ class Election(models.Model, electionalgs.Election):
   registration_starts_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
   voting_starts_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
   voting_ends_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
+
+  # if this is non-null, then a complaint period, where people can cast a quarantined ballot.
+  # we do NOT call this a "provisional" ballot, since provisional implies that the voter has not
+  # been qualified. We may eventually add this, but it can't be in the same CastVote table, which
+  # is tied to a voter.
+  complaint_period_ends_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
+
   tallying_starts_at = models.DateTimeField(auto_now_add=False, default=None, null=True)
   
   # dates when things were forced to be performed
@@ -730,6 +737,10 @@ class CastVote(models.Model, electionalgs.CastVote):
 
   cast_at = models.DateTimeField(auto_now_add=True)
 
+  # some ballots can be quarantined (this is not the same thing as provisional)
+  quarantined_p = modelsBooleanField(default=False, null=False)
+  released_from_quarantine_at = models.DateTimeField(auto_now_add=False, null=True)
+
   # when is the vote verified?
   verified_at = models.DateTimeField(null=True)
   invalidated_at = models.DateTimeField(null=True)
@@ -742,6 +753,10 @@ class CastVote(models.Model, electionalgs.CastVote):
   def voter_hash(self):
     return self.voter.hash
 
+  @property
+  def is_quarantined(self):
+    return self.quarantined_p and not self.released_from_quarantine_at
+
   def set_tinyhash(self):
     """
     find a tiny version of the hash for a URL slug.
@@ -774,6 +789,10 @@ class CastVote(models.Model, electionalgs.CastVote):
     return cls.objects.filter(voter = voter).order_by('-cast_at')
 
   def verify_and_store(self):
+    # if it's quarantined, don't let this go through
+    if self.is_quarantined:
+      raise Exception("cast vote is quarantined, verification and storage is delayed.")
+
     result = self.vote.verify(self.voter.election)
 
     if result:
diff --git a/helios/tests.py b/helios/tests.py
index 17d123ffbc7764aaafedb0c2312f7d57e9d6979c..078b914ac4029a140ca28aef524ac8bbd6f3c1cc 100644
--- a/helios/tests.py
+++ b/helios/tests.py
@@ -200,6 +200,19 @@ class VoterModelTests(TestCase):
         # check that you can get at the voter user structure
         self.assertEquals(v.user.user_id, v.voter_email)
 
+
+class CastVoteModelTests(TestCase):
+    fixtures = ['users.json', 'election.json']
+
+    def setUp(self):
+        self.election = models.Election.objects.get(short_name='test')
+        self.user = auth_models.User.objects.get(user_id='ben@adida.net', user_type='google')
+
+        # register the voter
+        self.voter = models.Voter.register_user_in_election(self.user, self.election)
+
+    def test_cast_vote(self):
+        assert False
 ##
 ## Black box tests
 ##