Summary
The production /where-to-buy page currently renders four separate sections that are all on Saba, with headings that lose interior capitalization:
- "Fort bay, saba"
- "Saba"
- "Windwardside / the bottom, saba"
- "Windwardside, saba"
The Island filter dropdown offers the same four near-duplicate options, so a visitor filtering by island sees four confusing choices that all mean Saba.
Evidence
Production HTML today (checked 2026-09-23):
<h2>Fort bay, saba</h2>
<h2>Saba</h2>
<h2>Windwardside / the bottom, saba</h2>
<h2>Windwardside, saba</h2>
and matching <option> values in the Island filter.
Cause in lib/venue-filters.ts:
islandKey() (lines 73-86) only normalizes Sint Maarten/SXM and Sint Eustatius/Statia variants. Any other locationName lowercases as-is, so "Fort Bay, Saba", "Windwardside, Saba", and "Windwardside / The Bottom, Saba" become three distinct keys instead of one Saba group.
islandDisplayName() (lines 89-93) capitalizes only the first character of the lowercased key, producing "Fort bay, saba" rather than "Fort Bay, Saba".
Impact
- Headings on a public customer-facing page show incorrect casing.
- Semantically identical locations are split into separate sections, and the "Island" filter granularity is locality-level for Saba while island-level for the other islands — inconsistent with the page's own "Regional Availability" framing (Saba / SXM / Statia).
- Locality detail is not lost by collapsing groups: each
VenueCard already renders the raw venue.locationName.
Why existing tests did not catch it
tests/lib/venue-filters.test.ts pins the SXM/Statia normalization and asserts other names "keep ... as lowercase keys" — the current behavior is tested as designed; the Saba-locality case and heading casing were not covered. The where-to-buy fixture data uses uniform location names, so the smoke suite never sees fragmented groups.
Recommended scope
Decide the canonical grouping level, then implement one of:
- Normalize Saba locality names to the
"saba" island key in islandKey() (consistent with the island-level framing; all four current variants collapse into one "Saba" section and one filter option), or
- Keep locality-level groups but render a properly-cased display name (e.g. preserve the venue's original
locationName for the heading instead of the lowercased key), and normalize obvious spelling/formatting variants like "Windwardside / the bottom, saba" vs "Windwardside, saba".
Option 1 matches the existing "island" semantics and the Regional Availability section; note an admin data-entry pass on locationName values may still be worthwhile for consistency on the cards themselves.
Acceptance criteria
Overlap
None — #84 (Where to Buy filtering) added the grouping/filtering this builds on; no existing issue tracks the fragmentation.
Summary
The production
/where-to-buypage currently renders four separate sections that are all on Saba, with headings that lose interior capitalization:The Island filter dropdown offers the same four near-duplicate options, so a visitor filtering by island sees four confusing choices that all mean Saba.
Evidence
Production HTML today (checked 2026-09-23):
and matching
<option>values in the Island filter.Cause in
lib/venue-filters.ts:islandKey()(lines 73-86) only normalizes Sint Maarten/SXM and Sint Eustatius/Statia variants. Any otherlocationNamelowercases as-is, so"Fort Bay, Saba","Windwardside, Saba", and"Windwardside / The Bottom, Saba"become three distinct keys instead of one Saba group.islandDisplayName()(lines 89-93) capitalizes only the first character of the lowercased key, producing"Fort bay, saba"rather than"Fort Bay, Saba".Impact
VenueCardalready renders the rawvenue.locationName.Why existing tests did not catch it
tests/lib/venue-filters.test.tspins the SXM/Statia normalization and asserts other names "keep ... as lowercase keys" — the current behavior is tested as designed; the Saba-locality case and heading casing were not covered. The where-to-buy fixture data uses uniform location names, so the smoke suite never sees fragmented groups.Recommended scope
Decide the canonical grouping level, then implement one of:
"saba"island key inislandKey()(consistent with the island-level framing; all four current variants collapse into one "Saba" section and one filter option), orlocationNamefor the heading instead of the lowercased key), and normalize obvious spelling/formatting variants like "Windwardside / the bottom, saba" vs "Windwardside, saba".Option 1 matches the existing "island" semantics and the Regional Availability section; note an admin data-entry pass on
locationNamevalues may still be worthwhile for consistency on the cards themselves.Acceptance criteria
locationNamelocality.Overlap
None — #84 (Where to Buy filtering) added the grouping/filtering this builds on; no existing issue tracks the fragmentation.