Backend PR (2 of 3) for the compare-screen redesign — exposes the PR #32 data through the API per spec §6/§8. All response changes are additive; existing consumers and e2e journeys are untouched.
What /api/compare now returns (additions only)
{"comparison":{"<urn>":{"school_info":{...},// unchanged
"yearly_data":[...],// unchanged + new columns (progress CIs, KS4 banding/gaps)
"ofsted":{...,"grade_source":"graded|ungraded_carried_forward","report_card":{"rc_achievement":{"code":2,"label":"Strong standard"},...},"ofsted_page_url":"https://reports.ofsted.gov.uk/provider/21/<urn>"},"census":{...},"admissions":{...incl.2nd/3rd-pref+cross-LA...},"admissions_history":[...],"deprivation":{...}}},"national_averages":{...},// same payload as /api/national-averages (shared helper, not duplicated)
"benchmarks":{// computed, never labelled as official
"source":"state-school average (computed from our dataset)","primary":{"disadvantaged_rwm_expected_pct":...,"eal_pct":...,"sen_support_pct":...,"disadvantaged_pct":...,"median_pupils":...},"secondary":{...}}}
Also: /api/national-averages now exposes gps_expected_pct / gps_high_pct / science_expected_pct (they were in the mart but not in the endpoint's metric list — this was why the England GPS/science ticks looked missing).
Notable decisions
Report-card labels are pinned to the live-sampled Ofsted vocabulary ("Needs attention", not the draft's "Attention needed"); safeguarding is excluded from graded areas by construction (backend/ofsted_codes.py, fully tested).
grade_source distinguishes a graded inspection from a carried-forward ungraded grade (expert-review requirement §8.4).
Benchmarks use a cohort-weighted average for disadvantaged attainment and medians for context measures, tagged with an explicit provenance string (§8.6).
One dbt ride-along: fact_performance (the combined mart the backend reads) now threads the PR #32 columns through — they were in fact_ks2/ks4_performance but not the merged mart.
Supplementary failures degrade to null blocks with HTTP 200 (same defensive pattern as the detail endpoint).
Tests
14 new tests (44 total): ofsted codes, supplementary enrichment, benchmarks math (hand-checkable weighted average), compare-endpoint shape + degradation, GPS/science exposure.
Deploy notes
New fields return NULL/empty until the DAGs have run on the target environment (already done on staging; prod needs its DAG runs after promotion).
No e2e changes: no user-facing behaviour changes — the frontend PR carries the journey updates.
Post-merge staging check
curl -s "https://stx.schoolcompare.co.uk/api/compare?urns=138690,100140" → expect the new keys, benchmarks.primary.disadvantaged_rwm_expected_pct ≈ 45–47, and report-card blocks (empty until a school has a Nov-2025 inspection).
Backend PR (2 of 3) for the compare-screen redesign — exposes the PR #32 data through the API per spec §6/§8. All response changes are **additive**; existing consumers and e2e journeys are untouched.
## What `/api/compare` now returns (additions only)
```jsonc
{
"comparison": {
"<urn>": {
"school_info": { ... }, // unchanged
"yearly_data": [ ... ], // unchanged + new columns (progress CIs, KS4 banding/gaps)
"ofsted": { ..., "grade_source": "graded|ungraded_carried_forward",
"report_card": { "rc_achievement": {"code":2,"label":"Strong standard"}, ... },
"ofsted_page_url": "https://reports.ofsted.gov.uk/provider/21/<urn>" },
"census": { ... }, "admissions": { ...incl. 2nd/3rd-pref + cross-LA... },
"admissions_history": [ ... ], "deprivation": { ... }
}
},
"national_averages": { ... }, // same payload as /api/national-averages (shared helper, not duplicated)
"benchmarks": { // computed, never labelled as official
"source": "state-school average (computed from our dataset)",
"primary": { "disadvantaged_rwm_expected_pct": ..., "eal_pct": ..., "sen_support_pct": ..., "disadvantaged_pct": ..., "median_pupils": ... },
"secondary": { ... }
}
}
```
Also: `/api/national-averages` now exposes `gps_expected_pct` / `gps_high_pct` / `science_expected_pct` (they were in the mart but not in the endpoint's metric list — this was why the England GPS/science ticks looked missing).
## Notable decisions
- **Report-card labels** are pinned to the live-sampled Ofsted vocabulary ("Needs attention", not the draft's "Attention needed"); safeguarding is excluded from graded areas by construction (`backend/ofsted_codes.py`, fully tested).
- **`grade_source`** distinguishes a graded inspection from a carried-forward ungraded grade (expert-review requirement §8.4).
- **Benchmarks** use a cohort-weighted average for disadvantaged attainment and medians for context measures, tagged with an explicit provenance string (§8.6).
- One dbt ride-along: `fact_performance` (the combined mart the backend reads) now threads the PR #32 columns through — they were in `fact_ks2/ks4_performance` but not the merged mart.
- Supplementary failures degrade to null blocks with HTTP 200 (same defensive pattern as the detail endpoint).
## Tests
14 new tests (44 total): ofsted codes, supplementary enrichment, benchmarks math (hand-checkable weighted average), compare-endpoint shape + degradation, GPS/science exposure.
## Deploy notes
- New fields return NULL/empty until the DAGs have run on the target environment (already done on staging; prod needs its DAG runs after promotion).
- No e2e changes: no user-facing behaviour changes — the frontend PR carries the journey updates.
## Post-merge staging check
`curl -s "https://stx.schoolcompare.co.uk/api/compare?urns=138690,100140"` → expect the new keys, `benchmarks.primary.disadvantaged_rwm_expected_pct` ≈ 45–47, and report-card blocks (empty until a school has a Nov-2025 inspection).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
This PR wires previously-added mart columns (KS2 progress CIs, KS4 banding/disadvantage gaps, extended admissions fields) through the backend, adds Ofsted report-card label translation and a computed state-school benchmarks helper, and enriches /api/compare with per-school supplementary blocks plus top-level national_averages/benchmarks — all additive to existing response shapes. The change is well-tested (new unit tests for compute_benchmarks, ofsted_codes, and compare enrichment), follows existing defensive patterns for optional DB lookups, and the accompanying dbt model change correctly threads the new columns through fact_performance without altering the join logic.
✅ No issues found.
## 🤖 AI Code Review (Claude Code)
This PR wires previously-added mart columns (KS2 progress CIs, KS4 banding/disadvantage gaps, extended admissions fields) through the backend, adds Ofsted report-card label translation and a computed state-school benchmarks helper, and enriches /api/compare with per-school supplementary blocks plus top-level national_averages/benchmarks — all additive to existing response shapes. The change is well-tested (new unit tests for compute_benchmarks, ofsted_codes, and compare enrichment), follows existing defensive patterns for optional DB lookups, and the accompanying dbt model change correctly threads the new columns through fact_performance without altering the join logic.
✅ No issues found.
tudor
merged commit 4a8e798c64 into main2026-07-13 21:58:51 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Backend PR (2 of 3) for the compare-screen redesign — exposes the PR #32 data through the API per spec §6/§8. All response changes are additive; existing consumers and e2e journeys are untouched.
What
/api/comparenow returns (additions only)Also:
/api/national-averagesnow exposesgps_expected_pct/gps_high_pct/science_expected_pct(they were in the mart but not in the endpoint's metric list — this was why the England GPS/science ticks looked missing).Notable decisions
backend/ofsted_codes.py, fully tested).grade_sourcedistinguishes a graded inspection from a carried-forward ungraded grade (expert-review requirement §8.4).fact_performance(the combined mart the backend reads) now threads the PR #32 columns through — they were infact_ks2/ks4_performancebut not the merged mart.Tests
14 new tests (44 total): ofsted codes, supplementary enrichment, benchmarks math (hand-checkable weighted average), compare-endpoint shape + degradation, GPS/science exposure.
Deploy notes
Post-merge staging check
curl -s "https://stx.schoolcompare.co.uk/api/compare?urns=138690,100140"→ expect the new keys,benchmarks.primary.disadvantaged_rwm_expected_pct≈ 45–47, and report-card blocks (empty until a school has a Nov-2025 inspection).🤖 Generated with Claude Code
https://claude.ai/code/session_0146VHeLAWjDVE2B5uU67jCB
🤖 AI Code Review (Claude Code)
This PR wires previously-added mart columns (KS2 progress CIs, KS4 banding/disadvantage gaps, extended admissions fields) through the backend, adds Ofsted report-card label translation and a computed state-school benchmarks helper, and enriches /api/compare with per-school supplementary blocks plus top-level national_averages/benchmarks — all additive to existing response shapes. The change is well-tested (new unit tests for compute_benchmarks, ofsted_codes, and compare enrichment), follows existing defensive patterns for optional DB lookups, and the accompanying dbt model change correctly threads the new columns through fact_performance without altering the join logic.
✅ No issues found.