Repository: GoogleChrome/lighthouse
Pull request #8385 (2019-04-18 01:07:38)

core: replace rawValue with numericValue in audit result
part 2 of apparently 3 for #6199

Following #8343, this now renames the public `rawValue` on `LH.Audit.Result` to `numericValue`. We have very few places we rely on this except the smoke tests, so it's an easy change and a better place to bikeshed on `numericValue` and the public interface than the next PR :)

The last PR will be renaming the variable internal to audits/audit tests.

patrickhulce: I'm a little unclear on what the purpose of this PR is, are we planning on exposing an audit-level property called `numericValue`/whatever we decide on that has the numers and not the `details.timingMs` route or whatever?

If we are, then I think I was confused about what killing `rawValue` meant since this doesn't seem fundamentally different :)

If we aren't and this is all temporary, then I have absolutely no preference on the name so merge away 😆 
brendankenny: > are we planning on exposing an audit-level property called `numericValue`/whatever we decide on that has the numbers here and not the details.timingMs route or whatever?

That's what's this PR does but it's not necessarily the plan :)

I don't think we ever actually settled on a plan, so this is bikeshedding on property name and object structure. Fun for everyone!

I'll try to make a better case tomorrow, but basically I think a large portion of our programmatic users just need something like this, a single numeric value that's a companion to the score, and don't want (or need) to dig into details to do it. They're also not all ms numbers, so it's hard to name the value. I also realize that this doesn't really differentiate the property from `rawValue` except for the (already removed) primacy and booleaness of the property in the audit product :)
brendankenny: (I am curious how many of these remaining rawValues are actually already covered by things in their `details`...)
benschwarz: > I think a large portion of our programmatic users just need something like this, a single numeric value that's a companion to the score, and don't want (or need) to dig into details to do it. 

👬 Strong upvote from me on that @brendankenny 
exterkamp: >  a single numeric value that's a companion to the score

This is the concept.  While I've been trying to analyze variance this has come up a lot.  RawValue is not suitable since it is non-numeric and has a lot of legacy baggage.  So we wanted a numeric only value that could be used for analysis. e.g. TTFB score: 0.7, numericValue: 1159 (1159ms) | DOM size score: 0.9, numericValue: 14 (14 nodes).
patrickhulce: > I think a large portion of our programmatic users just need something like this, a single numeric value that's a companion to the score, and don't want (or need) to dig into details to do it. 

As one of those programmatic users I also strongly upvote this :) 

SGTM!

