evaluateAccuracy(entries, metric, lanternMetric, lanternOrBaseline = 'lantern') {
    const evaluations = [];

    const percentErrors = [];
    for (const entry of entries) {
      const actualMetrics = entry[lanternOrBaseline];
      if (!actualMetrics) throw new Error(`No metrics for ${metric} ${lanternMetric} ${lanternOrBaseline}`);

      const evaluation = this.evaluateSite(
        entry,
        entry.wpt3g,
        actualMetrics,
        metric,
        lanternMetric
      );

      // No data was available at all, skip it.
      if (!evaluation) continue;

      // Data was supposed to be available, but one metric was missing, warn.
      if (!Number.isFinite(evaluation.diff)) {
        const missingMetric = Number.isFinite(entry.wpt3g[metric]) ? lanternMetric : metric;
        const message = `WARNING: ${evaluation.url} was missing values for ${missingMetric}`;
        WARNINGS.push(message);
        continue;
      }

      evaluations.push(evaluation);
      percentErrors.push(evaluation.diffAsPercent);
    }

    percentErrors.sort((a, b) => a - b);

    const p50 = percentErrors[Math.floor((percentErrors.length / 100) * 50)];
    const p90 = percentErrors[Math.floor((percentErrors.length / 100) * 90)];
    const p95 = percentErrors[Math.floor((percentErrors.length / 100) * 95)];
    return {evaluations, p50, p90, p95};
  }
@param {LanternSiteDefinition[]} entries
@param {keyof TargetMetrics} metric
@param {keyof LanternMetrics} lanternMetric
@param {'lantern'|'baseline'} lanternOrBaseline
@return {EstimateEvaluationSummary}