generateCollectionPairEntries = (
  c1,
  c2,
  getEntries,
  absentValue,
) => {
  const e1 = getEntries(c1);
  const e2 = getEntries(c2);

  // Establish a history-dependent comparison scoped to the active invocation
  // and use it to map reverse-preordered entries into an iterator with a
  // narrower total order.
  const fullCompare = makeFullOrderComparatorKit().antiComparator;
  const x = generateFullSortedEntries(e1, compareAntiRank, fullCompare);
  const y = generateFullSortedEntries(e2, compareAntiRank, fullCompare);

  // Maintain a single-result { done, key, value } buffer for each iterator
  // so they can be merged.
  let xDone;
  let xKey;
  let xValue;
  let yDone;
  let yKey;
  let yValue;
  const nonEntry = [undefined, undefined];
  const nextX = () => {
    !xDone || Fail`Internal: nextX must not be called once done`;
    const result = xValue;
    ({ done: xDone, value: [xKey, xValue] = nonEntry } = x.next());
    return result;
  };
  nextX();
  const nextY = () => {
    !yDone || Fail`Internal: nextY must not be called once done`;
    const result = yValue;
    ({ done: yDone, value: [yKey, yValue] = nonEntry } = y.next());
    return result;
  };
  nextY();
  return makeIterator(() => {
    let done = false;
    /** @type {[Key, V | absentValue, V | absentValue]} */
    let value;
    if (xDone && yDone) {
      done = true;
      value = [undefined, absentValue, absentValue];
    } else if (xDone) {
      value = [yKey, absentValue, nextY()];
    } else if (yDone) {
      value = [xKey, nextX(), absentValue];
    } else {
      // Compare the keys to determine if we should return a merged result
      // or a one-sided result.
      const comp = fullCompare(xKey, yKey);
      if (comp === 0) {
        value = [xKey, nextX(), nextY()];
      } else if (comp < 0) {
        value = [xKey, nextX(), absentValue];
      } else if (comp > 0) {
        value = [yKey, absentValue, nextY()];
      } else {
        throw Fail`Unexpected key comparison ${q(comp)} for ${xKey} vs ${yKey}`;
      }
    }
    return harden({ done, value });
  });
}
Returns an iterator that merges reverse-rank-sorted [key, value] entries of
two KeyCollections into a reverse-full-sorted [key, value1, value2] entries
by the key they have in common, representing the value for an absent entry in
either collection as `absentValue`.

@template [C=KeyCollection]
@template [V=unknown]
@param {C} c1
@param {C} c2
@param {(collection: C) => Array<[Key, V]>} getEntries
@param {any} absentValue
@returns {IterableIterator<[Key, V | absentValue, V | absentValue]>}