-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core(lhr): strictly numeric scores, add scoreDisplayMode #4690
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quick, let's merge before there are conflicts 😆
docs/understanding-results.md
Outdated
@@ -57,7 +57,7 @@ An object containing the results of the audits, keyed by their name. | |||
| rawValue | <code>boolean|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. | | |||
| 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>boolean|number</code> | The scored value determined by the audit as either boolean or a number `0-100`. If the audit is a boolean, the implication is `score ? 100 : 0`. | | |||
| scoringMode | <code>"binary"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail or are there shades of gray 0-100. *NOTE: This does not necessarily mean `typeof audit.score === audit.scoringMode`, an audit can have a score of 40 with a scoringMode of `"binary"` meant to indicate display should be failure.* | | |||
| scoreDisplayMode | <code>"binary"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail or are there shades of gray 0-100. *NOTE: This does not necessarily mean `typeof audit.score === audit.scoreDisplayMode`, an audit can have a score of 40 with a scoreDisplayMode of `"binary"` meant to indicate display should be failure.* | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
score should always be a number now, so entire caveat is unnecessary :)
lighthouse-core/audits/audit.js
Outdated
score = Math.max(0, score); | ||
return Math.round(score); | ||
return Math.round(score * 100) / 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lighthouse-core/scoring.js
Outdated
|
||
result.score = auditScore; | ||
if (!Number.isFinite(result.score)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to check in both places?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'd be fine with also doing this in generateAuditResult, however IMO there's not a big diff.
- Many of our tests assert the result returned by
audit()
Audit.generateAuditResult
is called via Runner once each audit is done- Basically right after that, we call this
scoreAllCategories
method.
So ideally we'd have something in Audit class that wraps each audit's audit()
method, but we don't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lol I just made your point for you. 😊
lighthouse-core/scoring.js
Outdated
* @param {number} val | ||
* @return {number} | ||
*/ | ||
const clamp2decimals = val => Math.round(val * 100) / 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the biggest fan of this name, clampTo2Decimals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
lighthouse-core/audits/audit.js
Outdated
throw new Error(`Audit score for ${audit.meta.name} is > 1`); | ||
} | ||
|
||
const scoreDisplayMode = result.scoreDisplayMode || audit.meta.scoreDisplayMode || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove result.scoreDisplayMode
and update the byteefficiency audit metas.
5d94217
to
e24e3c7
Compare
1584258
to
bb099d3
Compare
89c48f7
to
fddb987
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
couple nits, but we are so close! :D
docs/understanding-results.md
Outdated
@@ -56,8 +55,8 @@ An object containing the results of the audits, keyed by their name. | |||
| error | `boolean` | Set to true if there was an an exception thrown within the audit. The error message will be in `debugString`. | |||
| rawValue | <code>boolean|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. | | |||
| 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>boolean|number</code> | The scored value determined by the audit as either boolean or a number `0-100`. If the audit is a boolean, the implication is `score ? 100 : 0`. | | |||
| scoringMode | <code>"binary"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail or are there shades of gray 0-100. *NOTE: This does not necessarily mean `typeof audit.score === audit.scoringMode`, an audit can have a score of 40 with a scoringMode of `"binary"` meant to indicate display should be failure.* | | |||
| score | <code>boolean|number</code> | The scored value determined by the audit as a number `0-1`, representing displayed scores of 0-100. | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no longer boolean|number
just number
🎉 :D
docs/understanding-results.md
Outdated
| score | <code>boolean|number</code> | The scored value determined by the audit as either boolean or a number `0-100`. If the audit is a boolean, the implication is `score ? 100 : 0`. | | ||
| scoringMode | <code>"binary"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail or are there shades of gray 0-100. *NOTE: This does not necessarily mean `typeof audit.score === audit.scoringMode`, an audit can have a score of 40 with a scoringMode of `"binary"` meant to indicate display should be failure.* | | ||
| score | <code>boolean|number</code> | The scored value determined by the audit as a number `0-1`, representing displayed scores of 0-100. | | ||
| scoreDisplayMode | <code>"binary"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail (score of 1 or 0), or are there shades of gray (scores between 0-1 exclusive). | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why exclusive? we can still assign scores of 1 to numeric audits :)
it('throws if an audit returns a score that\'s not a number', () => { | ||
const re = /Invalid score/; | ||
assert.throws(_ => Audit._normalizeAuditScore(B, {rawValue: true, score: NaN}), re); | ||
assert.throws(_ => Audit._normalizeAuditScore(B, {rawValue: true, score: '50'}), /is > 1/); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wait why isn't this /Invalid score/?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this pair of assertions:
https://github.com/GoogleChrome/lighthouse/blob/scoring2.0/lighthouse-core/audits/audit.js#L127-L128
we assert its finite first, throw invalid score. otherwise we doublecheck we're finite but <= 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah exactly. :D clamp casts.
i fixed the tests.
so right now one could pass in a score of '0.7'
and it'd get casted and be just fine. we could hypothetically throw but yeah i don't think its a big deal.
i fixed the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💥 🎉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review!
docs/architecture.md
Outdated
@@ -9,9 +9,9 @@ _Some incomplete notes_ | |||
* **Driver** - Interfaces with [Chrome Debugging Protocol](https://developer.chrome.com/devtools/docs/debugger-protocol) ([API viewer](https://chromedevtools.github.io/debugger-protocol-viewer/)) | |||
* **Gatherers** - Uses Driver to collect information about the page. Minimal post-processing. | |||
* **Artifacts** - output of a gatherer | |||
* **Audit** - Tests for a single feature/optimization/metric. Using the Artifacts as input, an audit evaluates a test and resolves to a score which may be pass/fail/numeric. Formatting note: The meta description may contain markdown links and meta title may contain markdown code. | |||
* **Audit** - Tests for a single feature/optimization/metric. Using the Artifacts as input, an audit evaluates a test and resolves to a numeric score, described by scoreDisplayMode to be pass/fail or numeric. Formatting note: The meta description may contain markdown links and meta title may contain markdown code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe move the scoreDisplayMode
comment to the "formatting note"? It's pretty tangential to the rest of the sentence.
docs/scoring.md
Outdated
@@ -36,30 +36,30 @@ The metric results are not weighted equally. Currently the weights are: | |||
* 1X - perceptual speed index | |||
* 1X - estimated input latency | |||
|
|||
These weights were determined based on heuristics, and the Lighthouse team is working on formalizing this approach through more field data. | |||
These weights were determined based on heuristics, and the Lighthouse team is working on formalizing this approach through more field data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these weights are heuristics...
docs/understanding-results.md
Outdated
| score | <code>boolean|number</code> | The scored value determined by the audit as either boolean or a number `0-100`. If the audit is a boolean, the implication is `score ? 100 : 0`. | | ||
| scoringMode | <code>"binary"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail or are there shades of gray 0-100. *NOTE: This does not necessarily mean `typeof audit.score === audit.scoringMode`, an audit can have a score of 40 with a scoringMode of `"binary"` meant to indicate display should be failure.* | | ||
| 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"|"numeric"</code> | A string identifying how granular the score is meant to be indicating, i.e. is the audit pass/fail (score of 1 or 0), or are there shades of gray (scores between 0-1 inclusive). | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe "A string identifying the score granularity, i.e. is the ...."
}, | ||
'link-blocking-first-paint': { | ||
score: 100, | ||
score: 1.00, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mixed 1.00
s and 1
s. I'd personally rather just embrace it and go with all 1
all the time, but should at least be consistent in a file and/or context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally feel the same about the trailing 0s on e.g. 0.80
, too. Why hold on to the digit if we're not going to be doing 0-100 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
very well! :)
fixed up all these. also standardized on a leading 0, so we don't have a mix of .25
and 0.25
lighthouse-core/audits/audit.js
Outdated
score = Math.max(0, score); | ||
return Math.round(score); | ||
return Math.round(score * 100) / 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clampTo2Decimals
?
lighthouse-core/audits/audit.js
Outdated
score, | ||
scoreDisplayMode, | ||
informative, | ||
rawValue, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should rawValue
be copying over the rawValue
from the audit result? Should it have a different name if not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looking at usage below, maybe these could have a name that indicates they're overrides
@@ -52,7 +52,7 @@ function AuditFullResult() {} | |||
AuditFullResult.prototype.score; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be only {number}
now?
@@ -207,9 +207,9 @@ if (typeof module !== 'undefined' && module.exports) { | |||
* manual: (boolean|undefined), | |||
* notApplicable: (boolean|undefined), | |||
* debugString: (string|undefined), | |||
* displayValue: string, | |||
* displayValue: (string|undefined), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what happened here?
lighthouse-core/scoring.js
Outdated
} | ||
|
||
const score = Number(itemScore) || 0; | ||
const score = Number(item.score) || 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no more need for Number
coercion?
lighthouse-core/audits/audit.js
Outdated
} | ||
|
||
if (!Number.isFinite(score)) throw new Error(`Invalid score: ${score}`); | ||
if (score > 1) throw new Error(`Audit score for ${audit.meta.name} is > 1`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
worth checking < 0 as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
score
(0-1), no boolean nonsense.scoreDisplayMode
forces how it's displayed (renamed fromscoringMode
)displayValue
fallback stuff that was introduced in Resolve audit result #487This is a chain of PRs. Landing order is... 1st:
newdetails
(#4616). 2nd:shallowCategories
(#4711). 3rd:scoring2.0
(#4690)ref #4614