Patch:
diff --git a/clients/lightrider/lightrider-entry.js b/clients/lightrider/lightrider-entry.js
index d6b86d107..3d33c4749 100644
--- a/clients/lightrider/lightrider-entry.js
+++ b/clients/lightrider/lightrider-entry.js
@@ -26,11 +26,11 @@ const LR_PRESETS = {
  * @param {Connection} connection
  * @param {string} url
  * @param {LH.Flags} flags Lighthouse flags, including `output`
- * @param {{lrDevice?: 'desktop'|'mobile', categoryIDs?: Array<string>, logAssets: boolean, keepRawValues: boolean, configOverride?: LH.Config.Json}} lrOpts Options coming from Lightrider
+ * @param {{lrDevice?: 'desktop'|'mobile', categoryIDs?: Array<string>, logAssets: boolean, configOverride?: LH.Config.Json}} lrOpts Options coming from Lightrider
  * @return {Promise<string|Array<string>|void>}
  */
 async function runLighthouseInLR(connection, url, flags, lrOpts) {
-  const {lrDevice, categoryIDs, logAssets, keepRawValues, configOverride} = lrOpts;
+  const {lrDevice, categoryIDs, logAssets, configOverride} = lrOpts;
 
   // Certain fixes need to kick in under LR, see https://github.com/GoogleChrome/lighthouse/issues/5839
   global.isLightrider = true;
@@ -61,7 +61,7 @@ async function runLighthouseInLR(connection, url, flags, lrOpts) {
 
     // pre process the LHR for proto
     if (flags.output === 'json' && typeof results.report === 'string') {
-      return preprocessor.processForProto(results.report, {keepRawValues});
+      return preprocessor.processForProto(results.report);
     }
 
     return results.report;
diff --git a/docs/recipes/gulp/gulpfile.js b/docs/recipes/gulp/gulpfile.js
index 265e7cf9b..6cdeb8f46 100644
--- a/docs/recipes/gulp/gulpfile.js
+++ b/docs/recipes/gulp/gulpfile.js
@@ -50,7 +50,7 @@ const handleOk = function(results) {
   console.log(results); // eslint-disable-line no-console
   // TODO: use lighthouse results for checking your performance expectations.
   // e.g. process.exit(1) or throw Error if score falls below a certain threshold.
-  // if (results.audits['first-meaningful-paint'].rawValue > 3000) {
+  // if (results.audits['first-meaningful-paint'].numericValue > 3000) {
   //   console.log(`Warning: Time to first meaningful paint ${results.audits['first-meaningful-paint'].displayValue}`);
   //   process.exit(1);
   // }
diff --git a/docs/understanding-results.md b/docs/understanding-results.md
index c90e0c6d9..a98ec06f7 100644
--- a/docs/understanding-results.md
+++ b/docs/understanding-results.md
@@ -55,7 +55,7 @@ An object containing the results of the audits, keyed by their name.
 | explanation | <code>string&#124;undefined</code> | A string indicating the reason for audit failure. |
 | warnings | <code>string[]&#124;undefined</code> | Messages identifying potentially invalid cases |
 | errorMessage | <code>string&#124;undefined</code> | A message set |
-| rawValue | <code>boolean&#124;number</code> | The unscored value determined by the audit. Typically this will match the score if there's no additional information to impart. For performance audits, this value is typically a number indicating the metric value. |
+| numericValue | <code>number&#124;undefined</code> | The unscored value determined by the audit. Typically this will match the score if there's no additional information to impart. For performance audits, this value is typically a number indicating the metric value. |
 | displayValue | `string` | The string to display in the report alongside audit results. If empty, nothing additional is shown. This is typically used to explain additional information such as the number and nature of failing items. |
 | score | <code>number</code> | The scored value determined by the audit as a number `0-1`, representing displayed scores of 0-100. |
 | scoreDisplayMode | <code>"binary"&#124;"numeric"&#124;"error"&#124;"manual"&#124;"notApplicable"&#124;"informative"</code> | A string identifying how the score should be interpreted for display i.e. is the audit pass/fail (score of 1 or 0), did it fail, should it be ignored, or are there shades of gray (scores between 0-1 inclusive). |
diff --git a/lighthouse-core/audits/audit.js b/lighthouse-core/audits/audit.js
index c7184b624..3c9230a44 100644
--- a/lighthouse-core/audits/audit.js
+++ b/lighthouse-core/audits/audit.js
@@ -270,7 +270,7 @@ class Audit {
 
       score,
       scoreDisplayMode,
-      rawValue: product.rawValue,
+      numericValue: product.rawValue,
 
       displayValue: product.displayValue,
       explanation: product.explanation,
diff --git a/lighthouse-core/audits/deprecations.js b/lighthouse-core/audits/deprecations.js
index acea4fd00..d7890c4b4 100644
--- a/lighthouse-core/audits/deprecations.js
+++ b/lighthouse-core/audits/deprecations.js
@@ -25,7 +25,7 @@ class Deprecations extends Audit {
       failureTitle: 'Uses deprecated APIs',
       description: 'Deprecated APIs will eventually be removed from the browser. ' +
           '[Learn more](https://www.chromestatus.com/features#deprecated).',
-      requiredArtifacts: ['ChromeConsoleMessages'],
+      requiredArtifacts: ['ConsoleMessages'],
     };
   }
 
@@ -34,7 +34,7 @@ class Deprecations extends Audit {
    * @return {LH.Audit.Product}
    */
   static audit(artifacts) {
-    const entries = artifacts.ChromeConsoleMessages;
+    const entries = artifacts.ConsoleMessages;
 
     const deprecations = entries.filter(log => log.entry.source === 'deprecation').map(log => {
       return {
diff --git a/lighthouse-core/audits/dobetterweb/geolocation-on-start.js b/lighthouse-core/audits/dobetterweb/geolocation-on-start.js
index a5cdfa328..bd2cfc312 100644
--- a/lighthouse-core/audits/dobetterweb/geolocation-on-start.js
+++ b/lighthouse-core/audits/dobetterweb/geolocation-on-start.js
@@ -25,7 +25,7 @@ class GeolocationOnStart extends ViolationAudit {
       description: 'Users are mistrustful of or confused by sites that request their ' +
           'location without context. Consider tying the request to user gestures instead. ' +
           '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/geolocation-on-load).',
-      requiredArtifacts: ['ChromeConsoleMessages'],
+      requiredArtifacts: ['ConsoleMessages'],
     };
   }
 
diff --git a/lighthouse-core/audits/dobetterweb/no-document-write.js b/lighthouse-core/audits/dobetterweb/no-document-write.js
index e5c42eeed..61edf1a72 100644
--- a/lighthouse-core/audits/dobetterweb/no-document-write.js
+++ b/lighthouse-core/audits/dobetterweb/no-document-write.js
@@ -24,7 +24,7 @@ class NoDocWriteAudit extends ViolationAudit {
       description: 'For users on slow connections, external scripts dynamically injected via ' +
           '`document.write()` can delay page load by tens of seconds. ' +
           '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/document-write).',
-      requiredArtifacts: ['ChromeConsoleMessages'],
+      requiredArtifacts: ['ConsoleMessages'],
     };
   }
 
diff --git a/lighthouse-core/audits/dobetterweb/notification-on-start.js b/lighthouse-core/audits/dobetterweb/notification-on-start.js
index 92e243470..d928c7007 100644
--- a/lighthouse-core/audits/dobetterweb/notification-on-start.js
+++ b/lighthouse-core/audits/dobetterweb/notification-on-start.js
@@ -25,7 +25,7 @@ class NotificationOnStart extends ViolationAudit {
       description: 'Users are mistrustful of or confused by sites that request to send ' +
           'notifications without context. Consider tying the request to user gestures ' +
           'instead. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/notifications-on-load).',
-      requiredArtifacts: ['ChromeConsoleMessages'],
+      requiredArtifacts: ['ConsoleMessages'],
     };
   }
 
diff --git a/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js b/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js
index 2bf4e5be0..036dd798a 100644
--- a/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js
+++ b/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js
@@ -25,7 +25,7 @@ class PassiveEventsAudit extends ViolationAudit {
       description: 'Consider marking your touch and wheel event listeners as `passive` ' +
           'to improve your page\'s scroll performance. ' +
           '[Learn more](https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners).',
-      requiredArtifacts: ['ChromeConsoleMessages'],
+      requiredArtifacts: ['ConsoleMessages'],
     };
   }
 
diff --git a/lighthouse-core/audits/errors-in-console.js b/lighthouse-core/audits/errors-in-console.js
index 74195a8e6..1df3399a4 100644
--- a/lighthouse-core/audits/errors-in-console.js
+++ b/lighthouse-core/audits/errors-in-console.js
@@ -23,7 +23,7 @@ class ErrorLogs extends Audit {
       description: 'Errors logged to the console indicate unresolved problems. ' +
         'They can come from network request failures and other browser concerns.',
       failureTitle: 'Browser errors were logged to the console',
-      requiredArtifacts: ['ChromeConsoleMessages', 'RuntimeExceptions'],
+      requiredArtifacts: ['ConsoleMessages', 'RuntimeExceptions'],
     };
   }
 
@@ -32,7 +32,7 @@ class ErrorLogs extends Audit {
    * @return {LH.Audit.Product}
    */
   static audit(artifacts) {
-    const consoleEntries = artifacts.ChromeConsoleMessages;
+    const consoleEntries = artifacts.ConsoleMessages;
     const runtimeExceptions = artifacts.RuntimeExceptions;
     /** @type {Array<{source: string, description: string|undefined, url: string|undefined}>} */
     const consoleRows =
diff --git a/lighthouse-core/audits/violation-audit.js b/lighthouse-core/audits/violation-audit.js
index b259537ee..92f434930 100644
--- a/lighthouse-core/audits/violation-audit.js
+++ b/lighthouse-core/audits/violation-audit.js
@@ -15,7 +15,7 @@ class ViolationAudit extends Audit {
    */
   static getViolationResults(artifacts, pattern) {
     const seen = new Set();
-    return artifacts.ChromeConsoleMessages
+    return artifacts.ConsoleMessages
         .map(message => message.entry)
         .filter(entry => entry.url && entry.source === 'violation' && pattern.test(entry.text))
         .map(entry => ({label: `line: ${entry.lineNumber}`, url: entry.url}))
diff --git a/lighthouse-core/computed/page-dependency-graph.js b/lighthouse-core/computed/page-dependency-graph.js
index 2a9a93442..292eafbd8 100644
--- a/lighthouse-core/computed/page-dependency-graph.js
+++ b/lighthouse-core/computed/page-dependency-graph.js
@@ -30,9 +30,23 @@ class PageDependencyGraph {
   static getNetworkInitiators(record) {
     if (!record.initiator) return [];
     if (record.initiator.url) return [record.initiator.url];
-    if (record.initiator.type === 'script' && record.initiator.stack) {
-      const frames = record.initiator.stack.callFrames;
-      return Array.from(new Set(frames.map(frame => frame.url))).filter(Boolean);
+    if (record.initiator.type === 'script') {
+      // Script initiators have the stack of callFrames from all functions that led to this request.
+      // If async stacks are enabled, then the stack will also have the parent functions that asynchronously
+      // led to this request chained in the `parent` property.
+      /** @type {Set<string>} */
+      const scriptURLs = new Set();
+      let stack = record.initiator.stack;
+      while (stack) {
+        const callFrames = stack.callFrames || [];
+        for (const frame of callFrames) {
+          if (frame.url) scriptURLs.add(frame.url);
+        }
+
+        stack = stack.parent;
+      }
+
+      return Array.from(scriptURLs);
     }
 
     return [];
diff --git a/lighthouse-core/config/default-config.js b/lighthouse-core/config/default-config.js
index 86dc25925..48951810b 100644
--- a/lighthouse-core/config/default-config.js
+++ b/lighthouse-core/config/default-config.js
@@ -114,7 +114,7 @@ const defaultConfig = {
       'css-usage',
       'viewport-dimensions',
       'runtime-exceptions',
-      'chrome-console-messages',
+      'console-messages',
       'anchor-elements',
       'image-elements',
       'link-elements',
@@ -475,6 +475,7 @@ const defaultConfig = {
         {id: 'link-text', weight: 1, group: 'seo-content'},
         {id: 'is-crawlable', weight: 1, group: 'seo-crawl'},
         {id: 'robots-txt', weight: 1, group: 'seo-crawl'},
+        {id: 'image-alt', weight: 1, group: 'seo-content'},
         {id: 'hreflang', weight: 1, group: 'seo-content'},
         {id: 'canonical', weight: 1, group: 'seo-content'},
         {id: 'font-size', weight: 1, group: 'seo-mobile'},
diff --git a/lighthouse-core/gather/driver.js b/lighthouse-core/gather/driver.js
index 61e97ff8e..38fe38320 100644
--- a/lighthouse-core/gather/driver.js
+++ b/lighthouse-core/gather/driver.js
@@ -525,7 +525,14 @@ class Driver {
    * @return {Promise<{url: string, data: string}|null>}
    */
   async getAppManifest() {
-    this.setNextProtocolTimeout(3000);
+    // In all environments but LR, Page.getAppManifest finishes very quickly.
+    // In LR, there is a bug that causes this command to hang until outgoing
+    // requests finish. This has been seen in long polling (where it will never
+    // return) and when other requests take a long time to finish. We allow 10 seconds
+    // for outgoing requests to finish. Anything more, and we continue the run without
+    // a manifest.
+    // Googlers, see: http://b/124008171
+    this.setNextProtocolTimeout(10000);
     let response;
     try {
       response = await this.sendCommand('Page.getAppManifest');
@@ -1337,9 +1344,6 @@ class Driver {
     const uniqueCategories = Array.from(new Set(traceCategories));
 
     // Check any domains that could interfere with or add overhead to the trace.
-    if (this.isDomainEnabled('Debugger')) {
-      throw new Error('Debugger domain enabled when starting trace');
-    }
     if (this.isDomainEnabled('CSS')) {
       throw new Error('CSS domain enabled when starting trace');
     }
@@ -1405,6 +1409,18 @@ class Driver {
     return this.sendCommand('Runtime.enable');
   }
 
+  /**
+   * Enables `Debugger` domain to receive async stacktrace information on network request initiators.
+   * This is critical for tracing certain performance simulation situations.
+   *
+   * @return {Promise<void>}
+   */
+  async enableAsyncStacks() {
+    await this.sendCommand('Debugger.enable');
+    await this.sendCommand('Debugger.setSkipAllPauses', {skip: true});
+    await this.sendCommand('Debugger.setAsyncCallStackDepth', {maxDepth: 8});
+  }
+
   /**
    * @param {LH.Config.Settings} settings
    * @return {Promise<void>}
diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js
index 033a9a8bf..f7efa385f 100644
--- a/lighthouse-core/gather/gather-runner.js
+++ b/lighthouse-core/gather/gather-runner.js
@@ -33,7 +33,7 @@ const Driver = require('../gather/driver.js'); // eslint-disable-line no-unused-
  *     i. assertNoSameOriginServiceWorkerClients
  *     ii. retrieve and save userAgent
  *     iii. beginEmulation
- *     iv. enableRuntimeEvents
+ *     iv. enableRuntimeEvents/enableAsyncStacks
  *     v. evaluateScriptOnLoad rescue native Promise from potential polyfill
  *     vi. register a performance observer
  *     vii. register dialog dismisser
@@ -109,6 +109,7 @@ class GatherRunner {
     await driver.assertNoSameOriginServiceWorkerClients(options.requestedUrl);
     await driver.beginEmulation(options.settings);
     await driver.enableRuntimeEvents();
+    await driver.enableAsyncStacks();
     await driver.cacheNatives();
     await driver.registerPerformanceObserver();
     await driver.dismissJavaScriptDialogs();
diff --git a/lighthouse-core/gather/gatherers/chrome-console-messages.js b/lighthouse-core/gather/gatherers/console-messages.js
similarity index 92%
rename from lighthouse-core/gather/gatherers/chrome-console-messages.js
rename to lighthouse-core/gather/gatherers/console-messages.js
index 2444e6c7f..3093c9746 100644
--- a/lighthouse-core/gather/gatherers/chrome-console-messages.js
+++ b/lighthouse-core/gather/gatherers/console-messages.js
@@ -12,7 +12,7 @@
 
 const Gatherer = require('./gatherer');
 
-class ChromeConsoleMessages extends Gatherer {
+class ConsoleMessages extends Gatherer {
   constructor() {
     super();
     /** @type {Array<LH.Crdp.Log.EntryAddedEvent>} */
@@ -41,7 +41,7 @@ class ChromeConsoleMessages extends Gatherer {
 
   /**
    * @param {LH.Gatherer.PassContext} passContext
-   * @return {Promise<LH.Artifacts['ChromeConsoleMessages']>}
+   * @return {Promise<LH.Artifacts['ConsoleMessages']>}
    */
   async afterPass(passContext) {
     await passContext.driver.sendCommand('Log.stopViolationsReport');
@@ -51,4 +51,4 @@ class ChromeConsoleMessages extends Gatherer {
   }
 }
 
-module.exports = ChromeConsoleMessages;
+module.exports = ConsoleMessages;
diff --git a/lighthouse-core/lib/proto-preprocessor.js b/lighthouse-core/lib/proto-preprocessor.js
index 77b40feda..0db83e1fe 100644
--- a/lighthouse-core/lib/proto-preprocessor.js
+++ b/lighthouse-core/lib/proto-preprocessor.js
@@ -17,11 +17,8 @@ const fs = require('fs');
 
 /**
   * @param {string} result
-  * @param {{keepRawValues?: boolean}} opts
   */
-function processForProto(result, opts = {}) {
-  const {keepRawValues = false} = opts;
-
+function processForProto(result) {
   /** @type {LH.Result} */
   const reportJson = JSON.parse(result);
 
@@ -56,12 +53,8 @@ function processForProto(result, opts = {}) {
           audit.scoreDisplayMode = 'notApplicable';
         }
       }
-      // Drop raw values. https://github.com/GoogleChrome/lighthouse/issues/6199
-      if (!keepRawValues && 'rawValue' in audit) {
-        delete audit.rawValue;
-      }
-      // Normalize displayValue to always be a string, not an array. #6200
 
+      // Normalize displayValue to always be a string, not an array. #6200
       if (Array.isArray(audit.displayValue)) {
         /** @type {Array<any>}*/
         const values = [];
diff --git a/proto/lighthouse-result.proto b/proto/lighthouse-result.proto
index df9a044ea..76e9dfc90 100644
--- a/proto/lighthouse-result.proto
+++ b/proto/lighthouse-result.proto
@@ -283,6 +283,11 @@ message AuditResult {
   // List of warnings associated with this audit
   // type of `Value` since this can be null
   google.protobuf.Value warnings = 10;
+
+  // A numeric value that has a meaning specific to the audit, e.g. the number
+  // of nodes in the DOM or the timestamp of a specific load event. More
+  // information can be found in the audit details, if present.
+  google.protobuf.DoubleValue numeric_value = 11;
 }
 
 // Message containing the i18n data for the LHR - Version 1
diff --git a/proto/sample_v2_round_trip.json b/proto/sample_v2_round_trip.json
index e9a1122bf..215f93705 100644
--- a/proto/sample_v2_round_trip.json
+++ b/proto/sample_v2_round_trip.json
@@ -137,6 +137,7 @@
             }, 
             "displayValue": "1.2\u00a0s", 
             "id": "bootup-time", 
+            "numericValue": 1150.573, 
             "score": 0.92, 
             "scoreDisplayMode": "numeric", 
             "title": "JavaScript execution time"
@@ -460,6 +461,7 @@
                 "type": "debugdata"
             }, 
             "id": "diagnostics", 
+            "numericValue": 1.0, 
             "score": null, 
             "scoreDisplayMode": "informative", 
             "title": "Diagnostics"
@@ -536,6 +538,7 @@
             }, 
             "displayValue": "31 elements", 
             "id": "dom-size", 
+            "numericValue": 31.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Avoids an excessive DOM size"
@@ -562,6 +565,7 @@
                 "type": "opportunity"
             }, 
             "id": "efficient-animated-content", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Use video formats for animated content"
@@ -611,6 +615,7 @@
                 "type": "table"
             }, 
             "id": "errors-in-console", 
+            "numericValue": 5.0, 
             "score": 0.0, 
             "scoreDisplayMode": "binary", 
             "title": "Browser errors were logged to the console"
@@ -619,6 +624,7 @@
             "description": "Estimated Input Latency is an estimate of how long your app takes to respond to user input, in milliseconds, during the busiest 5s window of page load. If your latency is higher than 50 ms, users may perceive your app as laggy. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).", 
             "displayValue": "20\u00a0ms", 
             "id": "estimated-input-latency", 
+            "numericValue": 16.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Estimated Input Latency"
@@ -688,6 +694,7 @@
             "description": "First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint).", 
             "displayValue": "4.0\u00a0s", 
             "id": "first-contentful-paint", 
+            "numericValue": 3969.135, 
             "score": 0.51, 
             "scoreDisplayMode": "numeric", 
             "title": "First Contentful Paint"
@@ -696,6 +703,7 @@
             "description": "First CPU Idle marks the first time at which the page's main thread is quiet enough to handle input. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).", 
             "displayValue": "4.9\u00a0s", 
             "id": "first-cpu-idle", 
+            "numericValue": 4927.278, 
             "score": 0.72, 
             "scoreDisplayMode": "numeric", 
             "title": "First CPU Idle"
@@ -704,6 +712,7 @@
             "description": "First Meaningful Paint measures when the primary content of a page is visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).", 
             "displayValue": "4.0\u00a0s", 
             "id": "first-meaningful-paint", 
+            "numericValue": 3969.136, 
             "score": 0.51, 
             "scoreDisplayMode": "numeric", 
             "title": "First Meaningful Paint"
@@ -1020,6 +1029,7 @@
             "description": "Time to interactive is the amount of time it takes for the page to become fully interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).", 
             "displayValue": "4.9\u00a0s", 
             "id": "interactive", 
+            "numericValue": 4927.278, 
             "score": 0.78, 
             "scoreDisplayMode": "numeric", 
             "title": "Time to Interactive"
@@ -1240,6 +1250,7 @@
         "load-fast-enough-for-pwa": {
             "description": "A fast page load over a cellular network ensures a good mobile user experience. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/fast-3g).", 
             "id": "load-fast-enough-for-pwa", 
+            "numericValue": 4927.278, 
             "score": 1.0, 
             "scoreDisplayMode": "binary", 
             "title": "Page load is fast enough on mobile networks"
@@ -1337,6 +1348,7 @@
                 "type": "table"
             }, 
             "id": "main-thread-tasks", 
+            "numericValue": 16.0, 
             "score": null, 
             "scoreDisplayMode": "informative", 
             "title": "Tasks"
@@ -1398,6 +1410,7 @@
             }, 
             "displayValue": "1.5\u00a0s", 
             "id": "mainthread-work-breakdown", 
+            "numericValue": 1548.5690000000002, 
             "score": 0.96, 
             "scoreDisplayMode": "numeric", 
             "title": "Minimizes main-thread work"
@@ -1413,6 +1426,7 @@
             "description": "The potential First Input Delay that your users could experience is the duration, in milliseconds, of the longest task.", 
             "displayValue": "120\u00a0ms", 
             "id": "max-potential-fid", 
+            "numericValue": 122.537, 
             "score": 0.92, 
             "scoreDisplayMode": "numeric", 
             "title": "Max Potential FID"
@@ -1484,6 +1498,7 @@
                 "type": "debugdata"
             }, 
             "id": "metrics", 
+            "numericValue": 4927.278, 
             "score": null, 
             "scoreDisplayMode": "informative", 
             "title": "Metrics"
@@ -1724,6 +1739,7 @@
                 "type": "table"
             }, 
             "id": "network-requests", 
+            "numericValue": 18.0, 
             "score": null, 
             "scoreDisplayMode": "informative", 
             "title": "Network Requests"
@@ -1758,6 +1774,7 @@
             }, 
             "displayValue": "0\u00a0ms", 
             "id": "network-rtt", 
+            "numericValue": 1.7249999999999943, 
             "score": null, 
             "scoreDisplayMode": "informative", 
             "title": "Network Round Trip Times"
@@ -1792,6 +1809,7 @@
             }, 
             "displayValue": "570\u00a0ms", 
             "id": "network-server-latency", 
+            "numericValue": 572.829, 
             "score": null, 
             "scoreDisplayMode": "informative", 
             "title": "Server Backend Latencies"
@@ -1974,6 +1992,7 @@
                 "type": "opportunity"
             }, 
             "id": "offscreen-images", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Defer offscreen images", 
@@ -2052,6 +2071,7 @@
                 "type": "opportunity"
             }, 
             "id": "redirects", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Avoid multiple page redirects"
@@ -2115,6 +2135,7 @@
             }, 
             "displayValue": "Potential savings of 1,130\u00a0ms", 
             "id": "render-blocking-resources", 
+            "numericValue": 1129.0, 
             "score": 0.46, 
             "scoreDisplayMode": "numeric", 
             "title": "Eliminate render-blocking resources"
@@ -2200,6 +2221,7 @@
             "description": "Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index).", 
             "displayValue": "4.4\u00a0s", 
             "id": "speed-index", 
+            "numericValue": 4417.0, 
             "score": 0.74, 
             "scoreDisplayMode": "numeric", 
             "title": "Speed Index"
@@ -2297,6 +2319,7 @@
             }, 
             "displayValue": "Root document took 570\u00a0ms", 
             "id": "time-to-first-byte", 
+            "numericValue": 570.5630000000001, 
             "score": 1.0, 
             "scoreDisplayMode": "binary", 
             "title": "Server response times are low (TTFB)"
@@ -2362,6 +2385,7 @@
             }, 
             "displayValue": "Total size was 157\u00a0KB", 
             "id": "total-byte-weight", 
+            "numericValue": 160738.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Avoids enormous network payloads"
@@ -2376,6 +2400,7 @@
                 "type": "opportunity"
             }, 
             "id": "unminified-css", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Minify CSS"
@@ -2414,6 +2439,7 @@
             }, 
             "displayValue": "Potential savings of 30\u00a0KB", 
             "id": "unminified-javascript", 
+            "numericValue": 150.0, 
             "score": 0.88, 
             "scoreDisplayMode": "numeric", 
             "title": "Minify JavaScript", 
@@ -2429,6 +2455,7 @@
                 "type": "opportunity"
             }, 
             "id": "unused-css-rules", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Remove unused CSS"
@@ -2646,6 +2673,7 @@
             }, 
             "displayValue": "11 resources found", 
             "id": "uses-long-cache-ttl", 
+            "numericValue": 103455.0, 
             "score": 0.58, 
             "scoreDisplayMode": "numeric", 
             "title": "Serve static assets with an efficient cache policy"
@@ -2660,6 +2688,7 @@
                 "type": "opportunity"
             }, 
             "id": "uses-optimized-images", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Efficiently encode images", 
