Staging is broken right now.POST /api/admin/regenerate-sitemap 500s, so no sitemap can be regenerated at all.
This fix was pushed to the #114 branch, but #114 had already merged — the commit stranded on the tip of a merged branch and never reached main. Verified with git merge-base --is-ancestor, not the merged flag. Same stacked-PR shape as #108/#110.
What is failing
ValueError: locality 'richmond' collides with a published town of the same slug
build_sitemaps() -> _place_sitemap_rows() -> get_place_registry()
-> build_place_registry() -> _locality_places()
GIAS has a town Richmond in North Yorkshire with 37 schools. My curated locality list also had richmond for Richmond upon Thames. The collision guard raised, and the raise propagated all the way out of the admin endpoint.
The guard did its job. The problem is what it cost.
The real fix: a curation typo must not take down the sitemap
One bad row of hand-maintained data broke sitemap generation for all 25,000 school pages. The guard now skips the colliding locality and logs an error.
Skipping still achieves everything the guard was for — a locality never silently shadows a town — without the blast radius. And this matters well beyond today: GIAS town names change with no code change in this repo, so the raising version could have fired spontaneously in production months from now, on a deploy that touched nothing.
Also: four localities were boroughs, not districts
hackney, islington, greenwich and ealing are London local authorities with 104, 72, 108 and 115 schools. They already have pages at /schools/authority/[la]. A locality defined by two or three outcodes would have been a partial, near-duplicate subset — precisely the thin-content failure the two-namespace design exists to prevent.
Removed, along with richmond (Richmond upon Thames is a borough too). A test now guards all 32 London boroughs by name, so this cannot drift back.
Validated against the live corpus
The original list was curated from knowledge and never checked against real data. That was the process failure behind both bugs. Now:
Localities
15
Colliding with a viable town
none
Duplicating an authority
none
Clearing the 5-school threshold
15 of 15
Shoreditch 44 schools, Walthamstow 40, Wimbledon 34, down to Chiswick 12.
Backend: 97 passed.
After merging
Redeploy, then re-run sitemap_generate. Expect sitemaps to go 5 → 7 as places-1.xml and outcodes-1.xml appear.
**Staging is broken right now.** `POST /api/admin/regenerate-sitemap` 500s, so no sitemap can be regenerated at all.
This fix was pushed to the #114 branch, but #114 had already merged — the commit stranded on the tip of a merged branch and never reached `main`. Verified with `git merge-base --is-ancestor`, not the merged flag. Same stacked-PR shape as #108/#110.
## What is failing
```
ValueError: locality 'richmond' collides with a published town of the same slug
build_sitemaps() -> _place_sitemap_rows() -> get_place_registry()
-> build_place_registry() -> _locality_places()
```
GIAS has a town **Richmond in North Yorkshire with 37 schools**. My curated locality list also had `richmond` for Richmond upon Thames. The collision guard raised, and the raise propagated all the way out of the admin endpoint.
The guard did its job. The problem is what it cost.
## The real fix: a curation typo must not take down the sitemap
One bad row of hand-maintained data broke sitemap generation for **all 25,000 school pages**. The guard now skips the colliding locality and logs an error.
Skipping still achieves everything the guard was for — a locality never silently shadows a town — without the blast radius. And this matters well beyond today: **GIAS town names change with no code change in this repo**, so the raising version could have fired spontaneously in production months from now, on a deploy that touched nothing.
## Also: four localities were boroughs, not districts
`hackney`, `islington`, `greenwich` and `ealing` are London **local authorities** with 104, 72, 108 and 115 schools. They already have pages at `/schools/authority/[la]`. A locality defined by two or three outcodes would have been a partial, near-duplicate subset — precisely the thin-content failure the two-namespace design exists to prevent.
Removed, along with `richmond` (Richmond upon Thames is a borough too). A test now guards all 32 London boroughs by name, so this cannot drift back.
## Validated against the live corpus
The original list was curated from knowledge and never checked against real data. That was the process failure behind both bugs. Now:
| | |
|---|---|
| Localities | 15 |
| Colliding with a viable town | **none** |
| Duplicating an authority | **none** |
| Clearing the 5-school threshold | **15 of 15** |
Shoreditch 44 schools, Walthamstow 40, Wimbledon 34, down to Chiswick 12.
Backend: 97 passed.
## After merging
Redeploy, then re-run `sitemap_generate`. Expect `sitemaps` to go 5 → 7 as `places-1.xml` and `outcodes-1.xml` appear.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
Sitemap regeneration failed on staging. 'richmond' in the curated locality
list collides with the GIAS town Richmond in North Yorkshire (37 schools), the
registry raised, and the admin endpoint 500d — taking down sitemap generation
for all 25,000 school pages over one bad row of curated data.
The guard now skips the colliding locality and logs an error. Skipping still
achieves what the guard was for — a locality never silently shadows a town —
without letting curated data break the site. That matters beyond this bug:
GIAS town names change with no code change here, so a raise could fire
spontaneously in production later.
Also removes four localities that were London boroughs rather than districts.
Hackney, Islington, Greenwich and Ealing are local authorities with 104, 72,
108 and 115 schools and already have authority pages; a locality defined by
two or three outcodes would have been a partial near-duplicate of one — the
thin-content failure the two-namespace design exists to avoid. A test now
guards the whole borough list.
Validated against the live corpus: 15 localities, no town collisions, no
authority duplicates, all 15 clear the threshold.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
Changes locality/town-slug collisions from a hard ValueError (which took down sitemap generation for all 25,000 school pages) to a logged skip, removes the four curated localities that were borough-duplicates or collided with a GIAS town, and keeps the CSV seed, docstrings, and tests in sync with the change.
✅ No issues found.
## 🤖 AI Code Review (Claude Code)
Changes locality/town-slug collisions from a hard ValueError (which took down sitemap generation for all 25,000 school pages) to a logged skip, removes the four curated localities that were borough-duplicates or collided with a GIAS town, and keeps the CSV seed, docstrings, and tests in sync with the change.
✅ No issues found.
tudor
merged commit d423826840 into main2026-08-21 19:26:02 +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.
Staging is broken right now.
POST /api/admin/regenerate-sitemap500s, so no sitemap can be regenerated at all.This fix was pushed to the #114 branch, but #114 had already merged — the commit stranded on the tip of a merged branch and never reached
main. Verified withgit merge-base --is-ancestor, not the merged flag. Same stacked-PR shape as #108/#110.What is failing
GIAS has a town Richmond in North Yorkshire with 37 schools. My curated locality list also had
richmondfor Richmond upon Thames. The collision guard raised, and the raise propagated all the way out of the admin endpoint.The guard did its job. The problem is what it cost.
The real fix: a curation typo must not take down the sitemap
One bad row of hand-maintained data broke sitemap generation for all 25,000 school pages. The guard now skips the colliding locality and logs an error.
Skipping still achieves everything the guard was for — a locality never silently shadows a town — without the blast radius. And this matters well beyond today: GIAS town names change with no code change in this repo, so the raising version could have fired spontaneously in production months from now, on a deploy that touched nothing.
Also: four localities were boroughs, not districts
hackney,islington,greenwichandealingare London local authorities with 104, 72, 108 and 115 schools. They already have pages at/schools/authority/[la]. A locality defined by two or three outcodes would have been a partial, near-duplicate subset — precisely the thin-content failure the two-namespace design exists to prevent.Removed, along with
richmond(Richmond upon Thames is a borough too). A test now guards all 32 London boroughs by name, so this cannot drift back.Validated against the live corpus
The original list was curated from knowledge and never checked against real data. That was the process failure behind both bugs. Now:
Shoreditch 44 schools, Walthamstow 40, Wimbledon 34, down to Chiswick 12.
Backend: 97 passed.
After merging
Redeploy, then re-run
sitemap_generate. Expectsitemapsto go 5 → 7 asplaces-1.xmlandoutcodes-1.xmlappear.🤖 Generated with Claude Code
https://claude.ai/code/session_015mWQnpye9F299NVRCCSRvj
🤖 AI Code Review (Claude Code)
Changes locality/town-slug collisions from a hard ValueError (which took down sitemap generation for all 25,000 school pages) to a logged skip, removes the four curated localities that were borough-duplicates or collided with a GIAS town, and keeps the CSV seed, docstrings, and tests in sync with the change.
✅ No issues found.