From 113f8f05e3db9af160c4f3b6133d892ab435007c Mon Sep 17 00:00:00 2001 From: Lukce Date: Sat, 7 Nov 2026 20:14:34 -0500 Subject: [PATCH] fix(scoring): grade the score that is shown (extension 0.3.2) The engine rounded the overall score for display but graded the unrounded value, so a raw 59.7 showed as 60 with grade F, and 79.6 showed as 80 with grade C. Seen live in the extension on amazon.com and adidas.com (60, F) and microsoft.com, uber.com and ford.com (80, C). Round once and grade the rounded number. The E-E-A-T scorer already did this. Adds a regression test (59.7 -> 60, D). Bumps the extension to 0.3.2. --- .changeset/grade-matches-shown-score.md | 5 +++++ apps/chrome-extension/package.json | 2 +- packages/scoring/src/engine.test.ts | 10 ++++++++++ packages/scoring/src/engine.ts | 6 ++++-- 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 .changeset/grade-matches-shown-score.md diff --git a/.changeset/grade-matches-shown-score.md b/.changeset/grade-matches-shown-score.md new file mode 100644 index 0000000..6ac9893 --- /dev/null +++ b/.changeset/grade-matches-shown-score.md @@ -0,0 +1,5 @@ +--- +'@advance-labs/scoring': patch +--- + +Grade the rounded overall score, so the letter grade always matches the number shown. A raw 59.7 displayed as 60 but graded F (seen on amazon.com and adidas.com), and 79.6 displayed as 80 but graded C. diff --git a/apps/chrome-extension/package.json b/apps/chrome-extension/package.json index a128842..4c6666c 100644 --- a/apps/chrome-extension/package.json +++ b/apps/chrome-extension/package.json @@ -1,6 +1,6 @@ { "name": "@advance-labs/chrome-extension", - "version": "0.3.1", + "version": "0.3.2", "private": true, "type": "module", "description": "AEO/GEO Chrome MV3 extension — runs a client-side AI-readiness audit on the active tab and exports a PDF.", diff --git a/packages/scoring/src/engine.test.ts b/packages/scoring/src/engine.test.ts index 3d88a21..78c1bdd 100644 --- a/packages/scoring/src/engine.test.ts +++ b/packages/scoring/src/engine.test.ts @@ -67,6 +67,16 @@ describe('runRules', () => { expect(score.criticalCount).toBe(1); }); + it('grades the score it shows: 59.7 displays as 60 and grades D, not F', async () => { + // Seen live on amazon.com and adidas.com ("60, grade F") and microsoft.com ("80, grade C"). + const { score } = await runRules(goodContext(), [ + { ...passRule, weight: 597 }, + { ...failRule, weight: 403 }, + ]); + expect(score.overall).toBe(60); + expect(score.grade).toBe('D'); + }); + it('runs async rules and folds a thrown rule into a failed finding', async () => { const ctx = goodContext(); const { categories, score } = await runRules(ctx, [asyncRule, throwingRule]); diff --git a/packages/scoring/src/engine.ts b/packages/scoring/src/engine.ts index 743d2cb..e8a0187 100644 --- a/packages/scoring/src/engine.ts +++ b/packages/scoring/src/engine.ts @@ -162,10 +162,12 @@ export function aggregateScore(categories: ScoreCategory[]): Score { } } - const overall = weightTotal > 0 ? clampScore(weightedSum / weightTotal) : 100; + // Round once and grade the rounded number, so the grade always matches the score shown + // (unrounded 79.6 used to display "80" and grade C). + const overall = Math.round(weightTotal > 0 ? clampScore(weightedSum / weightTotal) : 100); return { - overall: Math.round(overall), + overall, grade: scoreToGrade(overall), categories, passedCount,