From f3fa12806b92c2502aebbc2d9996770130c7f036 Mon Sep 17 00:00:00 2001 From: Tudor Date: Fri, 17 Jul 2026 17:41:12 +0100 Subject: [PATCH 1/2] =?UTF-8?q?fix(compare):=20expert=20should-fixes=20S1-?= =?UTF-8?q?S4,=20S6=20=E2=80=94=20banded=20chips,=20P8=20reason,=20KS4=20g?= =?UTF-8?q?ap=20caption,=20all-through=20framing,=20cohort=20sizes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit S1: first-choice chip banded (More than half / About 1 in 3 / Over 1 in 4 missed out) so a 44%-offered grammar isn't understated by half. S2: Progress 8 explains its absence for 2024/25+ cohorts (no KS2 baseline, COVID) instead of a bare 'No data'. S3: KS4 trend charts get their own honest gap caption (2019/20-2020/21 unpublished; later years not in our dataset yet); y-axis 'Value'→'Score'; buildCompareChart exposes englandOnlyYears. S4: all-through schools labelled in chips, rail caption says 'N schools · view' for mixed baskets, whole-school roll no longer judged against the single-phase median, community section carries an all-ages caveat. S6 (spec §8.5): disadvantaged attainment shows the cohort behind it ('of ~50 disadvantaged pupils'). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB --- .../__tests__/lib/compareChartData.test.ts | 9 ++++++ nextjs-app/__tests__/lib/compareLogic.test.ts | 10 +++++++ nextjs-app/components/ComparisonChart.tsx | 24 +++++++++++---- nextjs-app/components/ComparisonView.tsx | 20 ++++++++++--- .../components/compare/CompareAcademics.tsx | 29 +++++++++++++++++++ .../components/compare/CompareAtAGlance.tsx | 8 ++++- .../components/compare/CompareCommunity.tsx | 17 ++++++++++- .../components/compare/TrendsExplorer.tsx | 1 + nextjs-app/lib/compareChartData.ts | 17 +++++++---- nextjs-app/lib/compareLogic.ts | 6 ++++ 10 files changed, 124 insertions(+), 17 deletions(-) diff --git a/nextjs-app/__tests__/lib/compareChartData.test.ts b/nextjs-app/__tests__/lib/compareChartData.test.ts index 09325ae..7c59bc5 100644 --- a/nextjs-app/__tests__/lib/compareChartData.test.ts +++ b/nextjs-app/__tests__/lib/compareChartData.test.ts @@ -73,6 +73,15 @@ describe('buildCompareChart', () => { expect(eng.data[chart.years.indexOf(202122)]).toBe(58.7); }); + it('lists England-only years so the component can caption dashed-only stretches', () => { + const chart = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct', { + 202122: 58.7, + }); + expect(chart.englandOnlyYears).toEqual([202122]); + const none = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct'); + expect(none.englandOnlyYears).toEqual([]); + }); + it('flags the unpublished 2021/22 school-level year when England has data but schools do not', () => { const withNational = buildCompareChart(THREE_SCHOOLS, SCHOOL_LIST, 'rwm_expected_pct', { 202122: 58.7, diff --git a/nextjs-app/__tests__/lib/compareLogic.test.ts b/nextjs-app/__tests__/lib/compareLogic.test.ts index faa257d..131e26a 100644 --- a/nextjs-app/__tests__/lib/compareLogic.test.ts +++ b/nextjs-app/__tests__/lib/compareLogic.test.ts @@ -177,6 +177,16 @@ describe('summariseAdmissions', () => { expect(s.chip).toEqual({ tone: 'warn', text: 'Over 1 in 4 first choices missed out' }); }); + it('60% → "About 1 in 3 first choices missed out"', () => { + const s = summariseAdmissions(admissions({ first_preference_offer_pct: 60 })); + expect(s.chip).toEqual({ tone: 'warn', text: 'About 1 in 3 first choices missed out' }); + }); + + it('44% (selective-scale demand) → "More than half of first choices missed out"', () => { + const s = summariseAdmissions(admissions({ first_preference_offer_pct: 43.69 })); + expect(s.chip).toEqual({ tone: 'warn', text: 'More than half of first choices missed out' }); + }); + it('100% → "All first choices offered"', () => { const s = summariseAdmissions(admissions({ first_preference_offer_pct: 100 })); expect(s.chip).toEqual({ tone: 'good', text: 'All first choices offered' }); diff --git a/nextjs-app/components/ComparisonChart.tsx b/nextjs-app/components/ComparisonChart.tsx index 851b03d..23a96f5 100644 --- a/nextjs-app/components/ComparisonChart.tsx +++ b/nextjs-app/components/ComparisonChart.tsx @@ -38,13 +38,15 @@ interface ComparisonChartProps { /** Official England figure per academic year for this metric — renders a * dashed grey reference line when provided. */ nationalByYear?: Record; + /** KS4 metrics get a different (honest) gap caption than KS2. */ + isSecondary?: boolean; } // One shape per basket slot (MAX_SCHOOLS = 5) — secondary encoding so // converging lines stay tellable apart without relying on hue alone. const POINT_STYLES: PointStyle[] = ['circle', 'triangle', 'rect', 'rectRot', 'star']; -export function ComparisonChart({ comparisonData, schools, metric, metricLabel, nationalByYear }: ComparisonChartProps) { +export function ComparisonChart({ comparisonData, schools, metric, metricLabel, nationalByYear, isSecondary = false }: ComparisonChartProps) { const isMobile = useIsMobile(); const [focusedUrn, setFocusedUrn] = useState(null); @@ -168,7 +170,7 @@ export function ComparisonChart({ comparisonData, schools, metric, metricLabel, display: true, title: { display: !isMobile, - text: kind === 'percentage' ? 'Percentage (%)' : kind === 'progress' ? 'Progress Score' : 'Value', + text: kind === 'percentage' ? 'Percentage (%)' : kind === 'progress' ? 'Progress Score' : 'Score', font: { size: 12, weight: 'bold', @@ -240,11 +242,23 @@ export function ComparisonChart({ comparisonData, schools, metric, metricLabel,
- {built.showUnpublished202122Note && ( + {isSecondary && built.englandOnlyYears.length > 0 ? ( + // KS4's honest story differs from KS2's: 2019/20–2020/21 school-level + // GCSE results weren't published (COVID grading); later years WERE + // published by DfE but aren't in our dataset yet.

- No national tests were held in 2019/20 and 2020/21 (COVID), and DfE didn't publish - school-level figures for 2021/22 — the England average is shown for that year. + School-level GCSE figures for 2019/20 and 2020/21 weren't published (COVID + grading), and more recent years aren't in our dataset yet where lines break — the + England average is shown where available.

+ ) : ( + !isSecondary && + built.showUnpublished202122Note && ( +

+ No national tests were held in 2019/20 and 2020/21 (COVID), and DfE didn't publish + school-level figures for 2021/22 — the England average is shown for that year. +

+ ) )} ); diff --git a/nextjs-app/components/ComparisonView.tsx b/nextjs-app/components/ComparisonView.tsx index 12ab3f1..d22e59e 100644 --- a/nextjs-app/components/ComparisonView.tsx +++ b/nextjs-app/components/ComparisonView.tsx @@ -365,12 +365,18 @@ export function ComparisonView({ style={{ '--school-count': activeSchools.length } as CSSProperties} aria-label="Schools in this comparison" > - {/* Fills the 200px label rail on desktop (hidden on mobile). */} + {/* Fills the 200px label rail on desktop (hidden on mobile). + All-through schools must not be miscounted as "primary + schools"/"secondary schools" — mixed baskets get "· primary + view" phrasing instead. */}
Comparing - {activeSchools.length} {comparePhase} school - {activeSchools.length === 1 ? '' : 's'} + {activeSchools.every((sch) => + sch.phase?.toLowerCase().includes(comparePhase), + ) + ? `${activeSchools.length} ${comparePhase} school${activeSchools.length === 1 ? '' : 's'}` + : `${activeSchools.length} schools · ${comparePhase} view`}
{activeSchools.map((school, index) => ( @@ -390,7 +396,13 @@ export function ComparisonView({ {shortName(school.school_name)} - {[school.local_authority, school.school_type].filter(Boolean).join(' · ')} + {[ + /all.?through/i.test(school.phase ?? '') ? 'All-through' : null, + school.local_authority, + school.school_type, + ] + .filter(Boolean) + .join(' · ')}