fix(counties): make the cluster and the entry panel agree on a US county
An operator asked why K1SEI showed "Middlesex" in Info (F2) and "Lower
Connecticut River Valley" in the cluster. Two sources: the entry panel has
a callbook answer, a spot carries only a callsign so the cluster derives one
from the FCC licence ZIP through GeoNames — and GeoNames has followed the
Census in replacing Connecticut's counties with the 2022 planning regions.
No award, callbook or log uses those, so every CT station matched nothing:
new county for ever, and counting toward nothing.
Measured against a full ULS import (1 556 444 US callsigns), 23 223 resolved
to a name the USA-CA reference does not contain. Three causes, three fixes:
- Spelling. "City and County of San Francisco", "Baltimore (city)",
"Nome (CA)", plus counties renamed since the award list was drawn
(Kusilvak, Oglala Lakota, the Valdez-Cordova split) and Alaska's four
"X City and Borough", whose reference codes read "JUNEAUCITYAND" because
the county-type suffix strip eats the wrong end. Normalised in
award.USCountyKey, which both sides already go through. 7 515 callsigns,
no re-download needed.
- Doña Ana, NM shipped into the reference as "NM/DO̱AANA" — mangled by a
non-UTF-8 CSV line, a code nothing could ever produce, so that county was
unwinnable and silent about it. Row repaired, cntygen now refuses such a
line, and a test makes every one of the 3 102 references reproduce its own
code from its own name.
- Connecticut. A planning region is drawn from towns in several counties, so
no name maps to a name — only the ZIP can resolve it. cmd/ctzipgen builds
the table from the Census 2020 crosswalk, filling PO-box-only ZIPs from the
nearest resolved centroid; all 11 ZIPs GeoNames still labels with a real
county agree with the result. 15 037 callsigns, applied at import, so the
store now carries a rules version and Settings says when a re-download is
needed.
Alignment itself is the last piece: a spot now shows the county the station is
logged with when we have one, and falls back to the ZIP-derived county only for
stations never worked.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package uls
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"hamlog/internal/award"
|
||||
)
|
||||
|
||||
// The eight counties Connecticut still has for every purpose except the Census.
|
||||
var ctLegalCounties = map[string]bool{
|
||||
"Fairfield": true, "Hartford": true, "Litchfield": true, "Middlesex": true,
|
||||
"New Haven": true, "New London": true, "Tolland": true, "Windham": true,
|
||||
}
|
||||
|
||||
// TestCTCountyOnlyLegalCounties makes sure no planning region ever creeps back
|
||||
// into the table — a regenerated file that quietly picked up "Capitol Region"
|
||||
// would put every Hartford-area station back out of reach of the award, which
|
||||
// is exactly the failure this table exists to end.
|
||||
func TestCTCountyOnlyLegalCounties(t *testing.T) {
|
||||
if len(ctCounty) < 400 {
|
||||
t.Fatalf("only %d Connecticut ZIPs — the table looks truncated", len(ctCounty))
|
||||
}
|
||||
for zip, county := range ctCounty {
|
||||
if !ctLegalCounties[county] {
|
||||
t.Errorf("ZIP %s → %q, which is not one of Connecticut's eight counties", zip, county)
|
||||
}
|
||||
if len(zip) != 5 {
|
||||
t.Errorf("ZIP %q is not five digits", zip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCTCountyMatchesAward closes the loop: every county in the table has to
|
||||
// produce a key the USA-CA reference actually lists. A county the resolver can
|
||||
// name but the award cannot match is worth no more than the planning region it
|
||||
// replaced.
|
||||
func TestCTCountyMatchesAward(t *testing.T) {
|
||||
want := map[string]bool{
|
||||
"CT/FAIRFIELD": true, "CT/HARTFORD": true, "CT/LITCHFIELD": true,
|
||||
"CT/MIDDLESEX": true, "CT/NEWHAVEN": true, "CT/NEWLONDON": true,
|
||||
"CT/TOLLAND": true, "CT/WINDHAM": true,
|
||||
}
|
||||
for zip, county := range ctCounty {
|
||||
if k := award.USCountyKey("CT", county); !want[k] {
|
||||
t.Errorf("ZIP %s → %q → key %q, not a USA-CA county", zip, county, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestCTCountyKnownZips pins a ZIP in each county against ground truth, so a
|
||||
// regeneration that silently shifted the whole table is caught. 06419 is the
|
||||
// case that started this: Killingworth is in Middlesex, and GeoNames calls it
|
||||
// "Lower Connecticut River Valley".
|
||||
func TestCTCountyKnownZips(t *testing.T) {
|
||||
for zip, want := range map[string]string{
|
||||
"06419": "Middlesex", // Killingworth
|
||||
"06001": "Hartford", // Avon
|
||||
"06106": "Hartford", // Hartford
|
||||
"06510": "New Haven", // New Haven
|
||||
"06880": "Fairfield", // Westport
|
||||
"06340": "New London", // Groton
|
||||
"06226": "Windham", // Willimantic
|
||||
"06238": "Tolland", // Coventry
|
||||
"06759": "Litchfield", // Litchfield
|
||||
} {
|
||||
if got := ctCounty[zip]; got != want {
|
||||
t.Errorf("ctCounty[%s] = %q, want %q", zip, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user