See here: https://github.com/BitShares/bitshares/blob/master/libraries/blockchain/chain_database.cpp#L900
Yup, it appears to be like I originally assumed. Which means that when it is time for the fired delegate to sign the block, they have the option of doing so. Not sure whether the default client is set up to do it or not (probably does), but it is not like we can rely on that anyway since the delegate can just turn block production off as soon as they are fired. So the assumption should be that if in the very first block of a round all other 100 delegates lose rank in the top 101, then worst case there will be 100 missing blocks until the next round.
Of course my assumption was that the 1 honest delegate waits until they can produce a block in the last four blocks of a round so that they can avoid that 100 block starting disadvantage. The recovering mechanism I discussed in this
post should work fine with the way the delegate updating is done in the current code. I don't really think the code needs to be changed.
What is far more important is that blocks not have hard size limitations that make them invalid blocks if they exceed that size. That way all of the vote update transactions could be stuffed in the single honest delegate's block. Each transaction can still have a max size to prevent abuse.
Edit:
But if we do want to change the code to allow active delegates to be replaced mid-round (to make recovering from the attacks discussed in this thread more convenient for example), then I have a suggestion on how it could be done. So let's say the round begins with block N (where N % 101 == 1). Let's say the order of the delegates producing blocks in this round is (D1, D2, ..., D100, D101). After the first 4 blocks have been produced we are at block N+4 to be produced by delegate D5 and the remaining blocks in the round are to be produced by o=(D6, D7, ..., D100, D101) in that order as of now. Transactions included in block N+4 cause some of the delegates in the set of top 101 delegates to be replaced by another set of delegates of the same size. So let's pretend R={D2, D3, D6, D80, D101} are replaced by A={D102, D103, D104, D105, D106}. Also define a new set of safe delegates, S, which includes all of the delegates who have already produced blocks in this round as well as the delegate producing the current block and the next block (as determined by the current order). So in this case S={D1, D2, D3, D4, D5, D6}. The clients split the remaining delegate order sequence for the round into a head (h=D6) and the tail (tail = (D7, ..., D100, D101)). Take the set consisting of the delegates in tail as T. Define R' = R \ S, which in this example would be R'={D80, D101}. The cardinality of R' is the number of delegates that we can choose from A to create the set A', which is the set of delegate that need to replace the delegates in R' from the tail. Order the delegates in set A according to their approval (and in the case of ties, lexicographical ordering according to their account address), and pick the |R'| delegates with the highest approval from that list to form the set A'. In this example if we assume D102 and D104 have the highest approval rating compared to the rest in A, then A'={D102, D104}. Define T' = (T \ R') ∪ A', in this example T'={D7, D8, ..., D78, D79, D81, D82, ..., D99, D100, D102, D104}. Then create a new tail, tail', which is a sequence consisting of the elements in T' in some random order (use the current random seed as of block N+4 as the random value). I will mathematically represent this as tail' = permutation(T', get_current_random_seed()). Then prepend h to this new tail to get the sequence o' = h || tail' that defines the order of the delegates to produce the remaining blocks N+5 to N+100 (assuming no further changes to the set of active delegate). At the end of the round, the regular method for determining the new active delegates and their order is used (this way D103, D105, and D106 in this example get to be included in the following round). This procedure ensures that the next block producer remains the same even if the current block causes him to no longer be in the top 101 ranks (I think this is important for predictability and performance).
So with the above in place, the single honest delegate is in a better position for recovering from the attack from the other 100 evil delegates. No matter which block he starts the fork off from, the block disadvantage is going to be zero compared to the other evil chain. That means after the next round is complete (assuming they elect 101 new good delegates who don't miss their blocks), the good chain will become the longest chain (by just 1 block but then it will just grow from there). This means that the good chain can recover in at most 51 minutes after collecting all the valid (non-expired) transactions that vote out the 100 bad delegates and replace them with 100 good ones.