fix(school): the Ofsted section shows the grade still in force and the latest visit

The section is dated by the latest visit and headlines the grade still in force with the inspection that awarded or confirmed it, or 'No overall grade'. A later visit that isn't the grade's source gets its own line, with an ungraded outcome such as 'Standards maintained'. The primary and secondary no-grade branches merge, so the secondary page no longer drops the sixth-form and early-years judgements (audit M2), and 'Not rated' goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
TudorandClaude Opus 5.5 committed 2026-10-05 16:31:26 +01:00
1 parent a42c586cc8
commit 9ef48da4b1
5 files changed
+147 -69

No files matched your search

@@ -0,0 +1,84 @@
import { render, screen } from '@testing-library/react';
import { OfstedSection } from '@/components/school/OfstedSection';
import { ofstedLegacyAreas } from '@/lib/utils';
import type { OfstedInspection } from '@/lib/types';
const empty = {
framework: null, inspection_date: null, inspection_type: null, overall_effectiveness: null,
quality_of_education: null, behaviour_attitudes: null, personal_development: null,
leadership_management: null, early_years_provision: null, sixth_form_provision: null,
previous_overall: null, rc_safeguarding_met: null, rc_inclusion: null, rc_curriculum_teaching: null,
rc_achievement: null, rc_attendance_behaviour: null, rc_personal_development: null,
rc_leadership_governance: null, rc_early_years: null, rc_sixth_form: null, report_url: null,
report_card: {},
} as OfstedInspection;
// `page` mimics how each school page used to mount the section; the secondary
// page's branch hard-coded four areas and dropped the sixth form (audit M2).
function renderSection(o: Partial<OfstedInspection>, page: Record<string, unknown> = {}) {
const ofsted = { ...empty, ...o } as OfstedInspection;
render(
<OfstedSection
{...page}
ofsted={ofsted}
urn={1}
isReportCard={false}
ofstedInspectedDate={ofsted.latest_visit?.date ?? null}
oeifAllSameGrade={false}
oeifAreas={ofstedLegacyAreas(ofsted)}
/>,
);
}
it('shows no overall grade, not an older one, after a no-grade inspection (Rabbsfarm)', () => {
renderSection({
inspection_date: '2025-06-17', quality_of_education: 3, behaviour_attitudes: 3,
personal_development: 2, leadership_management: 3, early_years_provision: 2,
current_grade: null, latest_visit: { date: '2025-06-17', kind: 'graded', outcome: null },
});
expect(screen.getByText(/Inspected 17 June 2025/)).toBeInTheDocument();
expect(screen.getByText('No overall grade')).toBeInTheDocument();
expect(screen.queryByText('Good', { selector: 'span' })).not.toBeInTheDocument();
expect(screen.queryByText('Not rated')).not.toBeInTheDocument();
expect(screen.getAllByText('Requires Improvement')).toHaveLength(3);
});
it('keeps the sixth-form judgement when there is no overall grade (audit M2)', () => {
renderSection({
inspection_date: '2025-04-01', quality_of_education: 1, behaviour_attitudes: 1,
personal_development: 1, leadership_management: 1, sixth_form_provision: 2,
current_grade: null, latest_visit: { date: '2025-04-01', kind: 'graded', outcome: null },
}, { variant: 'secondary' });
expect(screen.getByText(/sixth form/i)).toBeInTheDocument();
expect(screen.getByText('Good')).toBeInTheDocument();
});
it('dates a grade by its source and prints a later visit separately (Washwood Heath)', () => {
renderSection({
inspection_date: '2020-03-03', overall_effectiveness: 2, quality_of_education: 2,
current_grade: { grade: 2, date: '2020-03-03', basis: 'graded' },
latest_visit: { date: '2025-05-21', kind: 'ungraded', outcome: 'Standards maintained' },
});
expect(screen.getByText(/Inspected 21 May 2025/)).toBeInTheDocument();
expect(screen.getByText('Graded inspection, 3 March 2020')).toBeInTheDocument();
expect(screen.getByText(/Latest visit: Ungraded inspection, 21 May 2025: Standards maintained/)).toBeInTheDocument();
});
it('says a grade was confirmed at an ungraded visit (Robins Lane)', () => {
renderSection({
inspection_date: '2020-01-07', overall_effectiveness: 2,
current_grade: { grade: 2, date: '2024-07-18', basis: 'confirmed' },
latest_visit: { date: '2024-07-18', kind: 'ungraded', outcome: 'School remains Good' },
});
expect(screen.getByText('Confirmed at an ungraded inspection, 18 July 2024')).toBeInTheDocument();
expect(screen.queryByText(/Latest visit/)).not.toBeInTheDocument();
});
it('prints an ungraded outcome when there is no grade (Oakgrove)', () => {
renderSection({
current_grade: null,
latest_visit: { date: '2024-11-13', kind: 'ungraded', outcome: 'Standards maintained' },
});
expect(screen.getByText('No overall grade')).toBeInTheDocument();
expect(screen.getByText(/Ungraded inspection, 13 November 2024: Standards maintained/)).toBeInTheDocument();
});
@@ -191,7 +191,8 @@ export const primaryFixture = {
personal_development: 2, personal_development: 2,
leadership_management: 2, leadership_management: 2,
previous_overall: 3, previous_overall: 3,
grade_source: 'graded', current_grade: { grade: 2, date: '2023-05-17', basis: 'graded' },
latest_visit: { date: '2023-05-17', kind: 'graded', outcome: null },
}), }),
census, census,
admissions: makeAdmissions({ year: 2024 }), admissions: makeAdmissions({ year: 2024 }),
@@ -295,7 +296,8 @@ export const allThroughFixture = {
behaviour_attitudes: 1, behaviour_attitudes: 1,
personal_development: 1, personal_development: 1,
leadership_management: 1, leadership_management: 1,
grade_source: 'graded', current_grade: { grade: 1, date: '2022-10-04', basis: 'graded' },
latest_visit: { date: '2022-10-04', kind: 'graded', outcome: null },
}), }),
census, census,
admissions: makeAdmissions({ year: 2024, school_phase: 'Secondary' }), admissions: makeAdmissions({ year: 2024, school_phase: 'Secondary' }),
+52 -61
View File
@@ -1,16 +1,18 @@
/** /**
* OfstedSection — shared between the primary and secondary detail pages. * OfstedSection — shared between the primary and secondary detail pages.
* *
* The two versions were ~80% identical, but that figure masked a real fork in * The headline is the school's current Ofsted status (backend:
* the no-overall-grade case: the primary page shows a "Not rated" badge, while * fact_ofsted_latest): the report card; or the overall grade still in force,
* the secondary page shows a four-area OEIF panel. The disclaimer copy also * with the inspection that awarded or confirmed it; or "No overall grade".
* differs slightly. Both are preserved exactly via the `variant` prop rather * A later visit that is not the grade's source gets its own line. Both pages
* than reconciled, because this refactor must not change either page. Merging * render the same branches, so neither drops an area judgement (audit M2).
* them is a follow-up decision for a human, not a side effect of a move. * Rule: docs/superpowers/specs/2026-10-05-ofsted-current-status-design.md
* *
* Server component. * Server component.
*/ */
import { ofstedDisplay } from '@/lib/compareLogic';
import { formatOfstedDate, gradeSourceLine, latestVisitLine, showLatestVisitLine } from '@/lib/ofstedStatus';
import type { OfstedInspection } from '@/lib/types'; import type { OfstedInspection } from '@/lib/types';
import { Section, sectionStyles as styles } from './sectionShared'; import { Section, sectionStyles as styles } from './sectionShared';
@@ -40,14 +42,13 @@ export interface OfstedSectionProps {
ofstedInspectedDate: string | null; ofstedInspectedDate: string | null;
oeifAllSameGrade: boolean; oeifAllSameGrade: boolean;
oeifAreas: { label: string; value: number }[]; oeifAreas: { label: string; value: number }[];
variant?: 'primary' | 'secondary';
} }
export function OfstedSection({ export function OfstedSection({
ofsted, urn, isReportCard, ofstedInspectedDate, ofsted, urn, isReportCard, ofstedInspectedDate,
oeifAllSameGrade, oeifAreas, variant = 'primary', oeifAllSameGrade, oeifAreas,
}: OfstedSectionProps) { }: OfstedSectionProps) {
const isSecondary = variant === 'secondary'; const display = ofstedDisplay(ofsted);
return ( return (
<Section id="ofsted"> <Section id="ofsted">
@@ -55,7 +56,7 @@ export function OfstedSection({
{isReportCard ? 'Ofsted Report Card' : 'Ofsted Rating'} {isReportCard ? 'Ofsted Report Card' : 'Ofsted Rating'}
{ofstedInspectedDate && ( {ofstedInspectedDate && (
<span className={styles.ofstedDate}> <span className={styles.ofstedDate}>
{isSecondary && ' '}Inspected {new Date(ofstedInspectedDate).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })} Inspected {new Date(ofstedInspectedDate).toLocaleDateString('en-GB', { day: 'numeric', month: 'long', year: 'numeric' })}
</span> </span>
)} )}
<a <a
@@ -98,65 +99,55 @@ export function OfstedSection({
})} })}
</div> </div>
</> </>
) : (!isSecondary || ofsted.overall_effectiveness) ? ( ) : (
/* ── Old OEIF layout ── */
<> <>
<div className={styles.ofstedHeader}> <div className={styles.ofstedHeader}>
<span className={`${styles.ofstedGrade} ${styles[`ofstedGrade${ofsted.overall_effectiveness}`]}`}> {display.kind === 'graded' || display.kind === 'confirmed' ? (
{ofsted.overall_effectiveness ? OFSTED_LABELS[ofsted.overall_effectiveness] : 'Not rated'} <>
</span> <span className={`${styles.ofstedGrade} ${styles[`ofstedGrade${display.grade}`]}`}>
{ofsted.previous_overall != null && {display.gradeLabel}
ofsted.previous_overall !== ofsted.overall_effectiveness && ( </span>
<span className={styles.ofstedPrevious}> {ofsted.previous_overall != null && ofsted.previous_overall !== display.grade && (
Previously: {OFSTED_LABELS[ofsted.previous_overall]} <span className={styles.ofstedPrevious}>
</span> Previously: {OFSTED_LABELS[ofsted.previous_overall]}
</span>
)}
</>
) : (
<span className={styles.ofstedGrade}>No overall grade</span>
)} )}
</div> </div>
<p className={styles.ofstedDisclaimer}> <p className={styles.ofstedDisclaimer}>
{ofsted.grade_source === 'ungraded_carried_forward' {ofsted.current_grade
? 'This overall grade is carried forward from an earlier inspection. Ofsted has since visited without issuing a new overall grade. From September 2024, Ofsted no longer makes an overall effectiveness judgement.' ? gradeSourceLine(ofsted.current_grade)
: isSecondary : 'Ofsted stopped giving overall grades in September 2024.'}
? 'From September 2024, Ofsted no longer makes an overall effectiveness judgement in inspections.'
: 'From September 2024, Ofsted no longer makes an overall effectiveness judgement in inspections of state-funded schools.'}
</p> </p>
{oeifAllSameGrade ? ( {showLatestVisitLine(ofsted) && ofsted.latest_visit && (
<p className={styles.ofstedAllSame}> <p className={styles.ofstedDisclaimer}>Latest visit: {latestVisitLine(ofsted.latest_visit)}</p>
Rated <strong>{OFSTED_LABELS[ofsted.overall_effectiveness!]}</strong> across all inspected areas: Quality of Teaching, Behaviour, Pupils&apos; Development and Leadership.
</p>
) : (
<div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{oeifAreas.map(({ label, value }) => (
<div key={label} className={styles.metricCard}>
<div className={styles.metricLabel}>{label}</div>
<div className={`${styles.metricValue} ${styles[`ofstedGrade${value}`]}`}>
{OFSTED_LABELS[value]}
</div>
</div>
))}
</div>
)} )}
</> {oeifAllSameGrade && (display.kind === 'graded' || display.kind === 'confirmed') ? (
) : ( <p className={styles.ofstedAllSame}>
/* ── Secondary only: inspected since Sept 2024, no overall grade ── */ Rated <strong>{display.gradeLabel}</strong> across all inspected areas: Quality of Teaching, Behaviour, Pupils&apos; Development and Leadership.
<> </p>
<p className={styles.sectionSubtitle}> ) : oeifAreas.length > 0 ? (
From September 2024, Ofsted no longer gives a single overall grade. <>
</p> {ofsted.inspection_date && ofsted.inspection_date !== ofsted.latest_visit?.date && (
<div className={`${styles.metricsGrid} ${styles.gradeGrid}`}> <p className={styles.ofstedDisclaimer}>
{[ Area judgements from the graded inspection, {formatOfstedDate(ofsted.inspection_date)}.
{ label: 'Quality of Education', value: ofsted.quality_of_education }, </p>
{ label: 'Behaviour & Attitudes', value: ofsted.behaviour_attitudes }, )}
{ label: 'Personal Development', value: ofsted.personal_development }, <div className={`${styles.metricsGrid} ${styles.gradeGrid}`}>
{ label: 'Leadership & Management', value: ofsted.leadership_management }, {oeifAreas.map(({ label, value }) => (
].filter(({ value }) => value != null).map(({ label, value }) => ( <div key={label} className={styles.metricCard}>
<div key={label} className={styles.metricCard}> <div className={styles.metricLabel}>{label}</div>
<div className={styles.metricLabel}>{label}</div> <div className={`${styles.metricValue} ${styles[`ofstedGrade${value}`]}`}>
<div className={`${styles.metricValue} ${styles[`ofstedGrade${value}`]}`}> {OFSTED_LABELS[value]}
{OFSTED_LABELS[value!]} </div>
</div> </div>
))}
</div> </div>
))} </>
</div> ) : null}
</> </>
)} )}
</Section> </Section>
@@ -55,15 +55,17 @@ export function PrimarySchoolSections({
const secondaryAvg = nationalAvg?.secondary ?? {}; const secondaryAvg = nationalAvg?.secondary ?? {};
const isReportCard = !!(ofsted?.report_card && Object.keys(ofsted.report_card).length > 0); const isReportCard = !!(ofsted?.report_card && Object.keys(ofsted.report_card).length > 0);
// Report cards are dated by their own inspection (rc_inspection_date), never // Report cards are dated by their own inspection (rc_inspection_date);
// the legacy inspection_date (report cards exist only from Nov 2025). // anything else by the school's latest visit, never the older inspection a
// grade may come from.
const ofstedInspectedDate = isReportCard const ofstedInspectedDate = isReportCard
? ofsted?.rc_inspection_date ?? null ? ofsted?.rc_inspection_date ?? null
: ofsted?.inspection_date ?? null; : ofsted?.latest_visit?.date ?? null;
const oeifAreas = ofsted ? ofstedLegacyAreas(ofsted) : []; const oeifAreas = ofsted ? ofstedLegacyAreas(ofsted) : [];
const oeifAllSameGrade = const oeifAllSameGrade =
!!ofsted && !!ofsted &&
!isReportCard && !isReportCard &&
ofsted.overall_effectiveness != null &&
oeifAreas.length >= 3 && oeifAreas.length >= 3 &&
oeifAreas.every((a) => a.value === ofsted.overall_effectiveness); oeifAreas.every((a) => a.value === ofsted.overall_effectiveness);
@@ -77,7 +79,6 @@ export function PrimarySchoolSections({
ofstedInspectedDate={ofstedInspectedDate} ofstedInspectedDate={ofstedInspectedDate}
oeifAllSameGrade={oeifAllSameGrade} oeifAllSameGrade={oeifAllSameGrade}
oeifAreas={oeifAreas} oeifAreas={oeifAreas}
variant="primary"
/> />
)} )}
@@ -63,11 +63,12 @@ export function SecondarySchoolSections({
const isReportCard = !!(ofsted?.report_card && Object.keys(ofsted.report_card).length > 0); const isReportCard = !!(ofsted?.report_card && Object.keys(ofsted.report_card).length > 0);
const ofstedInspectedDate = isReportCard const ofstedInspectedDate = isReportCard
? ofsted?.rc_inspection_date ?? null ? ofsted?.rc_inspection_date ?? null
: ofsted?.inspection_date ?? null; : ofsted?.latest_visit?.date ?? null;
const oeifAreas = ofsted ? ofstedLegacyAreas(ofsted) : []; const oeifAreas = ofsted ? ofstedLegacyAreas(ofsted) : [];
const oeifAllSameGrade = const oeifAllSameGrade =
!!ofsted && !!ofsted &&
!isReportCard && !isReportCard &&
ofsted.overall_effectiveness != null &&
oeifAreas.length >= 3 && oeifAreas.length >= 3 &&
oeifAreas.every((a) => a.value === ofsted.overall_effectiveness); oeifAreas.every((a) => a.value === ofsted.overall_effectiveness);
@@ -81,7 +82,6 @@ export function SecondarySchoolSections({
ofstedInspectedDate={ofstedInspectedDate} ofstedInspectedDate={ofstedInspectedDate}
oeifAllSameGrade={oeifAllSameGrade} oeifAllSameGrade={oeifAllSameGrade}
oeifAreas={oeifAreas} oeifAreas={oeifAreas}
variant="secondary"
/> />
)} )}