prepare = rawTree => {
    if (!isObject(rawTree)) {
      return;
    }
    // Assertions of the above to narrow the type.
    assert.typeof(rawTree, 'object');
    assert(rawTree !== null);
    if (QCLASS in rawTree) {
      const qclass = rawTree[QCLASS];
      typeof qclass === 'string' ||
        Fail`invalid qclass typeof ${q(typeof qclass)}`;
      assert(!isArray(rawTree));
      switch (rawTree['@qclass']) {
        case 'undefined':
        case 'NaN':
        case 'Infinity':
        case '-Infinity': {
          return;
        }
        case 'bigint': {
          const { digits } = rawTree;
          typeof digits === 'string' ||
            Fail`invalid digits typeof ${q(typeof digits)}`;
          return;
        }
        case '@@asyncIterator': {
          return;
        }
        case 'symbol': {
          const { name } = rawTree;
          assert.typeof(name, 'string');
          const sym = passableSymbolForName(name);
          assert.typeof(sym, 'symbol');
          return;
        }
        case 'tagged': {
          const { tag, payload } = rawTree;
          assert.typeof(tag, 'string');
          prepare(payload);
          return;
        }
        case 'slot': {
          const { index, iface } = rawTree;
          assert.typeof(index, 'number');
          Nat(index);
          if (iface !== undefined) {
            assert.typeof(iface, 'string');
          }
          return;
        }
        case 'hilbert': {
          const { original, rest } = rawTree;
          'original' in rawTree ||
            Fail`Invalid Hilbert Hotel encoding ${rawTree}`;
          prepare(original);
          if ('rest' in rawTree) {
            if (typeof rest !== 'object') {
              throw Fail`Rest ${rest} encoding must be an object`;
            }
            if (rest === null) {
              throw Fail`Rest ${rest} encoding must not be null`;
            }
            if (isArray(rest)) {
              throw Fail`Rest ${rest} encoding must not be an array`;
            }
            if (QCLASS in rest) {
              throw Fail`Rest encoding ${rest} must not contain ${q(QCLASS)}`;
            }
            const names = ownKeys(rest);
            for (const name of names) {
              typeof name === 'string' ||
                Fail`Property name ${name} of ${rawTree} must be a string`;
              prepare(rest[name]);
            }
          }
          return;
        }
        case 'error': {
          const { name, message } = rawTree;
          if (typeof name !== 'string') {
            throw Fail`invalid error name typeof ${q(typeof name)}`;
          }
          getErrorConstructor(name) !== undefined ||
            Fail`Must be the name of an Error constructor ${name}`;
          typeof message === 'string' ||
            Fail`invalid error message typeof ${q(typeof message)}`;
          return;
        }

        default: {
          assert.fail(X`unrecognized ${q(QCLASS)} ${q(qclass)}`, TypeError);
        }
      }
    } else if (isArray(rawTree)) {
      const { length } = rawTree;
      for (let i = 0; i < length; i += 1) {
        prepare(rawTree[i]);
      }
    } else {
      const names = ownKeys(rawTree);
      for (const name of names) {
        if (typeof name !== 'string') {
          throw Fail`Property name ${name} of ${rawTree} must be a string`;
        }
        prepare(rawTree[name]);
      }
    }
  }
The first pass does some input validation.
Its control flow should mirror `recur` as closely as possible
and the two should be maintained together. They must visit everything
in the same order.

TODO now that ibids are gone, we should fold this back together into
one validating pass.

@param {Encoding} rawTree
@returns {void}