feat(ofsted): fall back to ungraded inspection outcome for school grade
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 18s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 48s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 1m30s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s

Ungraded (Section 8) inspections don't assign a fresh grade — the export
only gives free text like "School remains Good". Parse that text into a
grade (remains Outstanding -> 1, remains Good -> 2, else null) and use it
as a last-resort fallback when no graded overall effectiveness exists.

Also retain schools that have only an ungraded inspection (no graded date)
by coalescing the inspection date, so ~8.5k previously-dropped schools now
carry a grade.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tudor
2026-07-01 21:44:01 +01:00
co-authored by Claude Opus 4.8
parent eae62a4b42
commit 2332ee6347
8 changed files with 61 additions and 4 deletions
@@ -23,6 +23,8 @@ select
leadership_management,
early_years_provision,
sixth_form_provision,
ungraded_outcome,
ungraded_grade,
rc_safeguarding_met,
rc_inclusion,
rc_curriculum_teaching,
@@ -60,7 +60,9 @@ select
-- Latest Ofsted (populated after monthly Ofsted pipeline runs)
{% if ofsted_relation is not none %}
o.overall_effectiveness as ofsted_grade,
-- Prefer the graded overall effectiveness; fall back to the grade parsed
-- from the latest ungraded (Section 8) outcome when no graded grade exists.
coalesce(o.overall_effectiveness, o.ungraded_grade) as ofsted_grade,
o.inspection_date as ofsted_date,
o.framework as ofsted_framework
{% else %}
@@ -12,6 +12,8 @@ select
leadership_management,
early_years_provision,
sixth_form_provision,
ungraded_outcome,
ungraded_grade,
rc_safeguarding_met,
rc_inclusion,
rc_curriculum_teaching,
@@ -8,7 +8,13 @@ with source as (
renamed as (
select
cast(urn as integer) as urn,
to_date(nullif(trim(inspection_date), 'NULL'), 'DD/MM/YYYY') as inspection_date,
-- Inspection event date: the graded inspection when present, otherwise the
-- ungraded (Section 8) inspection so schools with only an ungraded
-- inspection are still retained.
coalesce(
to_date(nullif(trim(inspection_date), 'NULL'), 'DD/MM/YYYY'),
to_date(nullif(trim(ungraded_inspection_date), 'NULL'), 'DD/MM/YYYY')
) as inspection_date,
inspection_type,
event_type_grouping as framework,
@@ -21,6 +27,12 @@ renamed as (
{{ safe_numeric('early_years_provision') }}::integer as early_years_provision,
{{ safe_numeric('sixth_form_provision') }}::integer as sixth_form_provision,
-- Ungraded (Section 8) inspection outcome — free text, plus a grade
-- parsed from it (1/2/null) used as a last-resort fallback for schools
-- with no graded overall effectiveness.
nullif(trim(ungraded_outcome), 'NULL') as ungraded_outcome,
{{ parse_ungraded_outcome('ungraded_outcome') }}::integer as ungraded_grade,
-- Report Card fields (post-Nov 2025 framework)
-- TODO: add rc_* columns to tap-uk-ofsted schema once CSV column names are confirmed
null::text as rc_safeguarding_met,
@@ -36,7 +48,10 @@ renamed as (
report_url
from source
where urn is not null
and nullif(trim(inspection_date), 'NULL') is not null
and (
nullif(trim(inspection_date), 'NULL') is not null
or nullif(trim(ungraded_inspection_date), 'NULL') is not null
)
)
select * from renamed