@@ -2710,6 +2739,7 @@
                 "type": "opportunity"
             }, 
             "id": "uses-rel-preconnect", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Preconnect to required origins", 
@@ -2724,6 +2754,7 @@
                 "type": "opportunity"
             }, 
             "id": "uses-rel-preload", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Preload key requests"
@@ -2738,6 +2769,7 @@
                 "type": "opportunity"
             }, 
             "id": "uses-responsive-images", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Properly size images", 
@@ -2781,6 +2813,7 @@
             }, 
             "displayValue": "Potential savings of 63\u00a0KB", 
             "id": "uses-text-compression", 
+            "numericValue": 300.0, 
             "score": 0.75, 
             "scoreDisplayMode": "numeric", 
             "title": "Enable text compression"
@@ -2824,6 +2857,7 @@
             }, 
             "displayValue": "Potential savings of 9\u00a0KB", 
             "id": "uses-webp-images", 
+            "numericValue": 0.0, 
             "score": 1.0, 
             "scoreDisplayMode": "numeric", 
             "title": "Serve images in next-gen formats", 
@@ -3478,6 +3512,11 @@
                     "id": "robots-txt", 
                     "weight": 0.0
                 }, 
+                {
+                    "group": "seo-content", 
+                    "id": "image-alt", 
+                    "weight": 1.0
+                }, 
                 {
                     "group": "seo-content", 
                     "id": "hreflang", 
@@ -3511,7 +3550,7 @@
             "description": "These checks ensure that your page is optimized for search engine results ranking. There are additional factors Lighthouse does not check that may affect your search ranking. [Learn more](https://support.google.com/webmasters/answer/35769).", 
             "id": "seo", 
             "manualDescription": "Run these additional validators on your site to check additional SEO best practices.", 
-            "score": 0.9, 
+            "score": 0.82, 
             "title": "SEO"
         }
     }, 
diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts
index db5e250f4..a563f5648 100644
--- a/types/artifacts.d.ts
+++ b/types/artifacts.d.ts
@@ -47,11 +47,33 @@ declare global {
       Timing: Artifacts.MeasureEntry[];
     }
 
+    /**
+     * Artifacts provided by the default gatherers that are exposed to plugins with a hardended API.
+     * NOTE: any breaking changes here are considered breaking Lighthouse changes that must be done
+     * on a major version bump.
+     */
+    export interface PublicGathererArtifacts {
+      /** Console deprecation and intervention warnings logged by Chrome during page load. */
+      ConsoleMessages: Crdp.Log.EntryAddedEvent[];
+      /** Information on size and loading for all the images in the page. Natural size information for `picture` and CSS images is only available if the image was one of the largest 50 images. */
+      ImageElements: Artifacts.ImageElement[];
+      /** All the link elements on the page or equivalently declared in `Link` headers. @see https://html.spec.whatwg.org/multipage/links.html */
+      LinkElements: Artifacts.LinkElement[];
+      /** The values of the <meta> elements in the head. */
+      MetaElements: Array<{name: string, content?: string}>;
+      /** Set of exceptions thrown during page load. */
+      RuntimeExceptions: Crdp.Runtime.ExceptionThrownEvent[];
+      /** Information on all script elements in the page. Also contains the content of all requested scripts and the networkRecord requestId that contained their content. Note, HTML documents will have one entry per script tag, all with the same requestId. */
+      ScriptElements: Array<Artifacts.ScriptElement>;
+      /** The dimensions and devicePixelRatio of the loaded viewport. */
+      ViewportDimensions: Artifacts.ViewportDimensions;
+    }
+
     /**
      * Artifacts provided by the default gatherers. Augment this interface when adding additional
-     * gatherers.
+     * gatherers. Changes to these artifacts are not considered a breaking Lighthouse change.
      */
