def _set_what(self, what: str) -> None:
         self._what = what
-        self._who = None
 
     def _set_who(self, who: '_NickUserHost') -> None:
         self._who = who.copy()
-        self.complete()
 
     def complete(self) -> None:
         'Declare data collection finished, return full or empty content.'
         if '_verb' not in ret:
             self._log(f'PLEASE IMPLEMENT HANDLER FOR: {msg.raw}')
             return
-        for task, tok_names in ret['_tasks'].items():
-            if task.verb == 'set' and task.path == ('user',):
+        for task, tok_names in [t for t in ret['_tasks'].items()
+                                if t[0].verb == 'set']:
+            assert task.path == ('user',)
+            assert tok_names == ['sender']
+            self.db.user_id(ret['sender'])
+        for verb in ('setattr', 'do', 'doafter'):
+            for task, tok_names in [t for t in ret['_tasks'].items()
+                                    if t[0].verb == verb]:
+                node = self
+                for step in task.path:
+                    node = (node[ret[step] if step.isupper() else step]
+                            if isinstance(node, Dict)
+                            else getattr(node, step))
                 for tok_name in tok_names:
-                    self.db.user_id(ret[tok_name])
-                continue
-            node = self
-            for step in task.path:
-                node = (node[ret[step] if step.isupper() else step]
-                        if isinstance(node, Dict)
-                        else getattr(node, step))
-            for tok_name in sorted(tok_names):
-                # FIXME: alphabetical sorting of tok_names merely hack to parse
-                # TOPIC messages, to ensure any setattr_topic:what be processed
-                # before any setattr_topic:who, i.e. properly completing .topic
-                if task.verb == 'setattr':
-                    setattr(node, tok_name, ret[tok_name])
-                elif task.verb == 'do':
-                    getattr(node, tok_name)()
+                    if task.verb == 'setattr':
+                        setattr(node, tok_name, ret[tok_name])
+                    else:
+                        getattr(node, tok_name)()
         if ret['_verb'] == '005':   # RPL_ISUPPORT
             for item in ret['isupport']:
                 if item[0] == '-':
 
         ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
          (_MsgTok.CHANNEL, ':CHAN'),
          (_MsgTok.NICK_USER_HOST, 'setattr_db.channels.CHAN.topic:who'),
-         (_MsgTok.ANY, ':timestamp'))),
+         (_MsgTok.ANY, ':timestamp')),
+        bonus_tasks=('doafter_db.channels.CHAN.topic:complete',)),
 
     _MsgParseExpectation(
         '353',  # RPL_NAMREPLY
         ((_MsgTok.NICKNAME, 'setattr_db.users.me:nick'),
          (_MsgTok.CHANNEL, ':CHAN'),
          _MsgTok.ANY),  # comment
-        bonus_tasks=('do_db.channels.CHAN.user_ids:complete',)),
+        bonus_tasks=('doafter_db.channels.CHAN.user_ids:complete',)),
 
     _MsgParseExpectation(
         'JOIN',
         'ERROR',
         _MsgTok.NONE,
         ((_MsgTok.ANY, 'setattr_db:connection_state'),),
-        bonus_tasks=('do_:close',)),
+        bonus_tasks=('doafter_:close',)),
 
     _MsgParseExpectation(
         'MODE',
         'TOPIC',
         (_MsgTok.NICK_USER_HOST, 'setattr_db.channels.CHAN.topic:who'),
         ((_MsgTok.CHANNEL, ':CHAN'),
-         (_MsgTok.ANY, 'setattr_db.channels.CHAN.topic:what'))),
+         (_MsgTok.ANY, 'setattr_db.channels.CHAN.topic:what')),
+        bonus_tasks=('doafter_db.channels.CHAN.topic:complete',)),
 
     _MsgParseExpectation(
         'QUIT',