docs: private ImmutableList<Fact> rootUnlessThrowable() {
      Step rootSubject = null;
      boolean seenDerivation = false;
      for (Step step : steps) {
        if (step.isCheckCall()) {
          /*
           * If we don't have a description update, don't trigger display of a root object. (If we
           * did, we'd change the messages of a bunch of existing subjects, and we don't want to bite
           * that off yet.)
           *
           * If we do have a description update, then trigger display of a root object but only if the
           * old and new values are "different enough" to be worth both displaying.
           */
          seenDerivation |=
              step.descriptionUpdate != null
                  && step.valuesAreSimilar == OldAndNewValuesAreSimilar.DIFFERENT;
          continue;
        }
  
        if (rootSubject == null) {
          if (step.subject.actual() instanceof Throwable) {
            /*
             * We'll already include the Throwable as a cause of the AssertionError (see rootCause()),
             * so we don't need to include it again in the message.
             */
            return ImmutableList.of();
          }
          rootSubject = step;
        }
      }
      /*
       * TODO(cpovirk): Maybe say "root foo was: ..." instead of just "foo was: ..." if there's more
       * than one foo in the chain, if the description string doesn't start with "foo," and/or if the
       * name we have is just "object?"
       */
      return seenDerivation
          ? ImmutableList.of(
              fact(
                  rootSubject.subject.typeDescription() + " was",
                  rootSubject.subject.actualAsStringNoBrackets()))
          : ImmutableList.<Fact>of();
    }