@@ -19,11 +19,17 @@ import { pathToFileURL } from "node:url";
1919const MIN_CORRELATION = 0.7 ;
2020const MAX_SPREAD_RATIO = 0 ;
2121
22+ const raisedAgainst = ( ceiling , base ) => Number . isFinite ( base ) && ceiling > base ;
23+
24+ function measuredStatus ( ceiling , value ) {
25+ if ( ! Number . isFinite ( value ) ) return "missing" ;
26+ if ( value === ceiling ) return "at" ;
27+ return value > ceiling ? "rose" : "below" ;
28+ }
29+
2230function ceilingRow ( counter , ceiling , value , base ) {
23- if ( Number . isFinite ( base ) && ceiling > base ) return { counter, ceiling, base, status : "raised" } ;
24- if ( ! Number . isFinite ( value ) ) return { counter, ceiling, value : null , status : "missing" } ;
25- if ( value === ceiling ) return { counter, ceiling, value, status : "at" } ;
26- return { counter, ceiling, value, status : value > ceiling ? "rose" : "below" } ;
31+ if ( raisedAgainst ( ceiling , base ) ) return { counter, ceiling, base, status : "raised" } ;
32+ return { counter, ceiling, value, status : measuredStatus ( ceiling , value ) } ;
2733}
2834
2935/** Passes only when every gated counter sits exactly at a ceiling no higher than the base's. */
@@ -121,9 +127,12 @@ function pearson(xs, ys) {
121127const round = ( value ) => Math . round ( value * 100 ) / 100 ;
122128const readJson = ( path ) => JSON . parse ( readFileSync ( path , "utf8" ) ) ;
123129
130+ const versionOf = ( evidence ) => String ( evidence . browser ?? evidence . environment ?. browser ) ;
131+
124132/** Chrome's major version from a journey's evidence, e.g. "153" from "HeadlessChrome/153.0.1.2". */
125133export function browserMajor ( evidence ) {
126- return / \/ ( \d + ) \. / . exec ( evidence . browser ?? evidence . environment ?. browser ?? "" ) ?. [ 1 ] ?? null ;
134+ const match = / \/ ( \d + ) \. / . exec ( versionOf ( evidence ) ) ;
135+ return match ? match [ 1 ] : null ;
127136}
128137
129138/** The whole ceilings file, the journey named in it, and that journey's evidence. */
@@ -141,15 +150,19 @@ const isObject = (value) => typeof value === "object" && value !== null;
141150 * base file in a shape this script does not write throws: an unreadable base must not pass.
142151 */
143152export function readBase ( base , all , journey ) {
144- for ( const [ name , entry ] of Object . entries ( base ) ) {
145- if ( ! isObject ( entry ?. counts ) ) throw new Error ( `base ceilings: "${ name } " has no counts object` ) ;
146- }
153+ assertBaseShape ( base ) ;
147154 return {
148155 counts : base [ journey ] ?. counts ,
149156 removedJourneys : Object . keys ( base ) . filter ( ( name ) => ! Object . hasOwn ( all , name ) ) ,
150157 } ;
151158}
152159
160+ function assertBaseShape ( base ) {
161+ for ( const [ name , entry ] of Object . entries ( base ) ) {
162+ if ( ! isObject ( entry ?. counts ) ) throw new Error ( `base ceilings: "${ name } " has no counts object` ) ;
163+ }
164+ }
165+
153166/** Absent while the base branch has no ceilings file yet (and on runs without a base). */
154167function loadBase ( path , all , journey ) {
155168 if ( ! path || ! existsSync ( path ) ) return { counts : undefined , removedJourneys : [ ] } ;
@@ -171,18 +184,22 @@ function printNotes(recorded, evidence, rows) {
171184 }
172185}
173186
174- function runCheck ( args ) {
175- const { all, journey, evidence, counts } = journeyInputs ( args ) ;
176- const base = loadBase ( args [ 3 ] , all , journey ) ;
177- const { passed, rows } = checkCeilings ( all [ journey ] . counts , counts , base . counts ) ;
178- const ok = passed && base . removedJourneys . length === 0 ;
187+ function printResult ( journey , ok , rows , removedJourneys ) {
179188 console . log ( `[perf-ratchet] ${ journey } : ${ ok ? "PASS" : "FAIL" } ` ) ;
180189 for ( const row of rows ) console . log ( `[perf-ratchet] ${ formatRow ( row ) } ` ) ;
181- for ( const name of base . removedJourneys ) {
190+ for ( const name of removedJourneys ) {
182191 console . log (
183192 `[perf-ratchet] FAIL journey ${ name } removed against the base branch; ceilings only go down` ,
184193 ) ;
185194 }
195+ }
196+
197+ function runCheck ( args ) {
198+ const { all, journey, evidence, counts } = journeyInputs ( args ) ;
199+ const base = loadBase ( args [ 3 ] , all , journey ) ;
200+ const { passed, rows } = checkCeilings ( all [ journey ] . counts , counts , base . counts ) ;
201+ const ok = passed && base . removedJourneys . length === 0 ;
202+ printResult ( journey , ok , rows , base . removedJourneys ) ;
186203 printNotes ( all [ journey ] , evidence , rows ) ;
187204 return ok ? 0 : 1 ;
188205}
0 commit comments