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:
2026-08-14 00:42:27 +02:00
parent fbd62fda30
commit 30143b01bf
15 changed files with 1122 additions and 15 deletions
+10 -1
View File
@@ -1489,7 +1489,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
finally { setScpBusy(false); }
};
// US Counties (offline FCC ULS) — download progress arrives via events.
const [ulsStatus, setUlsStatus] = useState<{ count: number; updated_at?: string }>({ count: 0 });
const [ulsStatus, setUlsStatus] = useState<{ count: number; updated_at?: string; needs_refresh?: boolean }>({ count: 0 });
const [ulsBusy, setUlsBusy] = useState(false);
const [ulsProgress, setUlsProgress] = useState<{ stage: string; pct: number } | null>(null);
const [ulsMsg, setUlsMsg] = useState<{ ok: boolean; text: string } | null>(null);
@@ -6233,6 +6233,15 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
</Button>
</div>
{/* A database downloaded by an older OpsLog still holds Connecticut's
planning regions instead of its counties. The download date cannot
show that, so say it outright. */}
{loaded && ulsStatus.needs_refresh && !ulsBusy && (
<div className="text-[11px] rounded border border-warning-border bg-warning-muted text-warning-muted-foreground px-2 py-1.5 leading-relaxed">
{t('uscty.stale')}
</div>
)}
{ulsProgress && (
<div className="space-y-1">
<div className="text-[11px] text-muted-foreground flex justify-between">
+2
View File
@@ -148,6 +148,7 @@ const en: Dict = {
'uscty.dbStatus': 'County database',
'uscty.loaded': '{n} callsigns · updated {date}',
'uscty.notLoaded': 'Not downloaded yet.',
'uscty.stale': 'This database was built before Connecticut counties were corrected. Download it again to fix them.',
'uscty.download': 'Download',
'uscty.update': 'Update',
'uscty.done': 'County database ready — {n} callsigns.',
@@ -575,6 +576,7 @@ const fr: Dict = {
'uscty.dbStatus': 'Base des comtés',
'uscty.loaded': '{n} indicatifs · maj {date}',
'uscty.notLoaded': 'Pas encore téléchargée.',
'uscty.stale': 'Cette base a été construite avant la correction des comtés du Connecticut. Téléchargez-la à nouveau pour les corriger.',
'uscty.download': 'Télécharger',
'uscty.update': 'Mettre à jour',
'uscty.done': 'Base des comtés prête — {n} indicatifs.',
+2
View File
@@ -3362,6 +3362,7 @@ export namespace main {
export class ULSStatusResult {
count: number;
updated_at: string;
needs_refresh: boolean;
static createFrom(source: any = {}) {
return new ULSStatusResult(source);
@@ -3371,6 +3372,7 @@ export namespace main {
if ('string' === typeof source) source = JSON.parse(source);
this.count = source["count"];
this.updated_at = source["updated_at"];
this.needs_refresh = source["needs_refresh"];
}
}
export class UltrabeamSettings {