The School type filter offered GIAS's 34 establishment types ("Academy converter", "Academy sponsor led", "Voluntary controlled school"…). These describe governance and funding, which a parent can't be expected to tell apart and rarely needs to. There was also no way to filter by faith, which is the real meaning behind "Voluntary aided" and "Voluntary controlled", and which applies to many academies too.
School type → six groups: State school: academy or free school · State school: council-run · Independent (fee-paying) · Special school (SEND) · Sixth form or college · Alternative provision. Six rarely relevant types (higher education, secure units, online provider…) sit in no group and are reachable only under "Any school type".
New Faith filter: No religious character · Church of England · Roman Catholic · Other Christian · Jewish · Muslim · Other faith. A joint school (e.g. "Roman Catholic/Church of England") matches every faith it names. Faith goes behind More filters on desktop, and after School type in the phone sheet.
Backend: new backend/school_groups.py defines the groups over GIAS codes and looks them up by the translated name, which is all the API's data carries. /api/schools accepts a group key for school_type (an old raw-label link still filters exactly) plus a new faith key; an unknown faith key returns nothing. /api/filters gains school_type_groups and faiths; school_types is unchanged. No mart change, so no Airflow run is needed.
Frontend: FilterBar reads the two lists. Chips, counts, Clear all and analytics include faith. A URL value is matched ignoring case, and an unlisted one (an old link) shows as its own option, so the select never reads "Any" while the list is filtered. The results list's chip shows the group's label.
Analytics note:search_submitted.filters_active now reports type=<group key> (e.g. type=special), not raw labels. Anything grouping on type= will split at the deploy date.
Testing
Backend: new test_school_groups.py, which fails if any GIAS type or religion code is unaccounted for, and test_type_and_faith_filters.py. CI suite 311/311.
Frontend: new FilterBarTypeFaith.test.tsx; existing fixtures moved to group keys. 569/569, typecheck clean, next build passes with DATABASE_URL unset.
E2E: new journey "school type groups and the faith filter narrow to what they name". Against current staging it fails as expected at selecting "Special school (SEND)". It can only pass after merge.
Whole-branch review by a fresh reviewer: 0 Critical. Both Important findings (the results chip showing the raw key; the select reading "Any" for an old or mixed-case value) were fixed test-first.
Deferred minors:/api/filters derives the offered groups from all years, not only the latest; a valid faith key returns nothing if the religion column were ever missing; docs/LEGACY_CODE.md should list /api/filtersschool_types as no longer read by the UI; the new E2E journey passes trivially if its search has no special Catholic schools.
## Problem
The School type filter offered GIAS's 34 establishment types ("Academy converter", "Academy sponsor led", "Voluntary controlled school"…). These describe governance and funding, which a parent can't be expected to tell apart and rarely needs to. There was also no way to filter by faith, which is the real meaning behind "Voluntary aided" and "Voluntary controlled", and which applies to many academies too.
Spec: `docs/superpowers/specs/2026-10-02-school-type-groups-and-faith-filter-design.md` · Plan: `docs/superpowers/plans/2026-10-02-school-type-groups-and-faith-filter.md`
## Change
**School type → six groups:** State school: academy or free school · State school: council-run · Independent (fee-paying) · Special school (SEND) · Sixth form or college · Alternative provision. Six rarely relevant types (higher education, secure units, online provider…) sit in no group and are reachable only under "Any school type".
**New Faith filter:** No religious character · Church of England · Roman Catholic · Other Christian · Jewish · Muslim · Other faith. A joint school (e.g. "Roman Catholic/Church of England") matches every faith it names. Faith goes behind More filters on desktop, and after School type in the phone sheet.
- **Backend:** new `backend/school_groups.py` defines the groups over GIAS codes and looks them up by the translated name, which is all the API's data carries. `/api/schools` accepts a group key for `school_type` (an old raw-label link still filters exactly) plus a new `faith` key; an unknown faith key returns nothing. `/api/filters` gains `school_type_groups` and `faiths`; `school_types` is unchanged. No mart change, so no Airflow run is needed.
- **Frontend:** FilterBar reads the two lists. Chips, counts, Clear all and analytics include faith. A URL value is matched ignoring case, and an unlisted one (an old link) shows as its own option, so the select never reads "Any" while the list is filtered. The results list's chip shows the group's label.
- **Analytics note:** `search_submitted.filters_active` now reports `type=<group key>` (e.g. `type=special`), not raw labels. Anything grouping on `type=` will split at the deploy date.
## Testing
- Backend: new `test_school_groups.py`, which fails if any GIAS type or religion code is unaccounted for, and `test_type_and_faith_filters.py`. CI suite 311/311.
- Frontend: new `FilterBarTypeFaith.test.tsx`; existing fixtures moved to group keys. 569/569, typecheck clean, `next build` passes with `DATABASE_URL` unset.
- E2E: new journey **"school type groups and the faith filter narrow to what they name"**. Against current staging it fails as expected at selecting "Special school (SEND)". It can only pass after merge.
- Whole-branch review by a fresh reviewer: 0 Critical. Both Important findings (the results chip showing the raw key; the select reading "Any" for an old or mixed-case value) were fixed test-first.
**Deferred minors:** `/api/filters` derives the offered groups from all years, not only the latest; a valid faith key returns nothing if the religion column were ever missing; `docs/LEGACY_CODE.md` should list `/api/filters` `school_types` as no longer read by the UI; the new E2E journey passes trivially if its search has no special Catholic schools.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The results list's chip printed the school type group's key ("post16")
rather than its label. A URL value that no option spelled the same way
(an old link's raw GIAS type, or a key in another case) left the select
reading "Any school type" while the list stayed filtered, and choosing
"Any" changed nothing. Values now match options ignoring case, as the
API does, and an unlisted one is shown as an option of its own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds six parent-facing school type groups and a faith filter. The grouping lives in a new backend module that looks groups up by GIAS name, and /api/filters returns the new option lists. The frontend gets a Faith select, group labels on chips, and fallback handling for old raw-label links and mixed-case keys. The logic looks correct, including missing or blank religions counting as 'none', unknown keys matching nothing, and old links still working. Test coverage is thorough and nothing blocks the merge.
🟡 Minor
docs/superpowers/specs/2026-10-02-school-type-groups-and-faith-filter-design.md: The /api/schools section still says it filters on school_type_group and on a faith_groups column. The implementation has no such columns and filters by name at request time through _names_in_group. The architecture section was corrected but this section was not, so the spec contradicts the code.
nextjs-app/tests/components/FilterBarTypeFaith.test.tsx: The file ends with stray trailing blank lines. ResultsToolbar.test.tsx also gains a trailing blank line. This is a cosmetic lint nit.
## 🤖 AI Code Review (Claude Code)
Adds six parent-facing school type groups and a faith filter. The grouping lives in a new backend module that looks groups up by GIAS name, and `/api/filters` returns the new option lists. The frontend gets a Faith select, group labels on chips, and fallback handling for old raw-label links and mixed-case keys. The logic looks correct, including missing or blank religions counting as 'none', unknown keys matching nothing, and old links still working. Test coverage is thorough and nothing blocks the merge.
### 🟡 Minor
- **docs/superpowers/specs/2026-10-02-school-type-groups-and-faith-filter-design.md**: The `/api/schools` section still says it filters on `school_type_group` and on a `faith_groups` column. The implementation has no such columns and filters by name at request time through `_names_in_group`. The architecture section was corrected but this section was not, so the spec contradicts the code.
- **nextjs-app/__tests__/components/FilterBarTypeFaith.test.tsx**: The file ends with stray trailing blank lines. `ResultsToolbar.test.tsx` also gains a trailing blank line. This is a cosmetic lint nit.
The /api/schools section still described filtering on stored
school_type_group and faith_groups columns, which the architecture
correction had already dropped: the filters look up the name columns at
request time. Also trims a trailing blank line from two test files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds parent-facing school type groups and a faith filter. A new backend/school_groups.py maps GIAS names to groups, /api/schools gains a faith param and a group-key branch for school_type, and /api/filters gains school_type_groups and faiths. FilterBar gets a Faith select and grouped type options. Old raw-label links, missing or blank religion, unknown keys and mixed case are all handled and tested, and I found no correctness, security or deploy problems that should block the merge.
🟡 Minor
nextjs-app/components/HomeView.tsx: The results-list chip row shows school_type (now labelled) but has no chip for the new faith param. A faith-filtered result list therefore shows no indication in that row. FilterBar's own chips do cover faith, so this is only an inconsistency.
backend/tests/test_school_groups.py: The test imports yaml to read dbt_project.yml. If pyyaml is not in requirements.txt, the whole module fails at collection in CI. The plan itself notes this uncertainty. Confirm that pyyaml is a declared dependency, or add it.
e2e/tests/journeys.spec.ts: The new journey cannot pass until the change is deployed to staging, because it selects the new option labels. If the staging E2E gate also runs on pre-merge PRs, this test will fail there. The PR says it runs post-merge only, so verify that.
## 🤖 AI Code Review (Claude Code)
Adds parent-facing school type groups and a faith filter. A new `backend/school_groups.py` maps GIAS names to groups, `/api/schools` gains a `faith` param and a group-key branch for `school_type`, and `/api/filters` gains `school_type_groups` and `faiths`. FilterBar gets a Faith select and grouped type options. Old raw-label links, missing or blank religion, unknown keys and mixed case are all handled and tested, and I found no correctness, security or deploy problems that should block the merge.
### 🟡 Minor
- **nextjs-app/components/HomeView.tsx**: The results-list chip row shows `school_type` (now labelled) but has no chip for the new `faith` param. A faith-filtered result list therefore shows no indication in that row. FilterBar's own chips do cover faith, so this is only an inconsistency.
- **backend/tests/test_school_groups.py**: The test imports `yaml` to read `dbt_project.yml`. If `pyyaml` is not in `requirements.txt`, the whole module fails at collection in CI. The plan itself notes this uncertainty. Confirm that `pyyaml` is a declared dependency, or add it.
- **e2e/tests/journeys.spec.ts**: The new journey cannot pass until the change is deployed to staging, because it selects the new option labels. If the staging E2E gate also runs on pre-merge PRs, this test will fail there. The PR says it runs post-merge only, so verify that.
The row repeated the search, local authority and school type above the
results list, and nothing else: no phase, distance, gender, sixth form,
admissions or faith. The filter bar already shows every one of them, in
its selects and More filters count on desktop and as removable chips on
phones, so the row was a partial second copy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds parent-facing school type groups and a faith filter. Groups are defined over GIAS codes in a new backend module and looked up by translated name. /api/schools gets the faith param and a group-key branch for school_type, and /api/filters gets two new keys. The frontend adds the Faith select, group-based School type options, and compatibility for old raw-label links. The change looks sound: missing, blank and unknown names are handled, old links still work, and the frontend tolerates an API without the new keys. I found no correctness, security or deploy problems.
✅ No issues found.
## 🤖 AI Code Review (Claude Code)
Adds parent-facing school type groups and a faith filter. Groups are defined over GIAS codes in a new backend module and looked up by translated name. `/api/schools` gets the `faith` param and a group-key branch for `school_type`, and `/api/filters` gets two new keys. The frontend adds the Faith select, group-based School type options, and compatibility for old raw-label links. The change looks sound: missing, blank and unknown names are handled, old links still work, and the frontend tolerates an API without the new keys. I found no correctness, security or deploy problems.
✅ No issues found.
tudor
merged commit fb3ef7d2b9 into main2026-10-02 14:05:43 +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.
Problem
The School type filter offered GIAS's 34 establishment types ("Academy converter", "Academy sponsor led", "Voluntary controlled school"…). These describe governance and funding, which a parent can't be expected to tell apart and rarely needs to. There was also no way to filter by faith, which is the real meaning behind "Voluntary aided" and "Voluntary controlled", and which applies to many academies too.
Spec:
docs/superpowers/specs/2026-10-02-school-type-groups-and-faith-filter-design.md· Plan:docs/superpowers/plans/2026-10-02-school-type-groups-and-faith-filter.mdChange
School type → six groups: State school: academy or free school · State school: council-run · Independent (fee-paying) · Special school (SEND) · Sixth form or college · Alternative provision. Six rarely relevant types (higher education, secure units, online provider…) sit in no group and are reachable only under "Any school type".
New Faith filter: No religious character · Church of England · Roman Catholic · Other Christian · Jewish · Muslim · Other faith. A joint school (e.g. "Roman Catholic/Church of England") matches every faith it names. Faith goes behind More filters on desktop, and after School type in the phone sheet.
backend/school_groups.pydefines the groups over GIAS codes and looks them up by the translated name, which is all the API's data carries./api/schoolsaccepts a group key forschool_type(an old raw-label link still filters exactly) plus a newfaithkey; an unknown faith key returns nothing./api/filtersgainsschool_type_groupsandfaiths;school_typesis unchanged. No mart change, so no Airflow run is needed.search_submitted.filters_activenow reportstype=<group key>(e.g.type=special), not raw labels. Anything grouping ontype=will split at the deploy date.Testing
test_school_groups.py, which fails if any GIAS type or religion code is unaccounted for, andtest_type_and_faith_filters.py. CI suite 311/311.FilterBarTypeFaith.test.tsx; existing fixtures moved to group keys. 569/569, typecheck clean,next buildpasses withDATABASE_URLunset.Deferred minors:
/api/filtersderives the offered groups from all years, not only the latest; a valid faith key returns nothing if the religion column were ever missing;docs/LEGACY_CODE.mdshould list/api/filtersschool_typesas no longer read by the UI; the new E2E journey passes trivially if its search has no special Catholic schools.🤖 Generated with Claude Code
The results list's chip printed the school type group's key ("post16") rather than its label. A URL value that no option spelled the same way (an old link's raw GIAS type, or a key in another case) left the select reading "Any school type" while the list stayed filtered, and choosing "Any" changed nothing. Values now match options ignoring case, as the API does, and an unlisted one is shown as an option of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>🤖 AI Code Review (Claude Code)
Adds six parent-facing school type groups and a faith filter. The grouping lives in a new backend module that looks groups up by GIAS name, and
/api/filtersreturns the new option lists. The frontend gets a Faith select, group labels on chips, and fallback handling for old raw-label links and mixed-case keys. The logic looks correct, including missing or blank religions counting as 'none', unknown keys matching nothing, and old links still working. Test coverage is thorough and nothing blocks the merge.🟡 Minor
/api/schoolssection still says it filters onschool_type_groupand on afaith_groupscolumn. The implementation has no such columns and filters by name at request time through_names_in_group. The architecture section was corrected but this section was not, so the spec contradicts the code.ResultsToolbar.test.tsxalso gains a trailing blank line. This is a cosmetic lint nit.🤖 AI Code Review (Claude Code)
Adds parent-facing school type groups and a faith filter. A new
backend/school_groups.pymaps GIAS names to groups,/api/schoolsgains afaithparam and a group-key branch forschool_type, and/api/filtersgainsschool_type_groupsandfaiths. FilterBar gets a Faith select and grouped type options. Old raw-label links, missing or blank religion, unknown keys and mixed case are all handled and tested, and I found no correctness, security or deploy problems that should block the merge.🟡 Minor
school_type(now labelled) but has no chip for the newfaithparam. A faith-filtered result list therefore shows no indication in that row. FilterBar's own chips do cover faith, so this is only an inconsistency.yamlto readdbt_project.yml. Ifpyyamlis not inrequirements.txt, the whole module fails at collection in CI. The plan itself notes this uncertainty. Confirm thatpyyamlis a declared dependency, or add it.🤖 AI Code Review (Claude Code)
Adds parent-facing school type groups and a faith filter. Groups are defined over GIAS codes in a new backend module and looked up by translated name.
/api/schoolsgets thefaithparam and a group-key branch forschool_type, and/api/filtersgets two new keys. The frontend adds the Faith select, group-based School type options, and compatibility for old raw-label links. The change looks sound: missing, blank and unknown names are handled, old links still work, and the frontend tolerates an API without the new keys. I found no correctness, security or deploy problems.✅ No issues found.