How to combine multiple view result sets, limiting the combined result set
Here's what I ended up doing (not using views). I'm using Panels on this site, and my default view for this content-type is controlled via Panelizer. Since I couldn't find a way to do this with Views, I created a custom panels pane (code below).

Basically, this pane accepts one setting: the number of related events to display. The render callback counts the editor-defined related nodes, and grabs more (if needed) based on shared terms.

&lt;?php

$plugin = array(
'single' =&gt; TRUE,
'title' =&gt; t('Suggested Events'),
'description' =&gt; t('Combines curated suggested events with those related by category.'),
'category' =&gt; t('Custom Panes'),
'edit form' =&gt; 'MYMODULE_suggested_events_edit_form',
'render callback' =&gt; 'MYMODULE_suggested_events_render',
'admin info' =&gt; 'MYMODULE_suggested_events_info',
'defaults' =&gt; array(
  'events_to_show' =&gt; 4
),
'all contexts' =&gt; TRUE,
);


/**
 * Edit Form.
 */
function MYMODULE_suggested_events_edit_form($form, &amp;$form_state) {
$conf = $form_state['conf'];

$form['events_to_show'] = array(
  '#title' =&gt; t('Number of events to show'),
  '#description' =&gt; t('Used to control the number of suggested events shown. Defaults to 4.'),
  '#type' =&gt; 'select',
  '#options' =&gt; drupal_map_assoc(range(3, 6)),
  '#default_value' =&gt; $conf['events_to_show'],
  '#required' =&gt; TRUE,
);

return $form;
}


/**
 * Submit callback for settings form.
 */
function MYMODULE_suggested_events_edit_form_submit($form, &amp;$form_state) {

foreach (array_keys($form_state['plugin']['defaults']) as $key) {
  if (isset($form_state['values'][$key])) {
    $form_state['conf'][$key] = $form_state['values'][$key];
  }
}
}


/**
 * Run-time rendering of the content
 */
function MYMODULE_suggested_events_render($subtype, $conf, $args, $contexts) {

  if (isset($contexts['panelizer'])) {
    $nid = $contexts['panelizer']-&gt;data-&gt;nid;
  } else {
    return false;
  }

  // Grab the Category Term IDs from referenced node.
  $node = node_load($nid);
  $categoryField = field_get_items('node', $node, 'field_category');
  $categoryTIDs = array_column($categoryField, 'tid');

  // suggestedEvents are the events which are selected by the editor.
  $suggestedEventsField = field_get_items('node', $node, 'field_event_suggested');

  if (empty($suggestedEventsField)) {
    $suggestedEvents = array();
  } else {
    $suggestedEventsNIDs = array_column($suggestedEventsField, 'target_id');
    $suggestedEvents = entity_load('node', $suggestedEventsNIDs ); // @returns array of entities
  }


  // determine how many events we need to find 
  // based upon the total to display and how many are site-editor-defined
  $relatedEvents = array();
  $relatedEventsCount = 0;
  if (count($suggestedEvents) &lt; $conf['events_to_show']) {
    $relatedEventsCount = $conf['events_to_show'] - count($suggestedEvents);
  }

  if ($relatedEventsCount &gt; 0) {
    // Query for other events that share the referenced categories.
    $query = new EntityFieldQuery();
    $query-&gt;entityCondition('entity_type', 'node')
      -&gt;entityCondition('bundle', 'event')
      -&gt;propertyCondition('status', NODE_PUBLISHED)
      -&gt;propertyCondition('nid', $nid, '&lt;&gt;')
      -&gt;fieldCondition('field_category', 'tid', $categoryTIDs, 'IN')
      -&gt;fieldCondition('field_datetime', 'value', date('Y-m-d').'00:00:00', '&gt;=', 0)
      -&gt;range(0, $relatedEventsCount)
      // Run the query as user 1.
      -&gt;addMetaData('account', user_load(1));

    $result = $query-&gt;execute();
    if (isset($result['node'])) {
      $relatedEventsNIDs = array_keys($result['node']);
      $relatedEvents = entity_load('node', $relatedEventsNIDs);
    } 
  }

  $events = array_merge($suggestedEvents, $relatedEvents);

  $block = new stdClass();
  $block-&gt;title = 'You may also enjoy...';
  $block-&gt;content = '';
  if (!empty($events)) {
    $block-&gt;content .= '&lt;div class="block__content"&gt;';
    $eventsRenderArray = entity_view('node', $events, 'showcase_card');
    $block-&gt;content .= render( $eventsRenderArray );
    $block-&gt;content .= '&lt;/div&gt;';

    return $block;
  } else {
    return false;
  }


}


/**
 * Admin info.
 */
function MYMODULE_suggested_events_info($subtype, $conf, $contexts) {
if (!empty($conf)) {
  $block = new stdClass;
  $block-&gt;title = $conf['override_title'] ? $conf['override_title_text'] : '';
  $block-&gt;content = t('Show @events_to_show suggested events.', array(
    '@events_to_show' =&gt; $conf['events_to_show']
  ));

  return $block;
}
}