Creating a very specific custom Views argument handler
Well this is what I ended up with, it's not entirely pretty - and I've never really grasped how the Views structure works, but it works.

/**
 * Implementation of hook_views_data().
 */
function msc_cc_vc_views_data() {
  return array('msc_cc_vc' =&gt; array(
    'table' =&gt; array(
      'group' =&gt; t('MSC Version Control'),
      'base' =&gt; array(
        'title' =&gt; t('MSC Version Control'),
      ),
      'join' =&gt; array(
        'node' =&gt; array(
          // links directly to node via vid
          'table' =&gt; 'node',
          'left_table' =&gt; 'node',
          'left_field' =&gt; 'vid',
          'field' =&gt; 'vid',
        ),
      ),
    ),
    'users_version_tid' =&gt; array(
      'title' =&gt; t('User\'s Version Term ID'),
      'help' =&gt; t('The taxonomy term ID (from the Version vocabulary) of the supplied user UID.'),
      'argument' =&gt; array(
        'field' =&gt; 'uid',
        'handler' =&gt; 'msc_cc_vc_views_handler_argument_users_version',
        'numeric' =&gt; TRUE,
      ),
    ),
  ));
}

/**
 * Implementation of hook_views_handlers().
 */
function msc_cc_vc_views_handlers() {
  return array(
    'info' =&gt; array(
      'path' =&gt; drupal_get_path('module', 'msc_cc_vc') . '/views',
    ),
    'handlers' =&gt; array(
      // argument handlers
      'msc_cc_vc_views_handler_argument_users_version' =&gt; array(
        'parent' =&gt; 'views_handler_argument_many_to_one',
      ),
      // field handlers
      // filter handlers
      // relationship handlers
      // sort handlers
    ),
  );
}


And then the handler itself. Here I have hard-coded the Taxonomy VID because for this application it doesn't matter. You could steal the code for selecting vocabularies from other handlers, you might also want to allow multiple TIDs.

class msc_cc_vc_views_handler_argument_users_version extends views_handler_argument_many_to_one {

  /**
   * Called to implement a relationship in a query.
   */
  function query() {
    $this-&gt;ensure_my_table();

    // This is the supplied UID
    $uid = $this-&gt;value[0];

    // Not great Drupal but let's do some easy processing:
    $profile = content_profile_load('profile', $uid);
    $terms = taxonomy_node_get_terms_by_vocabulary($profile, 8);
    $version  = reset($terms);
    if (empty($version)) {
      drupal_set_message(t('The selected user does not have curriculum version.'), 'warning');
      return;
    }

    $def = $this-&gt;definition;

    // Rebuild the definition to create a unique relationship
    // that forces all results to have the selected version TID.

    $def['table'] = 'term_data';
    $def['type'] = 'INNER';
    $def['left_table'] = $this-&gt;table_alias;
    $def['left_field'] = 'vid';
    $def['field'] = 'revision';

    $def['table formula'] = "(SELECT td.*, tn.vid AS revision FROM {term_data} td INNER JOIN {term_node} tn ON tn.tid = td.tid WHERE td.tid={$version-&gt;tid})";

    $join = new views_join();

    $join-&gt;definition = $def;
    $join-&gt;construct();
    $join-&gt;adjusted = TRUE;

    // use a short alias for this:
    $alias = $def['table'] . '_' . $this-&gt;table;

    $this-&gt;alias = $this-&gt;query-&gt;add_relationship($alias, $join, 'term_data', $this-&gt;relationship);
  }
}


Enjoy.