defineExoClassKit = (
  tag,
  interfaceGuardKit,
  init,
  methodsKit,
  options = {},
) => {
  harden(methodsKit);
  const {
    finish = undefined,
    receiveAmplifier = undefined,
    receiveInstanceTester = undefined,
  } = options;
  const contextMapKit = objectMap(methodsKit, () => new WeakMap());
  const getContextKit = objectMap(
    contextMapKit,
    contextMap => facet => contextMap.get(facet),
  );
  const prototypeKit = defendPrototypeKit(
    tag,
    getContextKit,
    methodsKit,
    true,
    interfaceGuardKit,
  );
  let instanceCount = 0;
  /**
   * @param {Parameters<I>} args
   */
  const makeInstanceKit = (...args) => {
    // Be careful not to freeze the state record
    const state = seal(init(...args));
    // Don't freeze context until we add facets
    /** @type {{ state: ReturnType<I>, facets: any }} */
    const context = { state, facets: null };
    instanceCount += 1;
    const facets = objectMap(prototypeKit, (proto, facetName) => {
      const self = makeSelf(proto, instanceCount);
      contextMapKit[facetName].set(self, context);
      return self;
    });
    context.facets = facets;
    // Be careful not to freeze the state record
    freeze(context);
    if (finish) {
      finish(context);
    }
    return /** @type {GuardedKit<F>} */ (context.facets);
  };

  if (receiveAmplifier) {
    /** @type {Amplify} */
    const amplify = exoFacet => {
      for (const contextMap of values(contextMapKit)) {
        if (contextMap.has(exoFacet)) {
          const { facets } = contextMap.get(exoFacet);
          return facets;
        }
      }
      throw Fail`Must be a facet of ${q(tag)}: ${exoFacet}`;
    };
    harden(amplify);
    receiveAmplifier(amplify);
  }

  if (receiveInstanceTester) {
    /** @type {IsInstance} */
    const isInstance = (exoFacet, facetName = undefined) => {
      if (facetName === undefined) {
        return values(contextMapKit).some(contextMap =>
          contextMap.has(exoFacet),
        );
      }
      assert.typeof(facetName, 'string');
      const contextMap = contextMapKit[facetName];
      contextMap !== undefined ||
        Fail`exo class kit ${q(tag)} has no facet named ${q(facetName)}`;
      return contextMap.has(exoFacet);
    };
    harden(isInstance);
    receiveInstanceTester(isInstance);
  }

  return harden(makeInstanceKit);
}
@template {(...args: any[]) => any} I init function
@template {Record<FacetName, Methods>} F facet methods
@param {string} tag
@param {ExoClassInterfaceGuardKit<F> | undefined } interfaceGuardKit
@param {I} init
@param {ExoClassKitMethods<F, I>} methodsKit
@param {FarClassOptions<
  KitContext<ReturnType<I>, GuardedKit<F>>,
  GuardedKit<F>
>} [options]
@returns {(...args: Parameters<I>) => GuardedKit<F>}