-    export interface GathererArtifacts {
+    export interface GathererArtifacts extends PublicGathererArtifacts {
       /** The results of running the aXe accessibility tests on the page. */
       Accessibility: Artifacts.Accessibility;
       /** Array of all anchors on the page. */
@@ -60,8 +82,6 @@ declare global {
       AppCacheManifest: string | null;
       /** Array of all URLs cached in CacheStorage. */
       CacheContents: string[];
-      /** Console deprecation and intervention warnings logged by Chrome during page load. */
-      ChromeConsoleMessages: Crdp.Log.EntryAddedEvent[];
       /** CSS coverage information for styles used by page's final state. */
       CSSUsage: {rules: Crdp.CSS.RuleUsage[], stylesheets: Artifacts.CSSStyleSheetInfo[]};
       /** Information on the document's doctype(or null if not present), specifically the name, publicId, and systemId.
@@ -71,26 +91,18 @@ declare global {
       DOMStats: Artifacts.DOMStats;
       /** Relevant attributes and child properties of all <object>s, <embed>s and <applet>s in the page. */
       EmbeddedContent: Artifacts.EmbeddedContentInfo[];
-      /** All the link elements on the page or equivalently declared in `Link` headers. @see https://html.spec.whatwg.org/multipage/links.html */
-      LinkElements: Artifacts.LinkElement[];
       /** Information for font faces used in the page. */
       Fonts: Artifacts.Font[];
       /** Information on poorly sized font usage and the text affected by it. */
       FontSize: Artifacts.FontSize;
-      /** The hreflang and href values of all link[rel=alternate] nodes found in HEAD. */
-      Hreflang: {href: string, hreflang: string}[];
       /** The page's document body innerText if loaded with JavaScript disabled. */
       HTMLWithoutJavaScript: {bodyText: string, hasNoScript: boolean};
       /** Whether the page ended up on an HTTPS page after attempting to load the HTTP version. */
       HTTPRedirect: {value: boolean};
-      /** Information on size and loading for all the images in the page. Natural size information for `picture` and CSS images is only available if the image was one of the largest 50 images. */
-      ImageElements: Artifacts.ImageElement[];
       /** JS coverage information for code used during page load. */
       JsUsage: Crdp.Profiler.ScriptCoverage[];
       /** Parsed version of the page's Web App Manifest, or null if none found. */
       Manifest: Artifacts.Manifest | null;
-      /** The values of the <meta> elements in the head. */
-      MetaElements: Array<{name: string, content?: string}>;
       /** The URL loaded with interception */
       MixedContent: {url: string};
       /** The status code of the attempted load of the page while network access is disabled. */
@@ -103,10 +115,6 @@ declare global {
       ResponseCompression: {requestId: string, url: string, mimeType: string, transferSize: number, resourceSize: number, gzipSize?: number}[];
       /** Information on fetching and the content of the /robots.txt file. */
       RobotsTxt: {status: number|null, content: string|null};
-      /** Set of exceptions thrown during page load. */
-      RuntimeExceptions: Crdp.Runtime.ExceptionThrownEvent[];
-      /** Information on all script elements in the page. Also contains the content of all requested scripts and the networkRecord requestId that contained their content. Note, HTML documents will have one entry per script tag, all with the same requestId. */
-      ScriptElements: Array<Artifacts.ScriptElement>;
       /** Version information for all ServiceWorkers active after the first page load. */
       ServiceWorker: {versions: Crdp.ServiceWorker.ServiceWorkerVersion[], registrations: Crdp.ServiceWorker.ServiceWorkerRegistration[]};
       /** The status of an offline fetch of the page's start_url. -1 and a explanation if missing or there was an error. */
@@ -115,8 +123,6 @@ declare global {
       TagsBlockingFirstPaint: Artifacts.TagBlockingFirstPaint[];
       /** Information about tap targets including their position and size. */
       TapTargets: Artifacts.TapTarget[];
-      /** The dimensions and devicePixelRatio of the loaded viewport. */
-      ViewportDimensions: Artifacts.ViewportDimensions;
     }
 
     module Artifacts {
diff --git a/types/audit.d.ts b/types/audit.d.ts
index 6a2cc25cd..9be3f533d 100644
--- a/types/audit.d.ts
+++ b/types/audit.d.ts
@@ -113,7 +113,7 @@ declare global {
       /** A more detailed description that describes why the audit is important and links to Lighthouse documentation on the audit; markdown links supported. */
       description: string;
       /** A numeric value that has a meaning specific to the audit, e.g. the number of nodes in the DOM or the timestamp of a specific load event. More information can be found in the audit details, if present. */
-      rawValue?: number;
+      numericValue?: number;
       /** Extra information about the page provided by some types of audits, in one of several possible forms that can be rendered in the HTML report. */
       details?: Audit.Details;
     }


Test patch:
diff --git a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
index aeaddcff2..593c3c48d 100644
--- a/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
+++ b/lighthouse-cli/test/cli/__snapshots__/index-test.js.snap
@@ -962,6 +962,11 @@ Object {
           "id": "robots-txt",
           "weight": 1,
         },
+        Object {
+          "group": "seo-content",
+          "id": "image-alt",
+          "weight": 1,
+        },
         Object {
           "group": "seo-content",
           "id": "hreflang",
@@ -1079,7 +1084,7 @@ Object {
           "path": "runtime-exceptions",
         },
         Object {
-          "path": "chrome-console-messages",
+          "path": "console-messages",
         },
         Object {
           "path": "anchor-elements",
diff --git a/lighthouse-cli/test/cli/run-test.js b/lighthouse-cli/test/cli/run-test.js
index ea233fb75..7c00cf961 100644
--- a/lighthouse-cli/test/cli/run-test.js
+++ b/lighthouse-cli/test/cli/run-test.js
@@ -65,7 +65,7 @@ describe('CLI run', function() {
       assert.strictEqual(fileResults.fetchTime, lhr.fetchTime);
       assert.strictEqual(fileResults.requestedUrl, lhr.requestedUrl);
       assert.strictEqual(fileResults.finalUrl, lhr.finalUrl);
-      assert.strictEqual(fileResults.audits.viewport.rawValue, lhr.audits.viewport.rawValue);
+      assert.strictEqual(fileResults.audits.viewport.score, lhr.audits.viewport.score);
       assert.strictEqual(
           Object.keys(fileResults.audits).length,
           Object.keys(lhr.audits).length);
diff --git a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js
index 360775167..5824d6487 100644
--- a/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js
+++ b/lighthouse-cli/test/smokehouse/dobetterweb/dbw-expectations.js
@@ -75,7 +75,7 @@ module.exports = [
         },
         'render-blocking-resources': {
           score: '<1',
-          rawValue: '>100',
+          numericValue: '>100',
           details: {
             items: {
               length: 7,
@@ -145,7 +145,7 @@ module.exports = [
         },
         'dom-size': {
           score: 1,
-          rawValue: 31,
+          numericValue: 31,
           details: {
             items: [
               {statistic: 'Total DOM Elements', value: '31'},
diff --git a/lighthouse-cli/test/smokehouse/perf/expectations.js b/lighthouse-cli/test/smokehouse/perf/expectations.js
index 18b0ff7df..3fcebd574 100644
--- a/lighthouse-cli/test/smokehouse/perf/expectations.js
+++ b/lighthouse-cli/test/smokehouse/perf/expectations.js
@@ -27,8 +27,8 @@ module.exports = [
           score: '>=0.90',
         },
         'time-to-first-byte': {
-        // Can be flaky, so test float rawValue instead of boolean score
-          rawValue: '<1000',
+          // Can be flaky, so test float numericValue instead of boolean score
+          numericValue: '<1000',
         },
         'network-requests': {
           details: {
@@ -39,7 +39,7 @@ module.exports = [
         },
         'uses-rel-preload': {
           score: '<1',
-          rawValue: '>500',
+          numericValue: '>500',
           warnings: {
             0: /level-2.*warning/,
             length: 1,
diff --git a/lighthouse-cli/test/smokehouse/perf/lantern-expectations.js b/lighthouse-cli/test/smokehouse/perf/lantern-expectations.js
index 373fb6f4d..5186beb4b 100644
--- a/lighthouse-cli/test/smokehouse/perf/lantern-expectations.js
+++ b/lighthouse-cli/test/smokehouse/perf/lantern-expectations.js
@@ -15,13 +15,13 @@ module.exports = [
       finalUrl: 'http://localhost:10200/online-only.html',
       audits: {
         'first-contentful-paint': {
-          rawValue: '>2000',
+          numericValue: '>2000',
         },
         'first-cpu-idle': {
-          rawValue: '>2000',
+          numericValue: '>2000',
         },
         'interactive': {
-          rawValue: '>2000',
+          numericValue: '>2000',
         },
       },
     },
diff --git a/lighthouse-cli/test/smokehouse/redirects/expectations.js b/lighthouse-cli/test/smokehouse/redirects/expectations.js
index f3cef7150..6abd8c746 100644
--- a/lighthouse-cli/test/smokehouse/redirects/expectations.js
+++ b/lighthouse-cli/test/smokehouse/redirects/expectations.js
@@ -18,7 +18,7 @@ module.exports = [
       audits: {
         'redirects': {
           score: '<1',
-          rawValue: '>=500',
+          numericValue: '>=500',
           details: {
             items: {
               length: 3,
@@ -35,7 +35,7 @@ module.exports = [
       audits: {
         'redirects': {
           score: 1,
-          rawValue: '>=250',
+          numericValue: '>=250',
           details: {
             items: {
               length: 2,
diff --git a/lighthouse-cli/test/smokehouse/tricky-metrics/expectations.js b/lighthouse-cli/test/smokehouse/tricky-metrics/expectations.js
index 189610ad0..b7050ef4a 100644
--- a/lighthouse-cli/test/smokehouse/tricky-metrics/expectations.js
+++ b/lighthouse-cli/test/smokehouse/tricky-metrics/expectations.js
@@ -16,11 +16,11 @@ module.exports = [
       audits: {
         'first-cpu-idle': {
           score: '<75',
-          rawValue: '>9000',
+          numericValue: '>9000',
         },
         'interactive': {
           score: '<75',
-          rawValue: '>9000',
+          numericValue: '>9000',
         },
       },
     },
@@ -31,7 +31,7 @@ module.exports = [
       finalUrl: 'http://localhost:10200/delayed-fcp.html',
       audits: {
         'first-contentful-paint': {
-          rawValue: '>1', // We just want to check that it doesn't error
+          numericValue: '>1', // We just want to check that it doesn't error
         },
       },
     },
diff --git a/lighthouse-core/test/audits/deprecations-test.js b/lighthouse-core/test/audits/deprecations-test.js
index 0aff362a9..2fbb0b8b5 100644
--- a/lighthouse-core/test/audits/deprecations-test.js
+++ b/lighthouse-core/test/audits/deprecations-test.js
@@ -13,7 +13,7 @@ const assert = require('assert');
 describe('Console deprecations audit', () => {
   it('passes when no console messages were found', () => {
     const auditResult = DeprecationsAudit.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
     });
     assert.equal(auditResult.score, 1);
     assert.equal(auditResult.details.items.length, 0);
@@ -21,7 +21,7 @@ describe('Console deprecations audit', () => {
 
   it('handles deprecations that do not have url or line numbers', () => {
     const auditResult = DeprecationsAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {
           entry: {
             source: 'deprecation',
@@ -41,7 +41,7 @@ describe('Console deprecations audit', () => {
     const URL = 'http://example.com';
 
     const auditResult = DeprecationsAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {
           entry: {
             source: 'deprecation',
diff --git a/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js b/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js
index e6681ab9c..b0e5c3fc3 100644
--- a/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js
+++ b/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js
@@ -15,7 +15,7 @@ describe('UX: geolocation audit', () => {
     const text = 'Do not request geolocation permission without a user action.';
 
     const auditResult = GeolocationOnStartAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {entry: {source: 'violation', url: 'https://example.com/', text}},
         {entry: {source: 'violation', url: 'https://example2.com/two', text}},
         {entry: {source: 'violation', url: 'http://abc.com/', text: 'No document.write'}},
@@ -28,7 +28,7 @@ describe('UX: geolocation audit', () => {
 
   it('passes when geolocation has not been automatically requested', () => {
     const auditResult = GeolocationOnStartAudit.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
     });
     assert.equal(auditResult.score, 1);
     assert.equal(auditResult.details.items.length, 0);
diff --git a/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js b/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js
index 6a3172b72..7c49f428c 100644
--- a/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js
+++ b/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js
@@ -15,7 +15,7 @@ const URL = 'https://example.com';
 describe('Page does not use document.write()', () => {
   it('passes when document.write() is not used', () => {
     const auditResult = DocWriteUseAudit.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
       URL: {finalUrl: URL},
     });
     assert.equal(auditResult.score, 1);
@@ -26,7 +26,7 @@ describe('Page does not use document.write()', () => {
     const text = 'Do not use document.write';
     const auditResult = DocWriteUseAudit.audit({
       URL: {finalUrl: URL},
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {entry: {source: 'violation', url: 'https://example.com/', text}},
         {entry: {source: 'violation', url: 'https://example2.com/two', text}},
         {entry: {source: 'violation', url: 'http://abc.com/', text: 'Long event handler!'}},
diff --git a/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js b/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js
index 8a50e5f33..94dfe8915 100644
--- a/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js
+++ b/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js
@@ -14,7 +14,7 @@ describe('UX: notification audit', () => {
   it('fails when notification has been automatically requested', () => {
     const text = 'Do not request notification permission without a user action.';
     const auditResult = NotificationOnStart.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {entry: {source: 'violation', url: 'https://example.com/', text}},
         {entry: {source: 'violation', url: 'https://example2.com/two', text}},
         {entry: {source: 'violation', url: 'http://abc.com/', text: 'No document.write'}},
@@ -27,7 +27,7 @@ describe('UX: notification audit', () => {
 
   it('passes when notification has not been automatically requested', () => {
     const auditResult = NotificationOnStart.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
     });
     assert.equal(auditResult.score, 1);
     assert.equal(auditResult.details.items.length, 0);
diff --git a/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js b/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js
index 505fb6021..8077cac54 100644
--- a/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js
+++ b/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js
@@ -15,7 +15,7 @@ describe('Page uses passive events listeners where applicable', () => {
     const text = 'Use passive event listeners when you do not use preventDefault';
 
     const auditResult = PassiveEventsAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {entry: {source: 'violation', url: 'https://example.com/', text}},
         {entry: {source: 'violation', url: 'https://example2.com/two', text}},
         {entry: {source: 'violation', url: 'https://example2.com/two', text}}, // duplicate
@@ -30,7 +30,7 @@ describe('Page uses passive events listeners where applicable', () => {
 
   it('passes scroll blocking listeners should be passive', () => {
     const auditResult = PassiveEventsAudit.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
     });
     assert.equal(auditResult.score, 1);
     assert.equal(auditResult.extendedInfo.value.length, 0);
diff --git a/lighthouse-core/test/audits/errors-in-console-test.js b/lighthouse-core/test/audits/errors-in-console-test.js
index 3238927e6..6382a9d46 100644
--- a/lighthouse-core/test/audits/errors-in-console-test.js
+++ b/lighthouse-core/test/audits/errors-in-console-test.js
@@ -13,7 +13,7 @@ const assert = require('assert');
 describe('Console error logs audit', () => {
   it('passes when no console messages were found', () => {
     const auditResult = ErrorLogsAudit.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
       RuntimeExceptions: [],
     });
     assert.equal(auditResult.rawValue, 0);
@@ -24,7 +24,7 @@ describe('Console error logs audit', () => {
 
   it('filter out the non error logs', () => {
     const auditResult = ErrorLogsAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {
           entry: {
             level: 'info',
@@ -42,7 +42,7 @@ describe('Console error logs audit', () => {
 
   it('fails when error logs are found ', () => {
     const auditResult = ErrorLogsAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {
           entry: {
             level: 'error',
@@ -98,7 +98,7 @@ describe('Console error logs audit', () => {
 
   it('handle the case when some logs fields are undefined', () => {
     const auditResult = ErrorLogsAudit.audit({
-      ChromeConsoleMessages: [
+      ConsoleMessages: [
         {
           entry: {
             level: 'error',
@@ -119,7 +119,7 @@ describe('Console error logs audit', () => {
   // Checks bug #4188
   it('handle the case when exception info is not present', () => {
     const auditResult = ErrorLogsAudit.audit({
-      ChromeConsoleMessages: [],
+      ConsoleMessages: [],
       RuntimeExceptions: [{
         'timestamp': 1506535813608.003,
         'exceptionDetails': {
diff --git a/lighthouse-core/test/computed/page-dependency-graph-test.js b/lighthouse-core/test/computed/page-dependency-graph-test.js
index 814378405..97712ed01 100644
--- a/lighthouse-core/test/computed/page-dependency-graph-test.js
+++ b/lighthouse-core/test/computed/page-dependency-graph-test.js
@@ -281,6 +281,31 @@ describe('PageDependencyGraph computed artifact:', () => {
       assert.equal(nodes[2].isMainDocument(), false);
     });
 
+    it('should link up script initiators', () => {
+      const request1 = createRequest(1, '1', 0);
+      const request2 = createRequest(2, '2', 5);
+      const request3 = createRequest(3, '3', 5);
+      const request4 = createRequest(4, '4', 20);
+      request4.initiator = {
+        type: 'script',
+        stack: {callFrames: [{url: '2'}], parent: {parent: {callFrames: [{url: '3'}]}}},
+      };
+      const networkRecords = [request1, request2, request3, request4];
+
+      addTaskEvents(0, 0, []);
+
+      const graph = PageDependencyGraph.createGraph(traceOfTab, networkRecords);
+      const nodes = [];
+      graph.traverse(node => nodes.push(node));
+
+      assert.equal(nodes.length, 4);
+      assert.deepEqual(nodes.map(node => node.id), [1, 2, 3, 4]);
+      assert.deepEqual(nodes[0].getDependencies(), []);
+      assert.deepEqual(nodes[1].getDependencies(), [nodes[0]]);
+      assert.deepEqual(nodes[2].getDependencies(), [nodes[0]]);
+      assert.deepEqual(nodes[3].getDependencies(), [nodes[1], nodes[2]]);
+    });
+
     it('should throw when root node is not related to main document', () => {
       const request1 = createRequest(1, '1', 0, null, NetworkRequest.TYPES.Other);
       const request2 = createRequest(2, '2', 5, null, NetworkRequest.TYPES.Document);
diff --git a/lighthouse-core/test/gather/fake-driver.js b/lighthouse-core/test/gather/fake-driver.js
index 73e0782e0..1db517772 100644
--- a/lighthouse-core/test/gather/fake-driver.js
+++ b/lighthouse-core/test/gather/fake-driver.js
@@ -43,6 +43,9 @@ function makeFakeDriver({protocolGetVersionResponse}) {
     enableRuntimeEvents() {
       return Promise.resolve();
     },
+    enableAsyncStacks() {
+      return Promise.resolve();
+    },
     evaluateScriptOnLoad() {
       return Promise.resolve();
     },
diff --git a/lighthouse-core/test/gather/gather-runner-test.js b/lighthouse-core/test/gather/gather-runner-test.js
index 22c5762e4..36ab4f962 100644
--- a/lighthouse-core/test/gather/gather-runner-test.js
+++ b/lighthouse-core/test/gather/gather-runner-test.js
@@ -45,6 +45,9 @@ function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn,
     enableRuntimeEvents() {
       return Promise.resolve();
     }
+    enableAsyncStacks() {
+      return Promise.resolve();
+    }
     assertNoSameOriginServiceWorkerClients() {
       return Promise.resolve();
     }
@@ -333,6 +336,7 @@ describe('GatherRunner', function() {
       setThrottling: asyncFunc,
       dismissJavaScriptDialogs: asyncFunc,
       enableRuntimeEvents: asyncFunc,
+      enableAsyncStacks: asyncFunc,
       cacheNatives: asyncFunc,
       gotoURL: asyncFunc,
       registerPerformanceObserver: asyncFunc,
@@ -392,6 +396,7 @@ describe('GatherRunner', function() {
       setThrottling: asyncFunc,
       dismissJavaScriptDialogs: asyncFunc,
       enableRuntimeEvents: asyncFunc,
+      enableAsyncStacks: asyncFunc,
       cacheNatives: asyncFunc,
       gotoURL: asyncFunc,
       registerPerformanceObserver: asyncFunc,
diff --git a/lighthouse-core/test/lib/manifest-parser-test.js b/lighthouse-core/test/lib/manifest-parser-test.js
index 20b56ad56..5e8bd6b85 100644
--- a/lighthouse-core/test/lib/manifest-parser-test.js
+++ b/lighthouse-core/test/lib/manifest-parser-test.js
@@ -347,7 +347,6 @@ describe('Manifest Parser', function() {
       const display = parsedManifest.value.display;
       assert.ok(!display.warning);
       assert.equal(display.value, 'browser');
-      assert.equal(display.rawValue, undefined);
     });
 
     it('trims whitespace', () => {
diff --git a/lighthouse-core/test/lib/proto-preprocessor-test.js b/lighthouse-core/test/lib/proto-preprocessor-test.js
index 73b452054..d92093308 100644
--- a/lighthouse-core/test/lib/proto-preprocessor-test.js
+++ b/lighthouse-core/test/lib/proto-preprocessor-test.js
@@ -78,7 +78,7 @@ describe('processing for proto', () => {
       'audits': {
         'critical-request-chains': {
           'scoreDisplayMode': 'not-applicable',
-          'rawValue': 14.3,
+          'numericValue': 14.3,
           'displayValue': ['hello %d', 123],
         },
       },
diff --git a/lighthouse-core/test/report/html/renderer/performance-category-renderer-test.js b/lighthouse-core/test/report/html/renderer/performance-category-renderer-test.js
index b3c2ea12e..2d03ab6d8 100644
--- a/lighthouse-core/test/report/html/renderer/performance-category-renderer-test.js
+++ b/lighthouse-core/test/report/html/renderer/performance-category-renderer-test.js
@@ -122,7 +122,7 @@ describe('PerfCategoryRenderer', () => {
       group: 'load-opportunities',
       result: {
         score: 0, scoreDisplayMode: 'numeric',
-        rawValue: 100, explanation: 'Yikes!!', title: 'Bug #2', description: '',
+        numericValue: 100, explanation: 'Yikes!!', title: 'Bug #2', description: '',
       },
     };
 
@@ -166,7 +166,7 @@ describe('PerfCategoryRenderer', () => {
         group: 'load-opportunities',
         result: {
           error: true, score: 0,
-          rawValue: 100, explanation: 'Yikes!!', title: 'Bug #2',
+          numericValue: 100, explanation: 'Yikes!!', title: 'Bug #2',
         },
       };
       const wastedMs = renderer._getWastedMs(auditWithDebug);
diff --git a/lighthouse-core/test/results/artifacts/artifacts.json b/lighthouse-core/test/results/artifacts/artifacts.json
index d91391fc8..0aef7b229 100644
--- a/lighthouse-core/test/results/artifacts/artifacts.json
+++ b/lighthouse-core/test/results/artifacts/artifacts.json
@@ -406,7 +406,7 @@
       }
     }
   ],
-  "ChromeConsoleMessages": [
+  "ConsoleMessages": [
     {
       "entry": {
         "source": "other",
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index c7ed7e658..a7548037f 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -77,7 +77,7 @@
       "description": "First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint).",
       "score": 0.51,
       "scoreDisplayMode": "numeric",
-      "rawValue": 3969.135,
+      "numericValue": 3969.135,
       "displayValue": "4.0 s"
     },
     "first-meaningful-paint": {
@@ -86,7 +86,7 @@
       "description": "First Meaningful Paint measures when the primary content of a page is visible. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint).",
       "score": 0.51,
       "scoreDisplayMode": "numeric",
-      "rawValue": 3969.136,
+      "numericValue": 3969.136,
       "displayValue": "4.0 s"
     },
     "load-fast-enough-for-pwa": {
@@ -95,7 +95,7 @@
       "description": "A fast page load over a cellular network ensures a good mobile user experience. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/fast-3g).",
       "score": 1,
       "scoreDisplayMode": "binary",
-      "rawValue": 4927.278
+      "numericValue": 4927.278
     },
     "speed-index": {
       "id": "speed-index",
@@ -103,7 +103,7 @@
       "description": "Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/speed-index).",
       "score": 0.74,
       "scoreDisplayMode": "numeric",
-      "rawValue": 4417,
+      "numericValue": 4417,
       "displayValue": "4.4 s"
     },
     "screenshot-thumbnails": {
@@ -188,7 +188,7 @@
       "description": "Estimated Input Latency is an estimate of how long your app takes to respond to user input, in milliseconds, during the busiest 5s window of page load. If your latency is higher than 50 ms, users may perceive your app as laggy. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/estimated-input-latency).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 16,
+      "numericValue": 16,
       "displayValue": "20 ms"
     },
     "max-potential-fid": {
@@ -197,7 +197,7 @@
       "description": "The potential First Input Delay that your users could experience is the duration, in milliseconds, of the longest task.",
       "score": 0.92,
       "scoreDisplayMode": "numeric",
-      "rawValue": 122.537,
+      "numericValue": 122.537,
       "displayValue": "120 ms"
     },
     "errors-in-console": {
@@ -206,7 +206,7 @@
       "description": "Errors logged to the console indicate unresolved problems. They can come from network request failures and other browser concerns.",
       "score": 0,
       "scoreDisplayMode": "binary",
-      "rawValue": 5,
+      "numericValue": 5,
       "details": {
         "type": "table",
         "headings": [
@@ -256,7 +256,7 @@
       "description": "Time To First Byte identifies the time at which your server sends a response. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/ttfb).",
       "score": 1,
       "scoreDisplayMode": "binary",
-      "rawValue": 570.5630000000001,
+      "numericValue": 570.5630000000001,
       "displayValue": "Root document took 570 ms",
       "details": {
         "type": "opportunity",
@@ -271,7 +271,7 @@
       "description": "First CPU Idle marks the first time at which the page's main thread is quiet enough to handle input. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/first-interactive).",
       "score": 0.72,
       "scoreDisplayMode": "numeric",
-      "rawValue": 4927.278,
+      "numericValue": 4927.278,
       "displayValue": "4.9 s"
     },
     "interactive": {
@@ -280,7 +280,7 @@
       "description": "Time to interactive is the amount of time it takes for the page to become fully interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/consistently-interactive).",
       "score": 0.78,
       "scoreDisplayMode": "numeric",
-      "rawValue": 4927.278,
+      "numericValue": 4927.278,
       "displayValue": "4.9 s"
     },
     "user-timings": {
@@ -447,7 +447,7 @@
       "description": "Redirects introduce additional delays before the page can be loaded. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/redirects).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "details": {
         "type": "opportunity",
@@ -620,7 +620,7 @@
       "description": "Consider reducing the time spent parsing, compiling and executing JS. You may find delivering smaller JS payloads helps with this.",
       "score": 0.96,
       "scoreDisplayMode": "numeric",
-      "rawValue": 1548.5690000000002,
+      "numericValue": 1548.5690000000002,
       "displayValue": "1.5 s",
       "details": {
         "type": "table",
@@ -682,7 +682,7 @@
       "description": "Consider reducing the time spent parsing, compiling, and executing JS. You may find delivering smaller JS payloads helps with this. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/bootup).",
       "score": 0.92,
       "scoreDisplayMode": "numeric",
-      "rawValue": 1150.573,
+      "numericValue": 1150.573,
       "displayValue": "1.2 s",
       "details": {
         "type": "table",
@@ -748,7 +748,7 @@
       "description": "Consider using <link rel=preload> to prioritize fetching resources that are currently requested later in page load. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/preload).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "details": {
         "type": "opportunity",
@@ -763,7 +763,7 @@
       "description": "Consider adding preconnect or dns-prefetch resource hints to establish early connections to important third-party origins. [Learn more](https://developers.google.com/web/fundamentals/performance/resource-prioritization#preconnect).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "warnings": [],
       "details": {
@@ -791,7 +791,7 @@
       "description": "Collection of useful page vitals.",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 1,
+      "numericValue": 1,
       "details": {
         "type": "debugdata",
         "items": [
@@ -823,7 +823,7 @@
       "description": "Lists the network requests that were made during page load.",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 18,
+      "numericValue": 18,
       "details": {
         "type": "table",
         "headings": [
@@ -1064,7 +1064,7 @@
       "description": "Network round trip times (RTT) have a large impact on performance. If the RTT to an origin is high, it's an indication that servers closer to the user could improve performance. [Learn more](https://hpbn.co/primer-on-latency-and-bandwidth/).",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 1.7249999999999943,
+      "numericValue": 1.7249999999999943,
       "displayValue": "0 ms",
       "details": {
         "type": "table",
@@ -1099,7 +1099,7 @@
       "description": "Server latencies can impact web performance. If the server latency of an origin is high, it's an indication the server is overloaded or has poor backend performance. [Learn more](https://hpbn.co/primer-on-web-performance/#analyzing-the-resource-waterfall).",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 572.829,
+      "numericValue": 572.829,
       "displayValue": "570 ms",
       "details": {
         "type": "table",
@@ -1134,7 +1134,7 @@
       "description": "Lists the toplevel main thread tasks that executed during page load.",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 16,
+      "numericValue": 16,
       "details": {
         "type": "table",
         "headings": [
@@ -1225,7 +1225,7 @@
       "description": "Collects all available metrics.",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 4927.278,
+      "numericValue": 4927.278,
       "details": {
         "type": "debugdata",
         "items": [
@@ -1910,7 +1910,7 @@
       "description": "A long cache lifetime can speed up repeat visits to your page. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/cache-policy).",
       "score": 0.58,
       "scoreDisplayMode": "numeric",
-      "rawValue": 103455,
+      "numericValue": 103455,
       "displayValue": "11 resources found",
       "details": {
         "type": "table",
@@ -2024,7 +2024,7 @@
       "description": "Large network payloads cost users real money and are highly correlated with long load times. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/network-payloads).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 160738,
+      "numericValue": 160738,
       "displayValue": "Total size was 157 KB",
       "details": {
         "type": "table",
@@ -2090,7 +2090,7 @@
       "description": "Consider lazy-loading offscreen and hidden images after all critical resources have finished loading to lower time to interactive. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/offscreen-images).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "warnings": [],
       "details": {
@@ -2107,7 +2107,7 @@
       "description": "Resources are blocking the first paint of your page. Consider delivering critical JS/CSS inline and deferring all non-critical JS/styles. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/blocking-resources).",
       "score": 0.46,
       "scoreDisplayMode": "numeric",
-      "rawValue": 1129,
+      "numericValue": 1129,
       "displayValue": "Potential savings of 1,130 ms",
       "details": {
         "type": "opportunity",
@@ -2164,7 +2164,7 @@
       "description": "Minifying CSS files can reduce network payload sizes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/minify-css).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "details": {
         "type": "opportunity",
@@ -2180,7 +2180,7 @@
       "description": "Minifying JavaScript files can reduce payload sizes and script parse time. [Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).",
       "score": 0.88,
       "scoreDisplayMode": "numeric",
-      "rawValue": 150,
+      "numericValue": 150,
       "displayValue": "Potential savings of 30 KB",
       "warnings": [],
       "details": {
@@ -2220,7 +2220,7 @@
       "description": "Remove dead rules from stylesheets and defer the loading of CSS not used for above-the-fold content to reduce unnecessary bytes consumed by network activity. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/unused-css).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "details": {
         "type": "opportunity",
@@ -2236,7 +2236,7 @@
       "description": "Image formats like JPEG 2000, JPEG XR, and WebP often provide better compression than PNG or JPEG, which means faster downloads and less data consumption. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/webp).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "Potential savings of 9 KB",
       "warnings": [],
       "details": {
@@ -2282,7 +2282,7 @@
       "description": "Optimized images load faster and consume less cellular data. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/optimize-images).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "warnings": [],
       "details": {
@@ -2299,7 +2299,7 @@
       "description": "Text-based resources should be served with compression (gzip, deflate or brotli) to minimize total network bytes. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/text-compression).",
       "score": 0.75,
       "scoreDisplayMode": "numeric",
-      "rawValue": 300,
+      "numericValue": 300,
       "displayValue": "Potential savings of 63 KB",
       "details": {
         "type": "opportunity",
@@ -2342,7 +2342,7 @@
       "description": "Serve images that are appropriately-sized to save cellular data and improve load time. [Learn more](https://developers.google.com/web/tools/lighthouse/audits/oversized-images).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "warnings": [],
       "details": {
@@ -2359,7 +2359,7 @@
       "description": "Large GIFs are inefficient for delivering animated content. Consider using MPEG4/WebM videos for animations and PNG/WebP for static images instead of GIF to save network bytes. [Learn more](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/replace-animated-gifs-with-video/)",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 0,
+      "numericValue": 0,
       "displayValue": "",
       "details": {
         "type": "opportunity",
@@ -2390,7 +2390,7 @@
       "description": "Browser engineers recommend pages contain fewer than ~1,500 DOM elements. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer [style calculations](https://developers.google.com/web/fundamentals/performance/rendering/reduce-the-scope-and-complexity-of-style-calculations), and produce costly [layout reflows](https://developers.google.com/speed/articles/reflow). [Learn more](https://developers.google.com/web/tools/lighthouse/audits/dom-size).",
       "score": 1,
       "scoreDisplayMode": "numeric",
-      "rawValue": 31,
+      "numericValue": 31,
       "displayValue": "31 elements",
       "details": {
         "type": "table",
@@ -3491,6 +3491,11 @@
           "weight": 0,
           "group": "seo-crawl"
         },
+        {
+          "id": "image-alt",
+          "weight": 1,
+          "group": "seo-content"
+        },
         {
           "id": "hreflang",
           "weight": 1,
@@ -3522,7 +3527,7 @@
         }
       ],
       "id": "seo",
-      "score": 0.9
+      "score": 0.82
     },
     "pwa": {
       "title": "Progressive Web App",
@@ -5438,4 +5443,4 @@
     }
   },
   "stackPacks": []
-}
+}
\ No newline at end of file
diff --git a/lighthouse-core/test/runner-test.js b/lighthouse-core/test/runner-test.js
index ee3a55b45..720c85dd7 100644
--- a/lighthouse-core/test/runner-test.js
+++ b/lighthouse-core/test/runner-test.js
@@ -561,7 +561,8 @@ describe('Runner', () => {
           static audit(artifacts, context) {
             context.LighthouseRunWarnings.push(warningString);
             return {
-              rawValue: 5,
+              numericValue: 5,
+              score: 1,
             };
           }
         },
diff --git a/lighthouse-core/test/scoring-test.js b/lighthouse-core/test/scoring-test.js
index 723efdf6b..35ed8b020 100644
--- a/lighthouse-core/test/scoring-test.js
+++ b/lighthouse-core/test/scoring-test.js
@@ -35,7 +35,7 @@ describe('ReportScoring', () => {
   describe('#scoreAllCategories', () => {
     it('should score the categories', () => {
       const resultsByAuditId = {
-        'my-audit': {rawValue: 'you passed', score: 0},
+        'my-audit': {score: 0},
         'my-boolean-audit': {score: 1, extendedInfo: {}},
         'my-scored-audit': {score: 1},
         'my-failed-audit': {score: 0.2},