static prepareReportResult(lhr) {
    // If any mutations happen to the report within the renderers, we want the original object untouched
    const clone = /** @type {LH.ReportResult} */ (JSON.parse(JSON.stringify(lhr)));
    upgradeLhrForCompatibility(clone);

    for (const audit of Object.values(clone.audits)) {
      // Attach table/opportunity items with entity information.
      if (audit.details) {
        if (audit.details.type === 'opportunity' || audit.details.type === 'table') {
          if (!audit.details.isEntityGrouped && clone.entities) {
            ReportUtils.classifyEntities(clone.entities, audit.details);
          }
        }
      }
    }

    // For convenience, smoosh all AuditResults into their auditRef (which has just weight & group)
    if (typeof clone.categories !== 'object') throw new Error('No categories provided.');

    /** @type {Map<string, LH.ReportResult.AuditRef>} */
    const acronymToMetricMap = new Map();

    for (const category of Object.values(clone.categories)) {
      // Make basic lookup table for relevantAudits
      category.auditRefs.forEach(metricRef => {
        if (!metricRef.acronym) return;
        acronymToMetricMap.set(metricRef.acronym, metricRef);
      });

      category.auditRefs.forEach(auditRef => {
        const result = clone.audits[auditRef.id];
        auditRef.result = result;

        // Attach any relevantMetric auditRefs
        const relevantAcronyms = Object.keys(auditRef.result.metricSavings || {});
        if (relevantAcronyms.length) {
          auditRef.relevantMetrics = [];
          for (const acronym of relevantAcronyms) {
            const metric = acronymToMetricMap.get(acronym);
            if (!metric) continue;

            auditRef.relevantMetrics.push(metric);
          }
        }

        // attach the stackpacks to the auditRef object
        if (clone.stackPacks) {
          const ids = [auditRef.id, ...auditRef.result.replacesAudits ?? []];
          clone.stackPacks.forEach(pack => {
            const id = ids.find(id => pack.descriptions[id]);
            if (id && pack.descriptions[id]) {
              auditRef.stackPacks = auditRef.stackPacks || [];
              auditRef.stackPacks.push({
                title: pack.title,
                iconDataURL: pack.iconDataURL,
                description: pack.descriptions[id],
              });
            }
          });
        }
      });
    }

    return clone;
  }
Returns a new LHR that's reshaped for slightly better ergonomics within the report rendereer.
Also, sets up the localized UI strings used within renderer and makes changes to old LHRs to be
compatible with current renderer.
The LHR passed in is not mutated.
TODO(team): we all agree the LHR shape change is technical debt we should fix
@param {LH.Result} lhr
@return {LH.ReportResult}